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

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 1762
  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.'1762$this->source); })()), "session", [], "any"falsefalsefalse1762), "get", ["pageMenu"], "method"falsefalsefalse1762);
  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. <link rel=\"stylesheet\" href=\"";
  94.         // line 11
  95.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("css/sidebar-ecommerce-pro.css"), "html"nulltrue);
  96.         yield "\">
  97. ";
  98.         // line 12
  99.         $context["destination"] = "detailsejour";
  100.         // line 13
  101.         yield "
  102. ";
  103.         // line 15
  104.         $context["nowTs"] = $this->extensions['Twig\Extension\CoreExtension']->formatDate("now""U");
  105.         // line 16
  106.         $context["debutTs"] = $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.'16$this->source); })()), "dateDebutSejour", [], "any"falsefalsefalse16), "U");
  107.         // line 17
  108.         $context["finTs"] = $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.'17$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse17), "U");
  109.         // line 18
  110.         $context["closeTs"] = (((($tmp 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.'18$this->source); })()), "dateFinCode", [], "any"falsefalsefalse18)) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($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.'18$this->source); })()), "dateFinCode", [], "any"falsefalsefalse18), "U")) : ((isset($context["finTs"]) || array_key_exists("finTs"$context) ? $context["finTs"] : (function () { throw new RuntimeError('Variable "finTs" does not exist.'18$this->source); })())));
  111.         // line 19
  112.         $context["secondsPerDay"] = 86400;
  113.         // line 20
  114.         $context["daysSinceStart"] = Twig\Extension\CoreExtension::round((((isset($context["nowTs"]) || array_key_exists("nowTs"$context) ? $context["nowTs"] : (function () { throw new RuntimeError('Variable "nowTs" does not exist.'20$this->source); })()) - (isset($context["debutTs"]) || array_key_exists("debutTs"$context) ? $context["debutTs"] : (function () { throw new RuntimeError('Variable "debutTs" does not exist.'20$this->source); })())) / (isset($context["secondsPerDay"]) || array_key_exists("secondsPerDay"$context) ? $context["secondsPerDay"] : (function () { throw new RuntimeError('Variable "secondsPerDay" does not exist.'20$this->source); })())), 0"floor");
  115.         // line 21
  116.         $context["daysUntilEnd"] = Twig\Extension\CoreExtension::round((((isset($context["finTs"]) || array_key_exists("finTs"$context) ? $context["finTs"] : (function () { throw new RuntimeError('Variable "finTs" does not exist.'21$this->source); })()) - (isset($context["nowTs"]) || array_key_exists("nowTs"$context) ? $context["nowTs"] : (function () { throw new RuntimeError('Variable "nowTs" does not exist.'21$this->source); })())) / (isset($context["secondsPerDay"]) || array_key_exists("secondsPerDay"$context) ? $context["secondsPerDay"] : (function () { throw new RuntimeError('Variable "secondsPerDay" does not exist.'21$this->source); })())), 0"ceil");
  117.         // line 22
  118.         $context["daysAfterEnd"] = Twig\Extension\CoreExtension::round((((isset($context["nowTs"]) || array_key_exists("nowTs"$context) ? $context["nowTs"] : (function () { throw new RuntimeError('Variable "nowTs" does not exist.'22$this->source); })()) - (isset($context["finTs"]) || array_key_exists("finTs"$context) ? $context["finTs"] : (function () { throw new RuntimeError('Variable "finTs" does not exist.'22$this->source); })())) / (isset($context["secondsPerDay"]) || array_key_exists("secondsPerDay"$context) ? $context["secondsPerDay"] : (function () { throw new RuntimeError('Variable "secondsPerDay" does not exist.'22$this->source); })())), 0"floor");
  119.         // line 23
  120.         $context["daysUntilClose"] = Twig\Extension\CoreExtension::round((((isset($context["closeTs"]) || array_key_exists("closeTs"$context) ? $context["closeTs"] : (function () { throw new RuntimeError('Variable "closeTs" does not exist.'23$this->source); })()) - (isset($context["nowTs"]) || array_key_exists("nowTs"$context) ? $context["nowTs"] : (function () { throw new RuntimeError('Variable "nowTs" does not exist.'23$this->source); })())) / (isset($context["secondsPerDay"]) || array_key_exists("secondsPerDay"$context) ? $context["secondsPerDay"] : (function () { throw new RuntimeError('Variable "secondsPerDay" does not exist.'23$this->source); })())), 0"ceil");
  121.         // line 24
  122.         yield "<style>
  123. /* ============================================
  124.    PREMIUM DAY CARDS - Style Accompagnateur
  125.    ============================================ */
  126. /* Base card styles */
  127. /* ============================================
  128.    PREMIUM DAY CARDS - Timeline ultra-premium
  129.    Identique à l'espace accompagnateur
  130.    ============================================ */
  131. .date-card {
  132.   flex: 0 0 auto;
  133.   width: 110px;
  134.   background: #fff;
  135.   border-radius: 14px;
  136.   padding: 8px 6px;
  137.   text-align: center;
  138.   transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  139.   overflow: visible;
  140.   scroll-snap-align: center;
  141.   position: relative;
  142.   min-height: 56px;
  143.   max-height: 68px;
  144.   border: 1px solid transparent;
  145.   cursor: pointer;
  146. }
  147. .date-card .day {
  148.   font-weight: 600;
  149.   font-size: 0.70rem;
  150.   color: #2c3e50;
  151.   margin-bottom: 1px;
  152.   letter-spacing: -0.01em;
  153.   line-height: 1.15;
  154. }
  155. .date-card .full-date {
  156.   font-size: 0.60rem;
  157.   color: #6b7280;
  158.   font-weight: 500;
  159.   line-height: 1.1;
  160.   margin-top: 0px;
  161.   padding-bottom: 5px;
  162. }
  163. .date-card ul {
  164.   margin: 4px 0 0 0;
  165.   padding: 0;
  166.   list-style: none;
  167.   display: flex;
  168.   gap: 4px;
  169.   justify-content: center;
  170.   flex-wrap: wrap;
  171.   align-items: center;
  172. }
  173. .date-card ul li {
  174.   font-size: 0.60rem;
  175.   color: #6b7280;
  176.   display: flex;
  177.   align-items: center;
  178.   gap: 2px;
  179.   line-height: 1;
  180.   font-weight: 500;
  181. }
  182. .date-card ul li i {
  183.   font-size: 0.65rem;
  184. }
  185. .premium-day-card {
  186.   flex: 0 0 auto;
  187.   width: 130px;
  188.   background: #fff;
  189.   border-radius: 14px;
  190.   padding: 8px 6px;
  191.   text-align: center;
  192.   transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  193.   overflow: visible;
  194.   scroll-snap-align: center;
  195.   position: relative;
  196.   min-height: 56px;
  197.   max-height: 68px;
  198.   border: 1px solid transparent;
  199.   cursor: pointer;
  200.   will-change: transform;
  201.   contain: layout style;
  202. }
  203. .premium-day-card .day {
  204.   font-weight: 600;
  205.   font-size: 0.9rem;
  206.   color: #2c3e50;
  207.   margin-bottom: 1px;
  208.   letter-spacing: -0.01em;
  209.   line-height: 1.15;
  210. }
  211. .premium-day-card .full-date {
  212.   font-size: 0.75rem;
  213.   color: #6b7280;
  214.   font-weight: 500;
  215.   line-height: 1.1;
  216.   margin-top: 0;
  217. }
  218. /* Compteurs de médias - Points colorés minimalistes */
  219. .premium-day-card ul,
  220. .date-card ul,
  221. .media-list-horizontal {
  222.   margin: 4px 0 0 0;
  223.   padding: 0;
  224.   list-style: none;
  225.   display: flex;
  226.   gap: 4px;
  227.   justify-content: center;
  228.   flex-wrap: wrap;
  229.   align-items: center;
  230. }
  231. .premium-day-card ul li,
  232. .date-card ul li {
  233.   font-size: 0.60rem;
  234.   color: #6b7280;
  235.   display: flex;
  236.   align-items: center;
  237.   gap: 2px;
  238.   line-height: 1;
  239.   font-weight: 500;
  240. }
  241. .premium-day-card ul li i,
  242. .date-card ul li i {
  243.   font-size: 0.65rem;
  244. }
  245. /* ============================================
  246.    COULEURS PAR TYPE DE MÉDIA - Uniforme pour toutes les cartes
  247.    Photo = Orange, Vocal = Bleu, Vidéo = Orange clair
  248.    ============================================ */
  249. /* Photo = Orange 🟠 */
  250. .premium-day-card ul li i.bi-camera,
  251. .premium-day-card ul li i.bi-camera-fill,
  252. .premium-day-card ul li i.bi-image,
  253. .premium-day-card ul li i.bi-images,
  254. .premium-day-past ul li i.bi-camera,
  255. .premium-day-past ul li i.bi-camera-fill,
  256. .premium-day-past ul li i.bi-image,
  257. .premium-day-past ul li i.bi-images,
  258. .premium-day-current ul li i.bi-camera,
  259. .premium-day-current ul li i.bi-camera-fill,
  260. .premium-day-current ul li i.bi-image,
  261. .premium-day-current ul li i.bi-images,
  262. .premium-day-future ul li i.bi-camera,
  263. .premium-day-future ul li i.bi-camera-fill,
  264. .premium-day-future ul li i.bi-image,
  265. .premium-day-future ul li i.bi-images,
  266. .date-card ul li i.bi-camera,
  267. .date-card ul li i.bi-camera-fill,
  268. .date-card ul li i.bi-image,
  269. .date-card ul li i.bi-images {
  270.   color: #F56040 !important;
  271.   opacity: 1 !important;
  272. }
  273. /* Vocal/Audio = Bleu Mint 🔵 */
  274. .premium-day-card ul li i.bi-mic-fill,
  275. .premium-day-card ul li i.bi-mic,
  276. .premium-day-past ul li i.bi-mic-fill,
  277. .premium-day-past ul li i.bi-mic,
  278. .premium-day-current ul li i.bi-mic-fill,
  279. .premium-day-current ul li i.bi-mic,
  280. .premium-day-future ul li i.bi-mic-fill,
  281. .premium-day-future ul li i.bi-mic,
  282. .date-card ul li i.bi-mic-fill,
  283. .date-card ul li i.bi-mic {
  284.   color: #41A2AA !important;
  285.   opacity: 1 !important;
  286. }
  287. /* Vidéo = Orange clair 🟠 */
  288. .premium-day-card ul li i.bi-camera-video,
  289. .premium-day-card ul li i.bi-camera-video-fill,
  290. .premium-day-card ul li i.bi-film,
  291. .premium-day-past ul li i.bi-camera-video,
  292. .premium-day-past ul li i.bi-camera-video-fill,
  293. .premium-day-past ul li i.bi-film,
  294. .premium-day-current ul li i.bi-camera-video,
  295. .premium-day-current ul li i.bi-camera-video-fill,
  296. .premium-day-current ul li i.bi-film,
  297. .premium-day-future ul li i.bi-camera-video,
  298. .premium-day-future ul li i.bi-camera-video-fill,
  299. .premium-day-future ul li i.bi-film,
  300. .date-card ul li i.bi-camera-video,
  301. .date-card ul li i.bi-camera-video-fill,
  302. .date-card ul li i.bi-film {
  303.   color: #FF9F7A !important;
  304.   opacity: 1 !important;
  305. }
  306. /* État PASSÉ - Cohérent avec charte 5sur5 */
  307. .premium-day-past {
  308.   opacity: 0.85;
  309.   background: rgba(65, 162, 170, 0.05);
  310.   border: 1px solid rgba(65, 162, 170, 0.25);
  311.   cursor: pointer;
  312.   pointer-events: auto;
  313. }
  314. .premium-day-past:hover {
  315.   transform: translateY(-2px);
  316.   box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
  317.   opacity: 1;
  318. }
  319. /* État AUJOURD'HUI - Premium mis en avant clairement */
  320. .premium-day-current {
  321.   width: 110px !important;
  322.   border: 2px solid #41A2AA !important;
  323.   background: #fff !important;
  324.   box-shadow: 0 6px 16px rgba(65, 162, 170, 0.12) !important;
  325.   transform: scale(1.04);
  326.   z-index: 10;
  327.   cursor: pointer;
  328.   opacity: 1 !important;
  329.   position: relative;
  330. }
  331. /* Point animé \"Aujourd'hui\" - style calendrier moderne */
  332. .premium-day-current::after {
  333.   content: '';
  334.   position: absolute;
  335.   top: 8px;
  336.   right: 8px;
  337.   width: 8px;
  338.   height: 8px;
  339.   background: #41A2AA;
  340.   border-radius: 50%;
  341.   box-shadow: 0 0 0 0 rgba(65, 162, 170, 0.7);
  342.   animation: todayPulse 2s ease-in-out infinite;
  343.   z-index: 5;
  344. }
  345. @keyframes todayPulse {
  346.   0% {
  347.     box-shadow: 0 0 0 0 rgba(65, 162, 170, 0.7);
  348.   }
  349.   50% {
  350.     box-shadow: 0 0 0 6px rgba(65, 162, 170, 0);
  351.   }
  352.   100% {
  353.     box-shadow: 0 0 0 0 rgba(65, 162, 170, 0);
  354.   }
  355. }
  356. .premium-day-current:hover {
  357.   transform: scale(1.04);
  358.   box-shadow: 0 6px 16px rgba(65, 162, 170, 0.12) !important;
  359. }
  360. .premium-day-current:focus-visible {
  361.   outline: 3px solid rgba(65, 162, 170, 0.3);
  362.   outline-offset: 2px;
  363. }
  364. .premium-day-current .day,
  365. .premium-day-current .full-date {
  366.   color: #137F86 !important;
  367.   font-weight: 600 !important;
  368. }
  369. .premium-day-current .full-date {
  370.   padding-bottom: 5px !important;
  371. }
  372. .premium-day-current ul li {
  373.   color: #137F86 !important;
  374. }
  375. /* État ACTIF - Carte sélectionnée */
  376. .date-card.active,
  377. .premium-day-card.active {
  378.   width: 140px !important;
  379.   border: 2px solid #41A2AA !important;
  380.   background: #EAF7F7 !important;
  381.   box-shadow: 0 2px 8px rgba(65, 162, 170, 0.15) !important;
  382.   transform: scale(1.02);
  383.   z-index: 10;
  384. }
  385. .date-card.active .day,
  386. .premium-day-card.active .day,
  387. .date-card.active .day-number,
  388. .premium-day-card.active .day-number {
  389.   color: #137F86 !important;
  390.   font-weight: 700;
  391. }
  392. .date-card.active .full-date,
  393. .premium-day-card.active .full-date,
  394. .date-card.active .day-name,
  395. .premium-day-card.active .day-name {
  396.   color: #137F86 !important;
  397.   font-weight: 700;
  398. }
  399. .date-card.active ul li,
  400. .premium-day-card.active ul li {
  401.   color: #137F86 !important;
  402. }
  403. .date-card.active ul li i,
  404. .premium-day-card.active ul li i {
  405.   color: #41A2AA !important;
  406. }
  407. .date-card:hover,
  408. .premium-day-card:hover {
  409.   background-color: #f9f9f9;
  410.   box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  411. }
  412. /* État FUTUR - Semi-caché, réduit, verrouillé */
  413. .premium-day-future {
  414.   opacity: 0.45 !important;
  415.   transform: scale(0.92);
  416.   cursor: not-allowed !important;
  417.   pointer-events: none !important;
  418.   border: 1px solid rgba(188, 196, 206, 0.2) !important;
  419.   background: #fff !important;
  420.   box-shadow: none !important;
  421. }
  422. .premium-day-future:hover {
  423.   transform: scale(0.92) !important;
  424.   box-shadow: none !important;
  425. }
  426. .premium-day-future .day,
  427. .premium-day-future .full-date {
  428.   color: #BCC4CE !important;
  429. }
  430. .premium-day-future ul {
  431.   display: none !important;
  432. }
  433. /* Icône cadenas sur jours futurs */
  434. .premium-day-future::before {
  435.   content: '\\F4C0';
  436.   font-family: 'bootstrap-icons';
  437.   position: absolute;
  438.   top: 4px;
  439.   right: 4px;
  440.   font-size: 9px;
  441.   color: #BCC4CE;
  442.   opacity: 0.25;
  443. }
  444. /* Tooltip pour jours futurs */
  445. .premium-day-future::after {
  446.   content: attr(data-tooltip);
  447.   position: absolute;
  448.   bottom: -35px;
  449.   left: 50%;
  450.   transform: translateX(-50%);
  451.   background: rgba(0, 0, 0, 0.85);
  452.   color: white;
  453.   padding: 6px 10px;
  454.   border-radius: 6px;
  455.   font-size: 11px;
  456.   white-space: nowrap;
  457.   opacity: 0;
  458.   pointer-events: none;
  459.   transition: opacity 0.2s ease;
  460.   z-index: 1000;
  461. }
  462. /* Date container scroll */
  463. .date-container {
  464.   display: flex;
  465.   gap: 12px;
  466.   overflow-x: auto;
  467.   scrollbar-width: none;
  468.   -ms-overflow-style: none;
  469.   padding: 8px 4px;
  470. }
  471. .date-container::-webkit-scrollbar {
  472.   display: none;
  473. }
  474. /* Section days wrapper */
  475. .section-days {
  476.   background: #f8fafb;
  477.   border-radius: 12px;
  478.   padding: 10px 12px;
  479.   margin-bottom: 16px;
  480.   border: 1px solid rgba(65, 162, 170, 0.1);
  481.   box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  482. }
  483. /* Bouton favoris désactivé (0 favoris) */
  484. .mtb-btn.favoris-empty,
  485. .mtb-btn[data-filter=\"favoris\"]:disabled {
  486.   opacity: 0.6;
  487.   cursor: not-allowed;
  488.   pointer-events: none;
  489.   background: rgba(0, 0, 0, 0.02) !important;
  490.   border-color: rgba(0, 0, 0, 0.08) !important;
  491. }
  492. .mtb-btn.favoris-empty:hover,
  493. .mtb-btn[data-filter=\"favoris\"]:disabled:hover {
  494.   transform: none;
  495.   box-shadow: none;
  496. }
  497. .favoris-empty-text {
  498.   font-size: 11px;
  499.   font-family: inherit;
  500.   color: #94a3b8;
  501.   font-style: italic;
  502.   font-weight: 500;
  503.   line-height: 1.2;
  504. }
  505. /* Styles premium pour les filtres */
  506. .premium-5sur5-actions-group {
  507.   display: flex;
  508.   gap: 8px;
  509.   align-items: center;
  510.   flex-wrap: wrap;
  511. }
  512. .premium-5sur5-action-btn {
  513.   display: inline-flex;
  514.   align-items: center;
  515.   gap: 6px;
  516.   padding: 7px 12px;
  517.   background: #F7FBFC;
  518.   border: 1px solid rgba(65, 162, 170, 0.12);
  519.   border-radius: 14px;
  520.   color: #41A2AA;
  521.   font-size: 13px;
  522.   font-weight: 600;
  523.   font-family: inherit;
  524.   cursor: pointer;
  525.   transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  526.   white-space: nowrap;
  527.   position: relative;
  528.   line-height: 1.4;
  529. }
  530. .premium-5sur5-action-btn:hover:not(:disabled) {
  531.   background: rgba(65, 162, 170, 0.08);
  532.   border-color: rgba(65, 162, 170, 0.25);
  533.   transform: translateY(-1px);
  534. }
  535. .premium-5sur5-action-btn:active:not(:disabled) {
  536.   transform: translateY(0);
  537. }
  538. .premium-5sur5-action-btn i {
  539.   font-size: 14px;
  540.   opacity: 0.85;
  541.   line-height: 1;
  542. }
  543. .premium-5sur5-action-btn span:not(.premium-5sur5-badge):not(.favoris-empty-text) {
  544.   font-size: 13px;
  545.   font-weight: 600;
  546.   letter-spacing: 0.2px;
  547.   line-height: 1.4;
  548.   font-family: inherit;
  549. }
  550. .premium-5sur5-badge {
  551.   display: inline-block;
  552.   font-size: 11px;
  553.   font-weight: 600;
  554.   font-family: inherit;
  555.   padding: 2px 6px;
  556.   border-radius: 6px;
  557.   letter-spacing: 0.2px;
  558.   margin-left: 2px;
  559.   line-height: 1.2;
  560. }
  561. /* État actif pour les boutons premium */
  562. .premium-5sur5-action-btn.mtb-btn.active,
  563. .premium-5sur5-action-btn.mtb-btn.is-active {
  564.   background: rgba(65, 162, 170, 0.15) !important;
  565.   border-color: #41A2AA !important;
  566.   color: #137F86 !important;
  567.   box-shadow: 0 2px 8px rgba(65, 162, 170, 0.2);
  568. }
  569. .premium-5sur5-action-btn.mtb-btn[data-filter=\"favoris\"].active {
  570.   background: rgba(245, 96, 64, 0.15) !important;
  571.   border-color: #f56040 !important;
  572.   color: #d43e1f !important;
  573. }
  574. .premium-5sur5-action-btn.mtb-btn[data-filter=\"audio\"].active {
  575.   background: rgba(255, 215, 0, 0.15) !important;
  576.   border-color: #ffd700 !important;
  577.   color: #b8860b !important;
  578. }
  579. /* Bouton favoris désactivé */
  580. .premium-5sur5-action-btn.favoris-empty,
  581. .premium-5sur5-action-btn[data-filter=\"favoris\"]:disabled {
  582.   opacity: 0.6;
  583.   cursor: not-allowed;
  584.   pointer-events: none;
  585.   background: rgba(0, 0, 0, 0.02) !important;
  586.   border-color: rgba(0, 0, 0, 0.08) !important;
  587. }
  588. .premium-5sur5-action-btn.favoris-empty:hover,
  589. .premium-5sur5-action-btn[data-filter=\"favoris\"]:disabled:hover {
  590.   transform: none;
  591.   box-shadow: none;
  592. }
  593. /* Styles pour la section favoris */
  594. .favorites-ecommerce-view {
  595.   width: 100%;
  596.   max-width: 100%;
  597.   padding: 24px;
  598.   box-sizing: border-box;
  599. }
  600. .favorites-header {
  601.   display: flex;
  602.   justify-content: space-between;
  603.   align-items: center;
  604.   margin-bottom: 24px;
  605.   padding: 20px;
  606.   background: #f8fafb;
  607.   border-radius: 12px;
  608.   border: 1px solid rgba(65, 162, 170, 0.1);
  609. }
  610. .favorites-title {
  611.   display: flex;
  612.   align-items: center;
  613.   gap: 12px;
  614.   flex-wrap: wrap;
  615. }
  616. .favorites-title h3 {
  617.   font-size: 20px;
  618.   font-weight: 700;
  619.   color: #1a1a1a;
  620.   margin: 0;
  621.   display: flex;
  622.   align-items: center;
  623.   gap: 8px;
  624. }
  625. .favorites-title h3 i {
  626.   color: #f56040;
  627.   font-size: 20px;
  628. }
  629. .favorites-count {
  630.   display: inline-flex;
  631.   align-items: center;
  632.   padding: 6px 12px;
  633.   background: rgba(245, 96, 64, 0.1);
  634.   color: #f56040;
  635.   border-radius: 20px;
  636.   font-size: 14px;
  637.   font-weight: 600;
  638. }
  639. .btn-back-to-days {
  640.   display: flex;
  641.   align-items: center;
  642.   gap: 8px;
  643.   padding: 10px 20px;
  644.   background: #ffffff;
  645.   border: 1px solid rgba(65, 162, 170, 0.2);
  646.   border-radius: 10px;
  647.   color: #6b7280;
  648.   font-size: 14px;
  649.   font-weight: 600;
  650.   cursor: pointer;
  651.   transition: all 0.2s ease;
  652. }
  653. .btn-back-to-days:hover {
  654.   background: rgba(65, 162, 170, 0.05);
  655.   border-color: #41A2AA;
  656.   color: #41A2AA;
  657. }
  658. .favorites-content {
  659.   width: 100%;
  660. }
  661. .favorites-grid {
  662.   display: grid;
  663.   grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  664.   gap: 16px;
  665.   width: 100%;
  666.   padding: 0;
  667. }
  668. .favorites-grid .favorite-item,
  669. .favorites-grid .photo-item {
  670.   position: relative;
  671.   width: 100%;
  672.   aspect-ratio: 1;
  673.   border-radius: 12px;
  674.   overflow: hidden;
  675.   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  676.   transition: all 0.3s ease;
  677.   cursor: pointer;
  678. }
  679. .favorites-grid .favorite-item:hover,
  680. .favorites-grid .photo-item:hover {
  681.   transform: translateY(-4px);
  682.   box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  683. }
  684. .favorites-grid .favorite-item:hover .favorite-actions,
  685. .favorites-grid .photo-item:hover .favorite-actions {
  686.   opacity: 1;
  687. }
  688. .favorites-grid img {
  689.   width: 100%;
  690.   height: 100%;
  691.   object-fit: cover;
  692.   display: block;
  693. }
  694. .favorites-grid .favorite-item {
  695.   position: relative;
  696. }
  697. .favorites-grid .favorite-actions {
  698.   position: absolute;
  699.   top: 8px;
  700.   right: 8px;
  701.   display: flex;
  702.   gap: 6px;
  703.   opacity: 0;
  704.   transition: opacity 0.3s ease;
  705.   z-index: 10;
  706. }
  707. /* CTA discret et premium */
  708. .premium-cta-subtle {
  709.   margin: 20px 0;
  710.   padding: 16px 20px;
  711.   background: rgba(65, 162, 170, 0.04);
  712.   border: 1px solid rgba(65, 162, 170, 0.15);
  713.   border-radius: 12px;
  714.   cursor: pointer;
  715.   transition: all 0.3s ease;
  716.   display: flex;
  717.   align-items: center;
  718.   justify-content: space-between;
  719.   gap: 12px;
  720.   text-decoration: none;
  721.   color: inherit;
  722. }
  723. .premium-cta-subtle:hover {
  724.   background: rgba(65, 162, 170, 0.08);
  725.   border-color: rgba(65, 162, 170, 0.25);
  726.   transform: translateX(2px);
  727.   text-decoration: none;
  728.   color: inherit;
  729. }
  730. .premium-cta-subtle > div:first-child {
  731.   display: flex;
  732.   align-items: center;
  733.   gap: 12px;
  734.   flex: 1;
  735. }
  736. .premium-cta-subtle > div:first-child > div:first-child {
  737.   width: 40px;
  738.   height: 40px;
  739.   background: rgba(65, 162, 170, 0.1);
  740.   border-radius: 10px;
  741.   display: flex;
  742.   align-items: center;
  743.   justify-content: center;
  744.   flex-shrink: 0;
  745. }
  746. .premium-cta-subtle > div:first-child > div:first-child i {
  747.   font-size: 18px;
  748.   color: #41A2AA;
  749. }
  750. .premium-cta-subtle > div:first-child > div:last-child {
  751.   flex: 1;
  752.   min-width: 0;
  753. }
  754. .premium-cta-subtle > div:first-child > div:last-child p:first-child {
  755.   margin: 0;
  756.   font-size: 14px;
  757.   font-weight: 600;
  758.   color: #1a1a1a;
  759.   line-height: 1.4;
  760. }
  761. .premium-cta-subtle > div:first-child > div:last-child p:last-child {
  762.   margin: 4px 0 0 0;
  763.   font-size: 12px;
  764.   color: #6b7280;
  765.   line-height: 1.4;
  766. }
  767. .premium-cta-subtle > i:last-child {
  768.   font-size: 18px;
  769.   color: #41A2AA;
  770.   flex-shrink: 0;
  771. }
  772. .premium-5sur5-day-title {
  773.   font-size: 1.35rem;
  774.   font-weight: 700;
  775.   color: #2c3e50;
  776.   margin: 0 0 4px 0;
  777.   letter-spacing: -0.02em;
  778.   line-height: 1.3;
  779. }
  780. .premium-5sur5-day-subtitle {
  781.   font-size: 0.9rem;
  782.   color: #6b7280;
  783.   margin: 0;
  784.   font-weight: 500;
  785.   line-height: 1.5;
  786. }
  787. @media (max-width: 768px) {
  788.   .premium-5sur5-day-header {
  789.     padding: 12px 16px;
  790.     margin-bottom: 16px;
  791.   }
  792.   .premium-5sur5-day-title {
  793.     font-size: 1.15rem;
  794.   }
  795.   .premium-5sur5-day-subtitle {
  796.     font-size: 0.8rem;
  797.   }
  798.   /* Menu sticky en bas - Override des styles précédents */
  799.   .premium-5sur5-actions-group {
  800.     position: fixed !important;
  801.     bottom: 0 !important;
  802.     left: 0 !important;
  803.     right: 0 !important;
  804.     width: 100% !important;
  805.     background: #ffffff !important;
  806.     border-top: 1px solid rgba(65, 162, 170, 0.15) !important;
  807.     padding: 12px 16px !important;
  808.     z-index: 1050 !important;
  809.     box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.08) !important;
  810.     justify-content: space-around !important;
  811.     gap: 0 !important;
  812.     margin: 0 !important;
  813.     margin-top: 0 !important;
  814.     /* Safe area pour iPhone avec encoche */
  815.     padding-bottom: max(12px, env(safe-area-inset-bottom)) !important;
  816.   }
  817.   .premium-5sur5-action-btn {
  818.     flex: 1 !important;
  819.     justify-content: center !important;
  820.     min-width: 0 !important;
  821.     padding: 10px 8px !important;
  822.     border-radius: 12px !important;
  823.     font-size: 12px !important;
  824.   }
  825.   .premium-5sur5-action-btn i {
  826.     font-size: 16px !important;
  827.   }
  828.   
  829.   .premium-5sur5-action-btn span:not(.premium-5sur5-badge):not(.favoris-empty-text) {
  830.     font-size: 12px !important;
  831.   }
  832.   
  833.   .premium-5sur5-badge {
  834.     font-size: 10px !important;
  835.     padding: 2px 5px !important;
  836.   }
  837.   /* Ajouter un padding-bottom au contenu pour éviter que le menu sticky ne cache le contenu */
  838.   #scrollTarget {
  839.     padding-bottom: 80px !important;
  840.   }
  841.   /* Section favoris responsive */
  842.   .favorites-ecommerce-view {
  843.     padding: 16px !important;
  844.   }
  845.   .favorites-header {
  846.     flex-direction: column !important;
  847.     gap: 12px !important;
  848.     align-items: flex-start !important;
  849.     padding: 16px !important;
  850.     margin-bottom: 16px !important;
  851.   }
  852.   .favorites-title {
  853.     width: 100% !important;
  854.   }
  855.   .favorites-title h3 {
  856.     font-size: 18px !important;
  857.     margin-bottom: 8px !important;
  858.   }
  859.   .favorites-count {
  860.     font-size: 13px !important;
  861.     padding: 4px 10px !important;
  862.   }
  863.   .btn-back-to-days {
  864.     width: 100% !important;
  865.     justify-content: center !important;
  866.     padding: 10px 16px !important;
  867.     font-size: 14px !important;
  868.   }
  869.   .favorites-content {
  870.     padding: 0 !important;
  871.   }
  872.   .favorites-grid {
  873.     display: grid !important;
  874.     grid-template-columns: repeat(2, 1fr) !important;
  875.     gap: 12px !important;
  876.     padding: 0 !important;
  877.   }
  878.   .favorites-grid .favorite-item,
  879.   .favorites-grid .photo-item {
  880.     width: 100% !important;
  881.     height: auto !important;
  882.     min-height: 150px !important;
  883.     aspect-ratio: 1 !important;
  884.     position: relative !important;
  885.     display: block !important;
  886.     border-radius: 12px !important;
  887.     overflow: hidden !important;
  888.     background: #f0f0f0 !important;
  889.   }
  890.   .favorites-grid .favorite-item img,
  891.   .favorites-grid .photo-item img {
  892.     width: 100% !important;
  893.     height: 100% !important;
  894.     min-height: 150px !important;
  895.     object-fit: cover !important;
  896.     display: block !important;
  897.     position: absolute !important;
  898.     top: 0 !important;
  899.     left: 0 !important;
  900.     border-radius: 12px !important;
  901.   }
  902.   .favorites-grid video {
  903.     width: 100% !important;
  904.     height: 100% !important;
  905.     min-height: 150px !important;
  906.     object-fit: cover !important;
  907.     display: block !important;
  908.     position: absolute !important;
  909.     top: 0 !important;
  910.     left: 0 !important;
  911.     border-radius: 12px !important;
  912.   }
  913.   /* CTA discret responsive */
  914.   .premium-cta-subtle {
  915.     padding: 12px 16px !important;
  916.     margin: 16px 0 !important;
  917.   }
  918.   .premium-cta-subtle > div:first-child > div:first-child {
  919.     width: 36px !important;
  920.     height: 36px !important;
  921.   }
  922.   .premium-cta-subtle > div:first-child > div:first-child i {
  923.     font-size: 16px !important;
  924.   }
  925.   .premium-cta-subtle > div:first-child > div:last-child p:first-child {
  926.     font-size: 13px !important;
  927.   }
  928.   .premium-cta-subtle > div:first-child > div:last-child p:last-child {
  929.     font-size: 11px !important;
  930.   }
  931.   .premium-cta-subtle:hover {
  932.     background: rgba(65, 162, 170, 0.08) !important;
  933.     border-color: rgba(65, 162, 170, 0.25) !important;
  934.     transform: translateX(2px) !important;
  935.   }
  936. }
  937. .date-navigation {
  938.   width: 100%;
  939. }
  940. /* Legacy compatibility */
  941. .date-card .card-content {
  942.   display: block;
  943.   text-align: center;
  944. }
  945. .date-card .media-list-horizontal {
  946.   margin: 0 !important;
  947.   padding: 0 !important;
  948.   display: flex;
  949.   gap: 6px;
  950.   justify-content: center;
  951. }
  952. .date-card .media-list-horizontal li {
  953.   font-size: 0.65rem !important;
  954. }
  955. /* Dots minimalistes pour les indicateurs de jour */
  956. .dot {
  957.   display: inline-block;
  958.   width: 6px;
  959.   height: 6px;
  960.   border-radius: 50%;
  961.   margin-left: 4px;
  962. }
  963. .dot.blue {
  964.   background: #41a2aa;
  965. }
  966. .dot.green {
  967.   background: #8ed081;
  968. }
  969. .dot.orange {
  970.   background: #ff9c57;
  971. }
  972. /* Dot multi-couleur pour aujourd'hui + premier/dernier jour */
  973. .status-dot.multi {
  974.   position: absolute;
  975.   top: 6px;
  976.   right: 6px;
  977.   width: 10px;
  978.   height: 10px;
  979.   border-radius: 50%;
  980.   background: linear-gradient(90deg, #41a2aa 50%, #ff9c57 50%);
  981.   z-index: 5;
  982. }
  983. /* Variante pour premier jour + aujourd'hui */
  984. .status-dot.multi.green-orange {
  985.   background: linear-gradient(90deg, #8ed081 50%, #ff9c57 50%);
  986. }
  987. /* ==================== TOASTS & ANIMATIONS ==================== */
  988. @keyframes slideUpFromGift {
  989.   0% {
  990.     opacity: 0;
  991.     transform: translateY(60px) scale(0.9);
  992.   }
  993.   100% {
  994.     opacity: 1;
  995.     transform: translateY(0) scale(1);
  996.   }
  997. }
  998. @keyframes fadeOut {
  999.   to {
  1000.     opacity: 0;
  1001.     transform: translateY(-20px);
  1002.   }
  1003. }
  1004. /* ========== BANDEAU PROMO SÉJOUR TERMINÉ ========== */
  1005. .promo-banner-termine {
  1006.   background: linear-gradient(90deg, #d32f2f 0%, #e65100 50%, #ff5722 100%);
  1007.   color: white;
  1008.   padding: 0;
  1009.   height: 38px;
  1010.   width: 100%;
  1011.   position: relative;
  1012.   z-index: 100;
  1013.   box-shadow: 0 2px 6px rgba(211, 47, 47, 0.2);
  1014. }
  1015. .promo-banner-content {
  1016.   display: flex;
  1017.   align-items: center;
  1018.   justify-content: center;
  1019.   gap: 10px;
  1020.   max-width: 1200px;
  1021.   margin: 0 auto;
  1022.   padding: 0 12px;
  1023.   height: 100%;
  1024. }
  1025. .promo-banner-icon {
  1026.   font-size: 16px;
  1027.   flex-shrink: 0;
  1028. }
  1029. .promo-banner-text {
  1030.   font-size: 12px;
  1031.   line-height: 1.2;
  1032. }
  1033. .promo-banner-text strong {
  1034.   font-weight: 700;
  1035.   display: inline;
  1036. }
  1037. .promo-days {
  1038.   color: #fff;
  1039.   font-weight: 700;
  1040.   background: rgba(255,255,255,0.2);
  1041.   padding: 1px 5px;
  1042.   border-radius: 3px;
  1043.   font-size: 11px;
  1044. }
  1045. .promo-banner-cta {
  1046.   background: #fff;
  1047.   color: #d32f2f;
  1048.   font-weight: 600;
  1049.   font-size: 11px;
  1050.   padding: 4px 12px;
  1051.   border-radius: 12px;
  1052.   text-decoration: none;
  1053.   white-space: nowrap;
  1054.   transition: all 0.2s;
  1055. }
  1056. .promo-banner-cta:hover {
  1057.   background: rgba(255,255,255,0.9);
  1058.   transform: scale(1.02);
  1059.   color: #d32f2f;
  1060. }
  1061. .promo-banner-close {
  1062.   background: none;
  1063.   border: none;
  1064.   color: white;
  1065.   font-size: 18px;
  1066.   cursor: pointer;
  1067.   opacity: 0.7;
  1068.   padding: 0 2px;
  1069.   margin-left: 2px;
  1070.   line-height: 1;
  1071. }
  1072. .promo-banner-close:hover {
  1073.   opacity: 1;
  1074. }
  1075. @media (max-width: 600px) {
  1076.   .promo-banner-termine {
  1077.     height: 34px;
  1078.   }
  1079.   .promo-banner-content {
  1080.     gap: 6px;
  1081.     padding: 0 8px;
  1082.   }
  1083.   .promo-banner-text {
  1084.     font-size: 11px;
  1085.   }
  1086.   .promo-banner-icon {
  1087.     font-size: 14px;
  1088.   }
  1089. }
  1090. /* ========== SLIDER COMPACT PREMIUM ========== */
  1091. #heroPromo {
  1092.   margin: 0;
  1093.   padding: 0;
  1094.   width: 100%;
  1095.   overflow: hidden;
  1096.   background: #fff;
  1097. }
  1098. #heroPromo .divSliderModern {
  1099.   width: 100% !important;
  1100.   margin: 0 !important;
  1101.   padding: 0 !important;
  1102. }
  1103. #imageSlider {
  1104.   max-height: 70px !important;
  1105.   height: 70px !important;
  1106.   overflow: hidden !important;
  1107.   width: 100% !important;
  1108.   margin: 0 !important;
  1109.   padding: 0 !important;
  1110. }
  1111. #imageSlider .splide__track {
  1112.   height: 70px !important;
  1113.   width: 100% !important;
  1114.   margin: 0 !important;
  1115.   padding: 0 !important;
  1116. }
  1117. #imageSlider .splide__list {
  1118.   width: 100% !important;
  1119.   margin: 0 !important;
  1120.   padding: 0 !important;
  1121. }
  1122. #imageSlider .splide__slide {
  1123.   height: 70px !important;
  1124.   width: 100% !important;
  1125.   margin: 0 !important;
  1126.   padding: 0 !important;
  1127. }
  1128. #imageSlider .splide__slide img {
  1129.   object-fit: contain !important;
  1130.   height: auto !important;
  1131.   width: auto !important;
  1132. }
  1133. .slider-content-compact {
  1134.   display: flex;
  1135.   align-items: center;
  1136.   justify-content: flex-start;
  1137.   gap: 0;
  1138.   background: linear-gradient(135deg, #f7fcfc 0%, #ffffff 30%, #fef8f5 100%);
  1139.   height: 70px !important;
  1140.   padding: 0;
  1141.   width: 100%;
  1142.   box-sizing: border-box;
  1143.   overflow: hidden;
  1144.   position: relative;
  1145. }
  1146. .imgslider-compact {
  1147.   height: 100% !important;
  1148.   width: 70% !important;
  1149.   object-fit: cover;
  1150.   flex-shrink: 0;
  1151.   display: block;
  1152. }
  1153. .slider-text-compact {
  1154.   display: flex;
  1155.   flex-direction: column;
  1156.   gap: 4px;
  1157.   align-items: flex-start;
  1158.   justify-content: center;
  1159.   flex: 1;
  1160.   min-width: 0;
  1161.   overflow: hidden;
  1162.   padding: 12px 24px;
  1163.   height: 100%;
  1164. }
  1165. .slider-title-compact {
  1166.   font-size: 14px;
  1167.   font-weight: 700;
  1168.   line-height: 1.3;
  1169.   color: inherit;
  1170.   white-space: normal;
  1171.   word-wrap: break-word;
  1172.   max-width: 100%;
  1173. }
  1174. .slider-subtitle-compact {
  1175.   font-size: 12px;
  1176.   font-weight: 500;
  1177.   line-height: 1.3;
  1178.   color: inherit;
  1179.   white-space: normal;
  1180.   word-wrap: break-word;
  1181.   max-width: 100%;
  1182. }
  1183. @media (max-width: 768px) {
  1184.   #imageSlider, #imageSlider .splide__track, #imageSlider .splide__slide, .slider-content-compact {
  1185.     height: 65px !important;
  1186.   }
  1187.   .slider-content-compact {
  1188.     gap: 0;
  1189.   }
  1190.   .imgslider-compact {
  1191.     height: 100% !important;
  1192.     width: 70% !important;
  1193.   }
  1194.   .slider-text-compact {
  1195.     padding: 10px 16px;
  1196.   }
  1197.   .slider-title-compact {
  1198.     font-size: 13px;
  1199.     line-height: 1.2;
  1200.   }
  1201.   .slider-subtitle-compact {
  1202.     font-size: 11px;
  1203.     line-height: 1.2;
  1204.   }
  1205. }
  1206. @media (max-width: 480px) {
  1207.   #imageSlider, #imageSlider .splide__track, #imageSlider .splide__slide, .slider-content-compact {
  1208.     height: 60px !important;
  1209.   }
  1210.   .slider-content-compact {
  1211.     gap: 0;
  1212.   }
  1213.   .imgslider-compact {
  1214.     height: 100% !important;
  1215.     width: 70% !important;
  1216.   }
  1217.   .slider-text-compact {
  1218.     padding: 8px 12px;
  1219.   }
  1220.   .slider-title-compact {
  1221.     font-size: 12px;
  1222.     line-height: 1.2;
  1223.   }
  1224.   .slider-subtitle-compact {
  1225.     font-size: 10px;
  1226.     line-height: 1.2;
  1227.   }
  1228. }
  1229. /* ========== EMPTY STATE ========== */
  1230. .stay-empty-wrapper {
  1231.   padding: 50px 20px 60px;
  1232.   display: flex;
  1233.   justify-content: center;
  1234. }
  1235. .stay-empty-card {
  1236.   max-width: 720px;
  1237.   width: 100%;
  1238.   background: #ffffff;
  1239.   border-radius: 24px;
  1240.   padding: 44px 40px 40px;
  1241.   box-shadow: 0 16px 50px rgba(5, 45, 60, 0.06);
  1242.   margin: 0 auto;
  1243. }
  1244. .stay-empty-title {
  1245.   font-size: 1.5rem;
  1246.   font-weight: 700;
  1247.   color: #1A1A2E;
  1248.   margin-bottom: 20px;
  1249.   text-align: center;
  1250. }
  1251. .stay-empty-intro {
  1252.   font-size: 0.98rem;
  1253.   line-height: 1.7;
  1254.   color: #5A6178;
  1255.   max-width: 580px;
  1256.   margin: 0 auto 32px;
  1257.   text-align: center;
  1258. }
  1259. /* Section \"Ce qui va arriver\" */
  1260. .stay-empty-expect {
  1261.   display: flex;
  1262.   gap: 36px;
  1263.   align-items: flex-start;
  1264.   margin-bottom: 28px;
  1265. }
  1266. .stay-empty-expect-content {
  1267.   flex: 1;
  1268. }
  1269. .stay-empty-expect-label {
  1270.   font-size: 0.92rem;
  1271.   font-weight: 600;
  1272.   color: #1A1A2E;
  1273.   margin-bottom: 16px;
  1274. }
  1275. .stay-empty-list {
  1276.   list-style: none;
  1277.   padding: 0;
  1278.   margin: 0;
  1279. }
  1280. .stay-empty-list li {
  1281.   display: flex;
  1282.   align-items: flex-start;
  1283.   gap: 12px;
  1284.   padding: 10px 0;
  1285.   font-size: 0.92rem;
  1286.   color: #4B5563;
  1287.   line-height: 1.5;
  1288. }
  1289. .stay-empty-list-icon {
  1290.   width: 28px;
  1291.   height: 28px;
  1292.   border-radius: 8px;
  1293.   display: flex;
  1294.   align-items: center;
  1295.   justify-content: center;
  1296.   flex-shrink: 0;
  1297.   margin-top: 1px;
  1298. }
  1299. .stay-empty-list-icon svg {
  1300.   width: 14px;
  1301.   height: 14px;
  1302. }
  1303. .stay-empty-list-icon--check {
  1304.   background: rgba(65, 162, 170, 0.12);
  1305.   color: #41A2AA;
  1306. }
  1307. .stay-empty-list-icon--photos {
  1308.   background: rgba(240, 158, 122, 0.12);
  1309.   color: #E8865E;
  1310. }
  1311. .stay-empty-list-icon--vocal {
  1312.   background: rgba(155, 139, 244, 0.12);
  1313.   color: #7B6BE0;
  1314. }
  1315. /* Illustration compacte */
  1316. .stay-empty-illustration {
  1317.   position: relative;
  1318.   width: 180px;
  1319.   height: 200px;
  1320.   flex-shrink: 0;
  1321. }
  1322. .stay-empty-phone {
  1323.   position: absolute;
  1324.   left: 50%;
  1325.   top: 50%;
  1326.   transform: translate(-50%, -50%);
  1327.   width: 90px;
  1328.   filter: drop-shadow(0 8px 20px rgba(0,0,0,0.1));
  1329.   animation: phoneFloat 4s ease-in-out infinite;
  1330. }
  1331. @keyframes phoneFloat {
  1332.   0%, 100% { transform: translate(-50%, -50%) translateY(0); }
  1333.   50% { transform: translate(-50%, -50%) translateY(-5px); }
  1334. }
  1335. .stay-empty-bubble {
  1336.   position: absolute;
  1337.   display: flex;
  1338.   align-items: center;
  1339.   gap: 6px;
  1340.   padding: 6px 10px;
  1341.   background: #ffffff;
  1342.   border-radius: 10px;
  1343.   box-shadow: 0 4px 14px rgba(0,0,0,0.08);
  1344.   font-size: 0.72rem;
  1345.   font-weight: 600;
  1346.   color: #1A1A2E;
  1347.   white-space: nowrap;
  1348.   opacity: 0;
  1349.   animation: bubbleFadeIn 0.5s ease forwards;
  1350. }
  1351. .stay-empty-bubble-icon {
  1352.   width: 18px;
  1353.   height: 18px;
  1354.   border-radius: 5px;
  1355.   display: flex;
  1356.   align-items: center;
  1357.   justify-content: center;
  1358.   flex-shrink: 0;
  1359. }
  1360. .stay-empty-bubble-icon svg {
  1361.   width: 10px;
  1362.   height: 10px;
  1363. }
  1364. .stay-empty-bubble--arrived {
  1365.   top: 20px;
  1366.   left: -10px;
  1367.   animation-delay: 0.4s;
  1368. }
  1369. .stay-empty-bubble--arrived .stay-empty-bubble-icon {
  1370.   background: linear-gradient(135deg, #41A2AA, #359BA3);
  1371.   color: white;
  1372. }
  1373. .stay-empty-bubble--photos {
  1374.   top: 70px;
  1375.   right: -5px;
  1376.   animation-delay: 0.9s;
  1377. }
  1378. .stay-empty-bubble--photos .stay-empty-bubble-icon {
  1379.   background: linear-gradient(135deg, #F09E7A, #E8865E);
  1380.   color: white;
  1381. }
  1382. @keyframes bubbleFadeIn {
  1383.   0% { opacity: 0; transform: translateY(6px) scale(0.95); }
  1384.   100% { opacity: 1; transform: translateY(0) scale(1); }
  1385. }
  1386. .stay-empty-illustration-label {
  1387.   position: absolute;
  1388.   bottom: 0;
  1389.   left: 50%;
  1390.   transform: translateX(-50%);
  1391.   font-size: 0.7rem;
  1392.   color: #8E95A9;
  1393.   white-space: nowrap;
  1394.   text-align: center;
  1395. }
  1396. /* Note rassurante */
  1397. .stay-empty-reassurance {
  1398.   background: #F8FAFB;
  1399.   border-radius: 12px;
  1400.   padding: 14px 20px;
  1401.   margin-bottom: 24px;
  1402.   display: flex;
  1403.   align-items: flex-start;
  1404.   gap: 12px;
  1405. }
  1406. .stay-empty-reassurance-icon {
  1407.   width: 20px;
  1408.   height: 20px;
  1409.   color: #41A2AA;
  1410.   flex-shrink: 0;
  1411.   margin-top: 2px;
  1412. }
  1413. .stay-empty-reassurance p {
  1414.   margin: 0;
  1415.   font-size: 0.85rem;
  1416.   color: #5A6178;
  1417.   line-height: 1.6;
  1418. }
  1419. /* CTA */
  1420. .stay-empty-cta {
  1421.   display: inline-flex;
  1422.   align-items: center;
  1423.   gap: 8px;
  1424.   padding: 11px 22px;
  1425.   font-size: 0.88rem;
  1426.   font-weight: 600;
  1427.   color: #41A2AA;
  1428.   background: transparent;
  1429.   border: 1.5px solid #E5E9F0;
  1430.   border-radius: 10px;
  1431.   text-decoration: none;
  1432.   transition: all 0.2s ease;
  1433. }
  1434. .stay-empty-cta:hover {
  1435.   background: #F0F9FA;
  1436.   border-color: #41A2AA;
  1437.   color: #359BA3;
  1438.   text-decoration: none;
  1439. }
  1440. .stay-empty-cta svg {
  1441.   width: 16px;
  1442.   height: 16px;
  1443. }
  1444. .stay-empty-footer {
  1445.   text-align: center;
  1446. }
  1447. /* Responsive */
  1448. @media (max-width: 700px) {
  1449.   .stay-empty-card {
  1450.     padding: 32px 24px 32px;
  1451.   }
  1452.   .stay-empty-title {
  1453.     font-size: 1.3rem;
  1454.   }
  1455.   .stay-empty-expect {
  1456.     flex-direction: column;
  1457.     gap: 24px;
  1458.   }
  1459.   .stay-empty-illustration {
  1460.     width: 100%;
  1461.     height: 160px;
  1462.     order: -1;
  1463.   }
  1464.   .stay-empty-phone {
  1465.     width: 80px;
  1466.   }
  1467.   .stay-empty-bubble {
  1468.     font-size: 0.68rem;
  1469.     padding: 5px 8px;
  1470.   }
  1471.   .stay-empty-bubble--arrived {
  1472.     left: calc(50% - 85px);
  1473.   }
  1474.   .stay-empty-bubble--photos {
  1475.     right: calc(50% - 85px);
  1476.   }
  1477.   .stay-empty-reassurance {
  1478.     flex-direction: column;
  1479.     gap: 8px;
  1480.     text-align: center;
  1481.   }
  1482.   .stay-empty-reassurance-icon {
  1483.     margin: 0 auto;
  1484.   }
  1485. }
  1486. </style>
  1487. <script>
  1488.   window.__FEATURE_PARENT_CONVERSION__ = true;
  1489.   // Configuration runtime pour le système B2C
  1490.   ";
  1491.         // line 1575
  1492.         yield "  ";
  1493.         $context["nowTimestamp"] = $this->extensions['Twig\Extension\CoreExtension']->formatDate("now""U");
  1494.         // line 1576
  1495.         yield "  ";
  1496.         $context["debutTimestamp"] = $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.'1576$this->source); })()), "dateDebutSejour", [], "any"falsefalsefalse1576), "U");
  1497.         // line 1577
  1498.         yield "  ";
  1499.         $context["finTimestamp"] = $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.'1577$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse1577), "U");
  1500.         // line 1578
  1501.         yield "  ";
  1502.         $context["finCodeDateJS"] = (((CoreExtension::getAttribute($this->env$this->source, ($context["sejour"] ?? null), "dateFinCode", [], "any"truetruefalse1578) &&  !(null === 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.'1578$this->source); })()), "dateFinCode", [], "any"falsefalsefalse1578)))) ? (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.'1578$this->source); })()), "dateFinCode", [], "any"falsefalsefalse1578)) : ($this->extensions['Twig\Extension\CoreExtension']->modifyDate(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.'1578$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse1578), "+42 days")));
  1503.         // line 1579
  1504.         yield "  ";
  1505.         $context["closeTimestamp"] = $this->extensions['Twig\Extension\CoreExtension']->formatDate((isset($context["finCodeDateJS"]) || array_key_exists("finCodeDateJS"$context) ? $context["finCodeDateJS"] : (function () { throw new RuntimeError('Variable "finCodeDateJS" does not exist.'1579$this->source); })()), "U");
  1506.         // line 1580
  1507.         yield "  ";
  1508.         $context["daysSinceStartCalc"] = Twig\Extension\CoreExtension::round((((isset($context["nowTimestamp"]) || array_key_exists("nowTimestamp"$context) ? $context["nowTimestamp"] : (function () { throw new RuntimeError('Variable "nowTimestamp" does not exist.'1580$this->source); })()) - (isset($context["debutTimestamp"]) || array_key_exists("debutTimestamp"$context) ? $context["debutTimestamp"] : (function () { throw new RuntimeError('Variable "debutTimestamp" does not exist.'1580$this->source); })())) / 86400), 0"floor");
  1509.         // line 1581
  1510.         yield "  ";
  1511.         $context["daysUntilEndCalc"] = Twig\Extension\CoreExtension::round((((isset($context["finTimestamp"]) || array_key_exists("finTimestamp"$context) ? $context["finTimestamp"] : (function () { throw new RuntimeError('Variable "finTimestamp" does not exist.'1581$this->source); })()) - (isset($context["nowTimestamp"]) || array_key_exists("nowTimestamp"$context) ? $context["nowTimestamp"] : (function () { throw new RuntimeError('Variable "nowTimestamp" does not exist.'1581$this->source); })())) / 86400), 0"ceil");
  1512.         // line 1582
  1513.         yield "  ";
  1514.         $context["daysAfterEndCalc"] = Twig\Extension\CoreExtension::round((((isset($context["nowTimestamp"]) || array_key_exists("nowTimestamp"$context) ? $context["nowTimestamp"] : (function () { throw new RuntimeError('Variable "nowTimestamp" does not exist.'1582$this->source); })()) - (isset($context["finTimestamp"]) || array_key_exists("finTimestamp"$context) ? $context["finTimestamp"] : (function () { throw new RuntimeError('Variable "finTimestamp" does not exist.'1582$this->source); })())) / 86400), 0"floor");
  1515.         // line 1583
  1516.         yield "  ";
  1517.         $context["daysUntilCloseCalc"] = Twig\Extension\CoreExtension::round((((isset($context["closeTimestamp"]) || array_key_exists("closeTimestamp"$context) ? $context["closeTimestamp"] : (function () { throw new RuntimeError('Variable "closeTimestamp" does not exist.'1583$this->source); })()) - (isset($context["nowTimestamp"]) || array_key_exists("nowTimestamp"$context) ? $context["nowTimestamp"] : (function () { throw new RuntimeError('Variable "nowTimestamp" does not exist.'1583$this->source); })())) / 86400), 0"ceil");
  1518.         // line 1584
  1519.         yield "  
  1520.   window.PARENT_CONVERSION_CONFIG = {
  1521.     user: {
  1522.       prenom: \"";
  1523.         // line 1587
  1524.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, ($context["app"] ?? null), "user", [], "any"falsetruefalse1587), "prenom", [], "any"truetruefalse1587)) ? (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.'1587$this->source); })()), "user", [], "any"falsefalsefalse1587), "prenom", [], "any"falsefalsefalse1587), "Parent")) : ("Parent")), "js"), "html"nulltrue);
  1525.         yield "\"
  1526.     },
  1527.     sejour: {
  1528.       id: ";
  1529.         // line 1590
  1530.         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.'1590$this->source); })()), "id", [], "any"falsefalsefalse1590), "html"nulltrue);
  1531.         yield ",
  1532.       dateDebut: \"";
  1533.         // line 1591
  1534.         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.'1591$this->source); })()), "dateDebutSejour", [], "any"falsefalsefalse1591), "Y-m-d"), "html"nulltrue);
  1535.         yield "\",
  1536.       dateFin: \"";
  1537.         // line 1592
  1538.         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.'1592$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse1592), "Y-m-d"), "html"nulltrue);
  1539.         yield "\",
  1540.       dateFinCode: \"";
  1541.         // line 1593
  1542.         yield (((($tmp 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.'1593$this->source); })()), "dateFinCode", [], "any"falsefalsefalse1593)) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($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.'1593$this->source); })()), "dateFinCode", [], "any"falsefalsefalse1593), "Y-m-d"), "html"nulltrue)) : (""));
  1543.         yield "\",
  1544.       isTermine: ";
  1545.         // line 1594
  1546.         yield (((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.'1594$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse1594) < $this->extensions['Twig\Extension\CoreExtension']->convertDate())) ? ("true") : ("false"));
  1547.         yield "
  1548.     },
  1549.     dates: {
  1550.       aujourdhui: \"";
  1551.         // line 1597
  1552.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatDate("now""Y-m-d"), "html"nulltrue);
  1553.         yield "\",
  1554.       isFirstDay: ";
  1555.         // line 1598
  1556.         yield ((($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.'1598$this->source); })()), "dateDebutSejour", [], "any"falsefalsefalse1598), "Y-m-d") == $this->extensions['Twig\Extension\CoreExtension']->formatDate("now""Y-m-d"))) ? ("true") : ("false"));
  1557.         yield ",
  1558.       isWithin: ";
  1559.         // line 1599
  1560.         yield ((((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.'1599$this->source); })()), "dateDebutSejour", [], "any"falsefalsefalse1599) <= $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.'1599$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse1599) >= $this->extensions['Twig\Extension\CoreExtension']->convertDate()))) ? ("true") : ("false"));
  1561.         yield ",
  1562.       daysSinceStart: ";
  1563.         // line 1600
  1564.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((array_key_exists("daysSinceStartCalc"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["daysSinceStartCalc"]) || array_key_exists("daysSinceStartCalc"$context) ? $context["daysSinceStartCalc"] : (function () { throw new RuntimeError('Variable "daysSinceStartCalc" does not exist.'1600$this->source); })()), 0)) : (0)), "html"nulltrue);
  1565.         yield ",
  1566.       daysUntilEnd: ";
  1567.         // line 1601
  1568.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((array_key_exists("daysUntilEndCalc"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["daysUntilEndCalc"]) || array_key_exists("daysUntilEndCalc"$context) ? $context["daysUntilEndCalc"] : (function () { throw new RuntimeError('Variable "daysUntilEndCalc" does not exist.'1601$this->source); })()), 0)) : (0)), "html"nulltrue);
  1569.         yield ",
  1570.       daysAfterEnd: ";
  1571.         // line 1602
  1572.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((array_key_exists("daysAfterEndCalc"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["daysAfterEndCalc"]) || array_key_exists("daysAfterEndCalc"$context) ? $context["daysAfterEndCalc"] : (function () { throw new RuntimeError('Variable "daysAfterEndCalc" does not exist.'1602$this->source); })()), 0)) : (0)), "html"nulltrue);
  1573.         yield ",
  1574.       daysUntilClose: ";
  1575.         // line 1603
  1576.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((array_key_exists("daysUntilCloseCalc"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["daysUntilCloseCalc"]) || array_key_exists("daysUntilCloseCalc"$context) ? $context["daysUntilCloseCalc"] : (function () { throw new RuntimeError('Variable "daysUntilCloseCalc" does not exist.'1603$this->source); })()), 0)) : (0)), "html"nulltrue);
  1577.         yield "
  1578.     },
  1579.     stats: {
  1580.       totalDays: ";
  1581.         // line 1606
  1582.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'1606$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse1606), "diff", [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.'1606$this->source); })()), "dateDebutSejour", [], "any"falsefalsefalse1606)], "method"falsefalsefalse1606), "days", [], "any"falsefalsefalse1606), "html"nulltrue);
  1583.         yield ",
  1584.       totalPhotos: ";
  1585.         // line 1607
  1586.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((array_key_exists("attachementsCount"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["attachementsCount"]) || array_key_exists("attachementsCount"$context) ? $context["attachementsCount"] : (function () { throw new RuntimeError('Variable "attachementsCount" does not exist.'1607$this->source); })()), 0)) : (0)), "html"nulltrue);
  1587.         yield ",
  1588.       totalMessages: ";
  1589.         // line 1608
  1590.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((array_key_exists("nbmessages"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["nbmessages"]) || array_key_exists("nbmessages"$context) ? $context["nbmessages"] : (function () { throw new RuntimeError('Variable "nbmessages" does not exist.'1608$this->source); })()), 0)) : (0)), "html"nulltrue);
  1591.         yield ",
  1592.       todayPhotos: ";
  1593.         // line 1609
  1594.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((array_key_exists("photosDuJour"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["photosDuJour"]) || array_key_exists("photosDuJour"$context) ? $context["photosDuJour"] : (function () { throw new RuntimeError('Variable "photosDuJour" does not exist.'1609$this->source); })()), 0)) : (0)), "html"nulltrue);
  1595.         yield "
  1596.     },
  1597.     parent: {
  1598.       favorites: ";
  1599.         // line 1612
  1600.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((array_key_exists("nblikes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'1612$this->source); })()), 0)) : (0)), "html"nulltrue);
  1601.         yield ",
  1602.       cartCount: 0,
  1603.       lastVisitAt: \"";
  1604.         // line 1614
  1605.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatDate("now""Y-m-d H:i:s"), "html"nulltrue);
  1606.         yield "\"
  1607.     }
  1608.   };
  1609.   // Catalogue produits (routes réelles 5sur5)
  1610.   window.PARENT_PRODUCT_CATALOG = {
  1611.     digi10: { title:\"Pack numérique 10 photos\", badge:\"Petit budget\", url:\"";
  1612.         // line 1620
  1613.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("boutique5sur5");
  1614.         yield "\" },
  1615.     digi25: { title:\"Pack numérique 25 photos\", badge:\"Immédiat\", url:\"";
  1616.         // line 1621
  1617.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("boutique5sur5");
  1618.         yield "\" },
  1619.     retro12: { title:\"Pochette rétro 12 tirages\", badge:\"Cadeau\", url:\"";
  1620.         // line 1622
  1621.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("boutique5sur5");
  1622.         yield "\" },
  1623.     prints20: { title:\"Pochette 20 tirages\", badge:\"Best seller\", url:\"";
  1624.         // line 1623
  1625.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("boutique5sur5");
  1626.         yield "\" },
  1627.     album24: { title:\"Mini-album 24 pages\", badge:\"Parfait début\", url:\"";
  1628.         // line 1624
  1629.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("Album_du_Sejour");
  1630.         yield "\" },
  1631.     album48: { title:\"Album Premium 48 pages\", badge:\"Meilleure vente\", url:\"";
  1632.         // line 1625
  1633.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("Album_du_Sejour");
  1634.         yield "\" },
  1635.     mix10Poster: { title:\"Pack mixte 10 tirages + poster\", badge:\"Combo\", url:\"";
  1636.         // line 1626
  1637.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("boutique5sur5");
  1638.         yield "\" },
  1639.     bundleAlbumPrints: { title:\"Album + tirages (-15%)\", badge:\"Éco\", url:\"";
  1640.         // line 1627
  1641.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("boutique5sur5");
  1642.         yield "\" }
  1643.   };
  1644. </script>
  1645. <style>
  1646. .btn-close {
  1647.   font-size: 1.2rem;
  1648.   border: none;
  1649.   background: transparent;
  1650. }
  1651. .slide img {
  1652.   max-width: 100%;
  1653.   max-height: 100%;
  1654.   object-fit: contain;
  1655.   border-radius: 8px;
  1656.   box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
  1657.   transition: transform 0.3s ease;
  1658.   cursor: pointer;
  1659. }
  1660. .slide img.zoomed {
  1661.   transform: scale(1.5);
  1662.   cursor: zoom-in;
  1663. }
  1664. /* === Badges discrets des cartes jours (style accompagnateur avec Bootstrap) === */
  1665. /* Les badges utilisent directement les classes Bootstrap: badge, bg-success, bg-info, position-absolute */
  1666. /* === Affichage des dates (style accompagnateur exact) === */
  1667. .container--gallery.modern {
  1668.   background: #ffffff;
  1669.   border-radius: 32px;
  1670.   padding: 10px;
  1671.   box-shadow: 0 30px 70px rgba(11, 36, 71, 0.08);
  1672.   border: 1px solid rgba(65, 162, 170, 0.08);
  1673.   min-height:1000px;
  1674. }
  1675. @media (max-width: 768px) {
  1676.   .container--gallery.modern {
  1677.     padding: 24px;
  1678.     min-height:500px;
  1679.   }
  1680. }
  1681. .pro-journal {
  1682.   background: linear-gradient(145deg, #f8fbff 0%, #ffffff 100%);
  1683.   border-radius: 24px;
  1684.   padding: 28px;
  1685.   margin-bottom: 28px;
  1686.   border: 1px solid rgba(65, 162, 170, 0.08);
  1687.   box-shadow: 0 18px 45px rgba(11, 36, 71, 0.05);
  1688. }
  1689. .pro-entry-header {
  1690.   display: flex;
  1691.   align-items: center;
  1692.   justify-content: space-between;
  1693.   flex-wrap: wrap;
  1694.   gap: 18px;
  1695.   margin-bottom: 20px;
  1696. }
  1697. .pro-entry-header .date-chip {
  1698.   display: inline-flex;
  1699.   align-items: center;
  1700.   gap: 10px;
  1701.   padding: 10px 18px;
  1702.   border-radius: 999px;
  1703.   background: rgba(65, 162, 170, 0.08);
  1704.   color: #1f2933;
  1705.   font-weight: 600;
  1706.   font-size: 0.95rem;
  1707. }
  1708. .gallery-meta-chips {
  1709.   display: flex;
  1710.   flex-wrap: wrap;
  1711.   gap: 10px;
  1712.   align-items: center;
  1713. }
  1714. .gallery-meta-chips .filter-badge {
  1715.   background: #ffffff;
  1716.   border: 1px solid rgba(15, 40, 77, 0.08);
  1717.   border-radius: 999px;
  1718.   padding: 8px 14px;
  1719.   font-size: 0.85rem;
  1720.   font-weight: 600;
  1721.   color: #405064;
  1722.   display: inline-flex;
  1723.   align-items: center;
  1724.   gap: 6px;
  1725.   transition: all 0.2s ease;
  1726. }
  1727. .gallery-meta-chips .filter-badge.active {
  1728.   background: #41a2aa;
  1729.   color: #fff;
  1730.   border-color: #41a2aa;
  1731.   box-shadow: 0 8px 20px rgba(65, 162, 170, 0.25);
  1732. }
  1733. .gallery-grid {
  1734.   width: 100%;
  1735.   display: grid !important;
  1736.   grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  1737.   gap: 18px;
  1738. }
  1739. .gallery-grid .column {
  1740.   margin: 0 !important;
  1741. }
  1742. .gallery-grid .photo-item,
  1743. .gallery-grid .video-item,
  1744. .gallery-grid .audio-message-item {
  1745.   border-radius: 18px;
  1746.   background: #fff;
  1747.   border: 1px solid rgba(15, 40, 77, 0.08);
  1748.   box-shadow: 0 12px 30px rgba(11, 36, 71, 0.08);
  1749. }
  1750. .gallery-grid .photo-item img {
  1751.   border-radius: 16px;
  1752.   height: 220px;
  1753.   object-fit: cover;
  1754. }
  1755. .gallery-grid .video-item video,
  1756. .gallery-grid .audio-message-item audio {
  1757.   border-radius: 12px;
  1758. }
  1759. </style>
  1760. ";
  1761.         
  1762.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  1763.         
  1764.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  1765.         yield from [];
  1766.     }
  1767.     // line 1762
  1768.     /**
  1769.      * @return iterable<null|scalar|\Stringable>
  1770.      */
  1771.     public function block_Content(array $context, array $blocks = []): iterable
  1772.     {
  1773.         $macros $this->macros;
  1774.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  1775.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""Content"));
  1776.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  1777.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""Content"));
  1778.         // line 1764
  1779.         yield "
  1780. <div class=\"main-content\">
  1781.   <div class=\"row no-margin\">
  1782.     <!-- Bouton cadeau attractif e-commerce -->
  1783.     ";
  1784.         // line 1770
  1785.         $context["showGiftButton"] = (Twig\Extension\CoreExtension::length($this->env->getCharset(), ((array_key_exists("likes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'1770$this->source); })()), [])) : ([]))) > 0);
  1786.         // line 1771
  1787.         yield "    <div
  1788.       class=\"gift-button\"
  1789.       id=\"gift-button-trigger\"
  1790.       data-has-favorites=\"";
  1791.         // line 1774
  1792.         yield (((($tmp = (isset($context["showGiftButton"]) || array_key_exists("showGiftButton"$context) ? $context["showGiftButton"] : (function () { throw new RuntimeError('Variable "showGiftButton" does not exist.'1774$this->source); })())) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ("1") : ("0"));
  1793.         yield "\"
  1794.       style=\"cursor: pointer; ";
  1795.         // line 1775
  1796.         yield (((($tmp = (isset($context["showGiftButton"]) || array_key_exists("showGiftButton"$context) ? $context["showGiftButton"] : (function () { throw new RuntimeError('Variable "showGiftButton" does not exist.'1775$this->source); })())) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ("") : ("display:none;"));
  1797.         yield "\"
  1798.     >
  1799.       <i id=\"gift-icon-payment\" class=\"bi bi-gift gift-pulse\"></i>
  1800.       <label
  1801.         id=\"giftCount\"
  1802.         class=\"labelGiftCount gift-count-bounce\"
  1803.         style=\"background-color: #f56040\"
  1804.       >
  1805.         ";
  1806.         // line 1783
  1807.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ((array_key_exists("likes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'1783$this->source); })()), [])) : ([]))), "html"nulltrue);
  1808.         yield "
  1809.       </label>
  1810.       <!-- Message flottant attractif -->
  1811.       <div class=\"gift-tooltip\" id=\"giftTooltip\">
  1812.         <div class=\"gift-tooltip-content\">
  1813.           <div class=\"gift-tooltip-header\">
  1814.             <i class=\"bi bi-clock-history\"></i>
  1815.             <strong>Offre limitée !</strong>
  1816.           </div>
  1817.           <p>Commandez vite ! Les photos seront disponibles seulement pendant <strong>6 semaines</strong> après la fin du séjour.</p>
  1818.           <div class=\"gift-tooltip-cta\">
  1819.             <i class=\"bi bi-lightning-charge\"></i>
  1820.             Commander maintenant
  1821.           </div>
  1822.         </div>
  1823.       </div>
  1824.     </div>
  1825.     <!-- Sidebar E-commerce -->
  1826.     <div id=\"ecommerce-sidebar\">
  1827.       <div class=\"ecommerce-header\">
  1828.         <h2 class=\"ecommerce-title\" id=\"ecommerce-title\">
  1829.           🎉 Vos souvenirs favoris sont prêts !
  1830.         </h2>
  1831.         <p class=\"ecommerce-subtitle\" id=\"ecommerce-subtitle\">
  1832.           ";
  1833.         // line 1808
  1834.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ((array_key_exists("likes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'1808$this->source); })()), [])) : ([]))), "html"nulltrue);
  1835.         yield " photos sélectionnées avec amour ❤️
  1836.         </p>
  1837.         <button class=\"ecommerce-close\" onclick=\"closeEcommerceSidebar()\">
  1838.           <i class=\"bi bi-x\"></i>
  1839.         </button>
  1840.       </div>
  1841.       <div class=\"ecommerce-content\">
  1842.         <!-- Bannière d'urgence -->
  1843.         <div class=\"urgency-banner\" id=\"urgency-banner\">
  1844.           <div>
  1845.             <i class=\"bi bi-clock-history\"></i>
  1846.             <strong>⏳ Commandez vite !</strong>
  1847.           </div>
  1848.           <div> Les photos seront disponibles seulement <strong>6 semaines</strong> après la fin du séjour</div>
  1849.           <div class=\"countdown\" id=\"countdown-timer\" style=\"display: none;\">
  1850.             Plus que <span id=\"days-left\">0</span> jours !
  1851.           </div>
  1852.         </div>
  1853.         <!-- Produits recommandés -->
  1854.         <div id=\"products-container\">
  1855.           <!-- Album Photo -->
  1856.           <div class=\"product-card popular\" id=\"album-card\">
  1857.             <div class=\"product-header\">
  1858.               <div class=\"product-icon\">
  1859.                 <img src=\"/images/produit/Album5sur5-3.jpg\" alt=\"Album Photo Premium\" style=\"width: 100%; height: 100%; object-fit: contain; border-radius: 8px;\">
  1860.               </div>
  1861.               <div class=\"product-info\">
  1862.                 <h4>Album Photo Premium</h4>
  1863.                 <div class=\"product-pricing\">
  1864.                   <span class=\"current-price\">24,90€</span>
  1865.                   <span class=\"original-price\">28,90€</span>
  1866.                   <span class=\"savings\">-14%</span>
  1867.                 </div>
  1868.               </div>
  1869.               <div class=\"product-favorites-indicator\" title=\"Photos favorites sélectionnées\">
  1870.                 <i class=\"bi bi-heart-fill\" style=\"color: #f56040\"></i>
  1871.                 <span id=\"album-fav-count\">";
  1872.         // line 1846
  1873.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ((array_key_exists("likes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'1846$this->source); })()), [])) : ([]))), "html"nulltrue);
  1874.         yield "</span>
  1875.               </div>
  1876.             </div>
  1877.             <p class=\"product-description\">
  1878.               Album photo personnalisé avec vos <strong id=\"album-count\">";
  1879.         // line 1850
  1880.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ((array_key_exists("likes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'1850$this->source); })()), [])) : ([]))), "html"nulltrue);
  1881.         yield "</strong> photos favorites. Papier de qualité supérieure, reliure rigide.
  1882.             </p>
  1883.             <button class=\"product-cta\" onclick=\"orderProduct('album')\" 
  1884.                     title=\"Commander l'album photo avec vos photos favorites\">
  1885.               <i class=\"bi bi-cart-plus\"></i>
  1886.               Commander l'album
  1887.             </button>
  1888.           </div>
  1889.           <!-- Pack Numérique -->
  1890.           <div class=\"product-card\" id=\"digital-card\">
  1891.             <div class=\"product-header\">
  1892.               <div class=\"product-icon\">
  1893.                 <img src=\"/images/produit/photoNumerique.jpg\" alt=\"Pack Numérique HD\" style=\"width: 100%; height: 100%; object-fit: contain; border-radius: 8px;\">
  1894.               </div>
  1895.               <div class=\"product-info\">
  1896.                 <h4>Pack Numérique HD</h4>
  1897.                 <p class=\"price\">À partir de 3,90€</p>
  1898.               </div>
  1899.                 <div class=\"product-favorites-indicator\" title=\"Photos favorites sélectionnées\">
  1900.                   <i class=\"bi bi-heart-fill\" style=\"color: #f56040\"></i>
  1901.                   <span id=\"digital-fav-count\">";
  1902.         // line 1871
  1903.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ((array_key_exists("likes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'1871$this->source); })()), [])) : ([]))), "html"nulltrue);
  1904.         yield "</span>
  1905.                 </div>
  1906.             </div>
  1907.             <p class=\"product-description\">
  1908.               Téléchargement immédiat de vos <strong id=\"digital-count\">";
  1909.         // line 1875
  1910.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ((array_key_exists("likes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'1875$this->source); })()), [])) : ([]))), "html"nulltrue);
  1911.         yield "</strong> photos en haute définition. Qualité professionnelle garantie.
  1912.             </p>
  1913.             <button class=\"product-cta\" onclick=\"orderProduct('digital')\" 
  1914.                     title=\"Télécharger vos photos en haute définition\">
  1915.               <i class=\"bi bi-download\"></i>
  1916.               Télécharger HD
  1917.             </button>
  1918.           </div>
  1919.           <!-- Pochette Tirages -->
  1920.           <div class=\"product-card\" id=\"prints-card\" style=\"display: none;\">
  1921.             <div class=\"product-header\">
  1922.               <div class=\"product-icon\">
  1923.                 <i class=\"bi bi-images\"></i>
  1924.               </div>
  1925.               <div class=\"product-info\">
  1926.                 <h4>Pochette Tirages</h4>
  1927.                 <p class=\"price\">À partir de 9,90€</p>
  1928.               </div>
  1929.               <div class=\"product-favorites-indicator\" title=\"Photos favorites sélectionnées\">
  1930.                 <i class=\"bi bi-heart-fill\" style=\"color: #f56040\"></i>
  1931.                 <span>";
  1932.         // line 1896
  1933.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ((array_key_exists("likes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'1896$this->source); })()), [])) : ([]))), "html"nulltrue);
  1934.         yield "</span>
  1935.               </div>
  1936.             </div>
  1937.             <p class=\"product-description\">
  1938.               <strong id=\"prints-count\">12</strong> tirages photo 10x15cm de vos favoris. Papier brillant professionnel, envoi sous 48h.
  1939.             </p>
  1940.             <button class=\"product-cta\" onclick=\"orderProduct('prints')\" 
  1941.                     title=\"Commander des tirages photo de vos favoris\">
  1942.               <i class=\"bi bi-printer\"></i>
  1943.               Commander les tirages
  1944.             </button>
  1945.           </div>
  1946.         </div>
  1947.         <!-- Réassurance -->
  1948.         <div class=\"reassurance\">
  1949.           <i class=\"bi bi-shield-check\" style=\"color: #10b981; margin-right: 8px;\"></i>
  1950.           <strong>Imprimé en France – satisfaction garantie ✅</strong>
  1951.         </div>
  1952.         
  1953.       </div>
  1954.     </div>
  1955.     <div class=\"selection-popover\" id=\"selectionPopover\">
  1956.       <h4>Votre sélection</h4>
  1957.       <p>Tirages : ";
  1958.         // line 1921
  1959.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ((array_key_exists("likes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'1921$this->source); })()), [])) : ([]))), "html"nulltrue);
  1960.         yield " / 12</p>
  1961.       <p>Numériques : ";
  1962.         // line 1922
  1963.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ((array_key_exists("likes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'1922$this->source); })()), [])) : ([]))), "html"nulltrue);
  1964.         yield " / 15</p>
  1965.       <p>Album : ";
  1966.         // line 1923
  1967.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), ((array_key_exists("likes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'1923$this->source); })()), [])) : ([]))), "html"nulltrue);
  1968.         yield " / 20</p>
  1969.       <button class=\"finalize-button\" onclick=\"openEcommerceSidebar()\" 
  1970.               title=\"Voir les produits disponibles avec vos favoris\">
  1971.         <i class=\"bi bi-gift\"></i>
  1972.         Finaliser ma commande
  1973.       </button>
  1974.     </div>
  1975.     
  1976.     <style>
  1977.       /* Amélioration des boutons de produits */
  1978.       .product-cta {
  1979.         background: #3a8d95;
  1980.         border: none;
  1981.         border-radius: 25px;
  1982.         color: white;
  1983.         padding: 12px 24px;
  1984.         font-weight: 600;
  1985.         cursor: pointer;
  1986.         transition: all 0.3s ease;
  1987.         display: flex;
  1988.         align-items: center;
  1989.         gap: 8px;
  1990.         width: 100%;
  1991.         justify-content: center;
  1992.         margin-top: 10px;
  1993.       }
  1994.       
  1995.       .product-cta:hover {
  1996.         transform: translateY(-2px);
  1997.         box-shadow: 0 5px 15px rgba(58, 141, 149, 0.4);
  1998.         background: #2f7a82;
  1999.       }
  2000.       
  2001.       .product-cta:active {
  2002.         transform: translateY(0);
  2003.       }
  2004.       
  2005.       .product-cta:disabled {
  2006.         background: #ccc;
  2007.         cursor: not-allowed;
  2008.         transform: none;
  2009.         box-shadow: none;
  2010.       }
  2011.       
  2012.       .finalize-button {
  2013.         background: linear-gradient(135deg, #e91e63 0%, #ad1457 100%);
  2014.         border: none;
  2015.         border-radius: 25px;
  2016.         color: white;
  2017.         padding: 12px 24px;
  2018.         font-weight: 600;
  2019.         cursor: pointer;
  2020.         transition: all 0.3s ease;
  2021.         display: flex;
  2022.         align-items: center;
  2023.         gap: 8px;
  2024.         width: 100%;
  2025.         justify-content: center;
  2026.         margin-top: 15px;
  2027.       }
  2028.       
  2029.       .finalize-button:hover {
  2030.         transform: translateY(-2px);
  2031.         box-shadow: 0 5px 15px rgba(233, 30, 99, 0.4);
  2032.         background: linear-gradient(135deg, #d81b60 0%, #9c1450 100%);
  2033.       }
  2034.       
  2035.       /* Amélioration des cartes de produits */
  2036.       .product-card {
  2037.         border-radius: 12px;
  2038.         box-shadow: 0 4px 15px rgba(0,0,0,0.1);
  2039.         transition: all 0.3s ease;
  2040.         margin-bottom: 20px;
  2041.         overflow: hidden;
  2042.       }
  2043.       
  2044.       .product-card:hover {
  2045.         transform: translateY(-5px);
  2046.         box-shadow: 0 8px 25px rgba(0,0,0,0.15);
  2047.       }
  2048.       
  2049.       .product-header {
  2050.         display: flex;
  2051.         align-items: center;
  2052.         gap: 15px;
  2053.         padding: 20px;
  2054.         background: #f8f9fa;
  2055.       }
  2056.       
  2057.       .product-icon {
  2058.         width: 60px;
  2059.         height: 60px;
  2060.         border-radius: 8px;
  2061.         overflow: hidden;
  2062.         flex-shrink: 0;
  2063.       }
  2064.       
  2065.       .product-info h4 {
  2066.         margin: 0 0 5px 0;
  2067.         color: #333;
  2068.         font-weight: 600;
  2069.       }
  2070.       
  2071.       .product-pricing {
  2072.         display: flex;
  2073.         align-items: center;
  2074.         gap: 10px;
  2075.         margin: 5px 0;
  2076.       }
  2077.       
  2078.       .current-price {
  2079.         font-size: 1.2rem;
  2080.         font-weight: 700;
  2081.         color: #e91e63;
  2082.       }
  2083.       
  2084.       .original-price {
  2085.         text-decoration: line-through;
  2086.         color: #666;
  2087.         font-size: 0.9rem;
  2088.       }
  2089.       
  2090.       .savings {
  2091.         background: #4caf50;
  2092.         color: white;
  2093.         padding: 2px 8px;
  2094.         border-radius: 12px;
  2095.         font-size: 0.8rem;
  2096.         font-weight: 600;
  2097.       }
  2098.       
  2099.       .product-description {
  2100.         padding: 0 20px 20px 20px;
  2101.         color: #666;
  2102.         line-height: 1.5;
  2103.       }
  2104.       
  2105.       .product-favorites-indicator {
  2106.         display: flex;
  2107.         align-items: center;
  2108.         gap: 5px;
  2109.         background: rgba(245, 96, 64, 0.1);
  2110.         padding: 5px 10px;
  2111.         border-radius: 15px;
  2112.         font-size: 0.9rem;
  2113.         color: #f56040;
  2114.         font-weight: 600;
  2115.       }
  2116.     </style>
  2117.   </div>
  2118.   ";
  2119.         // line 2075
  2120.         yield "  ";
  2121.         if ((((array_key_exists("attachementsCount"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["attachementsCount"]) || array_key_exists("attachementsCount"$context) ? $context["attachementsCount"] : (function () { throw new RuntimeError('Variable "attachementsCount" does not exist.'2075$this->source); })()), 0)) : (0)) > 0)) {
  2122.             // line 2076
  2123.             yield "  
  2124.   ";
  2125.             // line 2078
  2126.             yield "  ";
  2127.             $context["isSejourTermine"] = (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.'2078$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse2078) < $this->extensions['Twig\Extension\CoreExtension']->convertDate());
  2128.             // line 2079
  2129.             yield "  ";
  2130.             $context["finCodeDate"] = (((CoreExtension::getAttribute($this->env$this->source, ($context["sejour"] ?? null), "dateFinCode", [], "any"truetruefalse2079) &&  !(null === 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.'2079$this->source); })()), "dateFinCode", [], "any"falsefalsefalse2079)))) ? (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.'2079$this->source); })()), "dateFinCode", [], "any"falsefalsefalse2079)) : ($this->extensions['Twig\Extension\CoreExtension']->modifyDate(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.'2079$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse2079), "+42 days")));
  2131.             // line 2080
  2132.             yield "  ";
  2133.             $context["daysUntilClose"] = Twig\Extension\CoreExtension::round((($this->extensions['Twig\Extension\CoreExtension']->formatDate((isset($context["finCodeDate"]) || array_key_exists("finCodeDate"$context) ? $context["finCodeDate"] : (function () { throw new RuntimeError('Variable "finCodeDate" does not exist.'2080$this->source); })()), "U") - $this->extensions['Twig\Extension\CoreExtension']->formatDate("now""U")) / 86400), 0"ceil");
  2134.             // line 2081
  2135.             yield "  
  2136.   <section id=\"heroPromo\" style=\"margin: 0; padding: 0;\">
  2137.     ";
  2138.             // line 2084
  2139.             yield "    ";
  2140.             if ((($tmp = (isset($context["isSejourTermine"]) || array_key_exists("isSejourTermine"$context) ? $context["isSejourTermine"] : (function () { throw new RuntimeError('Variable "isSejourTermine" does not exist.'2084$this->source); })())) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2141.                 // line 2085
  2142.                 yield "    <div class=\"promo-banner-termine\" id=\"promoBannerTermine\">
  2143.       <div class=\"promo-banner-content\">
  2144.         <span class=\"promo-banner-icon\">🎬</span>
  2145.         <div class=\"promo-banner-text\">
  2146.           ";
  2147.                 // line 2089
  2148.                 if (((isset($context["daysUntilClose"]) || array_key_exists("daysUntilClose"$context) ? $context["daysUntilClose"] : (function () { throw new RuntimeError('Variable "daysUntilClose" does not exist.'2089$this->source); })()) > 0)) {
  2149.                     // line 2090
  2150.                     yield "            <strong>Séjour terminé — Dernière chance !</strong>
  2151.             Plus que <span class=\"promo-days\">";
  2152.                     // line 2091
  2153.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["daysUntilClose"]) || array_key_exists("daysUntilClose"$context) ? $context["daysUntilClose"] : (function () { throw new RuntimeError('Variable "daysUntilClose" does not exist.'2091$this->source); })()), "html"nulltrue);
  2154.                     yield "</span> jour";
  2155.                     yield ((((isset($context["daysUntilClose"]) || array_key_exists("daysUntilClose"$context) ? $context["daysUntilClose"] : (function () { throw new RuntimeError('Variable "daysUntilClose" does not exist.'2091$this->source); })()) > 1)) ? ("s") : (""));
  2156.                     yield " pour commander vos souvenirs.
  2157.           ";
  2158.                 } else {
  2159.                     // line 2093
  2160.                     yield "            <strong>Séjour terminé</strong>
  2161.             Créez vos souvenirs : albums, tirages, photos numériques...
  2162.           ";
  2163.                 }
  2164.                 // line 2096
  2165.                 yield "        </div>
  2166.         <a href=\"";
  2167.                 // line 2097
  2168.                 yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("boutique5sur5");
  2169.                 yield "\" class=\"promo-banner-cta\">Commander</a>
  2170.         <button class=\"promo-banner-close\" onclick=\"this.parentElement.parentElement.style.display='none'\" aria-label=\"Fermer\">×</button>
  2171.       </div>
  2172.     </div>
  2173.     ";
  2174.             } else {
  2175.                 // line 2102
  2176.                 yield "    ";
  2177.                 // line 2103
  2178.                 yield "    <div class=\"divSliderModern\" style=\"margin: 0; padding: 0; width: 100%; overflow: hidden;\">
  2179.       <div class=\"splide no-padding no-margin\" id=\"imageSlider\" style=\"width: 100%;\">
  2180.         <div class=\"splide__track\" style=\"width: 100%;\">
  2181.           <ul class=\"splide__list\" style=\"width: 100%;\">
  2182.             <li class=\"splide__slide\" style=\"width: 100%;\">
  2183.               <div class=\"slider-content-compact\">
  2184.                 <img src=\"";
  2185.                 // line 2109
  2186.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("/images/imgSliderEmpty2.png"), "html"nulltrue);
  2187.                 yield "\" class=\"imgslider-compact\" alt=\"Produits souvenirs\" />
  2188.                 <div class=\"slider-text-compact\">
  2189.                   <span class=\"slider-title-compact\" style=\"color: #41a2aa\">Ajoutez vos favoris</span>
  2190.                   <span class=\"slider-subtitle-compact\" style=\"color: #f09e7a\">et créez vos souvenirs personnalisés !</span>
  2191.                 </div>
  2192.             </div>
  2193.           </li>
  2194.             <li class=\"splide__slide\" style=\"width: 100%;\">
  2195.               <div class=\"slider-content-compact\">
  2196.                 <img src=\"";
  2197.                 // line 2118
  2198.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("/images/imgSliderEmpty1.png"), "html"nulltrue);
  2199.                 yield "\" class=\"imgslider-compact\" alt=\"Livre du séjour\" />
  2200.                 <div class=\"slider-text-compact\">
  2201.                   <span class=\"slider-title-compact\" style=\"color: #f09e7a\">Pensez à commander le livre</span>
  2202.                   <span class=\"slider-subtitle-compact\" style=\"color: #41a2aa\">et offrez le plus beau des cadeaux !</span>
  2203.               </div>
  2204.             </div>
  2205.           </li>
  2206.         </ul>
  2207.       </div>
  2208.     </div>
  2209.   </div>
  2210.     ";
  2211.             }
  2212.             // line 2130
  2213.             yield "  </section>
  2214.   ";
  2215.         }
  2216.         // line 2132
  2217.         yield "  ";
  2218.         // line 2133
  2219.         yield "  
  2220.   <!-- Section de contenu à atteindre après le scroll -->
  2221.   <div
  2222.     class=\"no-margin\"
  2223.     id=\"scrollTarget\"
  2224.     style=\"width: 100%; background: #ffffff; padding-top: 16px\"
  2225.   >
  2226.     <div class=\"no-margin\" id=\"scrollTarget\" style=\"width: 100%\">
  2227.       <!-- Header premium 5sur5 -->
  2228.       <header class=\"premium-5sur5-day-header\" style=\"padding: 5px 25px; background: #ffffff; border-bottom: 1px solid rgba(65, 162, 170, 0.1); margin-bottom: -15px;\">
  2229.         <div class=\"d-flex justify-content-between align-items-center flex-wrap gap-3\">
  2230.           <div class=\"flex-grow-1\">
  2231.             <h5 class=\"premium-5sur5-day-title\" style=\"margin: 0 0 6px 0; font-size: 1.3rem; font-weight: 700; color: #1a1a1a;\">
  2232.               ";
  2233.         // line 2146
  2234.         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.'2146$this->source); })()), "themSejour", [], "any"falsefalsefalse2146), "html"nulltrue);
  2235.         yield "
  2236.             </h5>
  2237.             <p class=\"premium-5sur5-day-subtitle\" style=\"margin: 0; font-size: 0.9rem; color: #6b7280; font-weight: 500;\">
  2238.                    du ";
  2239.         // line 2149
  2240.         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.'2149$this->source); })()), "dateDebutSejour", [], "any"falsefalsefalse2149), "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);
  2241.         yield "
  2242.           au ";
  2243.         // line 2150
  2244.         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.'2150$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse2150), "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);
  2245.         yield "
  2246.               · Code : <span style=\"color: #41a2aa; font-weight: 600;\">";
  2247.         // line 2151
  2248.         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.'2151$this->source); })()), "codeSejour", [], "any"falsefalsefalse2151), "html"nulltrue);
  2249.         yield "</span>
  2250.             </p>
  2251.         </div>
  2252.           <!-- 🎯 MEDIA TOOLBAR PREMIUM - Style 5sur5 -->
  2253.           <div class=\"premium-5sur5-actions-group\" style=\"gap: 8px;\">
  2254.             <!-- Tout -->
  2255.           <button class=\"premium-5sur5-action-btn mtb-btn ";
  2256.         // line 2158
  2257.         if ((((array_key_exists("attachementsCount"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["attachementsCount"]) || array_key_exists("attachementsCount"$context) ? $context["attachementsCount"] : (function () { throw new RuntimeError('Variable "attachementsCount" does not exist.'2158$this->source); })()), 0)) : (0)) > 0)) {
  2258.             yield "active";
  2259.         }
  2260.         yield "\" data-filter=\"all\" title=\"Tout\">
  2261.             <i class=\"bi bi-grid-3x3-gap-fill\"></i>
  2262.             <span>Tout</span>
  2263.             <span class=\"premium-5sur5-badge\" style=\"background: rgba(65, 162, 170, 0.1); color: #41A2AA;\">";
  2264.         // line 2161
  2265.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((array_key_exists("attachementsCount"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["attachementsCount"]) || array_key_exists("attachementsCount"$context) ? $context["attachementsCount"] : (function () { throw new RuntimeError('Variable "attachementsCount" does not exist.'2161$this->source); })()), 0)) : (0)), "html"nulltrue);
  2266.         yield "</span>
  2267.             </button>
  2268.           <!-- Favoris -->
  2269.           <button 
  2270.             class=\"premium-5sur5-action-btn mtb-btn ";
  2271.         // line 2166
  2272.         if ((((array_key_exists("nblikes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'2166$this->source); })()), 0)) : (0)) == 0)) {
  2273.             yield "favoris-empty";
  2274.         }
  2275.         yield "\" 
  2276.             data-filter=\"favoris\" 
  2277.             title=\"";
  2278.         // line 2168
  2279.         if ((((array_key_exists("nblikes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'2168$this->source); })()), 0)) : (0)) == 0)) {
  2280.             yield "Pas de favoris pour l'instant";
  2281.         } else {
  2282.             yield "Mes favoris";
  2283.         }
  2284.         yield "\"
  2285.             ";
  2286.         // line 2169
  2287.         if ((((array_key_exists("nblikes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'2169$this->source); })()), 0)) : (0)) == 0)) {
  2288.             yield "disabled";
  2289.         }
  2290.         // line 2170
  2291.         yield "          >
  2292.             <i class=\"bi bi-heart-fill\" style=\"color:";
  2293.         // line 2171
  2294.         if ((((array_key_exists("nblikes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'2171$this->source); })()), 0)) : (0)) == 0)) {
  2295.             yield "#cbd5e1";
  2296.         } else {
  2297.             yield "#f56040";
  2298.         }
  2299.         yield ";\"></i>
  2300.             <span>Favoris</span>
  2301.             <span class=\"favoris-count\" id=\"mesFavCount\" data-bind=\"fav\" data-empty-text=\"Pas de favoris\">
  2302.               ";
  2303.         // line 2174
  2304.         if ((((array_key_exists("nblikes"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'2174$this->source); })()), 0)) : (0)) == 0)) {
  2305.             // line 2175
  2306.             yield "                <span class=\"favoris-empty-text\" style=\"color: #94a3b8; font-style: italic; font-size: 11px;\">Pas de favoris</span>
  2307.               ";
  2308.         } else {
  2309.             // line 2177
  2310.             yield "                <span class=\"premium-5sur5-badge\" style=\"background: rgba(245, 96, 64, 0.1); color: #F56040;\">";
  2311.             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.'2177$this->source); })()), "html"nulltrue);
  2312.             yield "</span>
  2313.               ";
  2314.         }
  2315.         // line 2179
  2316.         yield "</span>
  2317.             </button>
  2318.           <!-- Vocal -->
  2319.           <button class=\"premium-5sur5-action-btn mtb-btn\" data-filter=\"audio\" title=\"Messages vocaux\">
  2320.             <span class=\"icon-telephone-voicemail\" style=\"display: inline-flex; align-items: center; gap: 0;\">
  2321.               <i class=\"bi bi-telephone-fill\" style=\"color:#ffd700; font-size: 14px;\"></i>
  2322.               <i class=\"bi bi-voicemail\" style=\"color:#ffd700; font-size: 14px; margin-left: -4px;\"></i>
  2323.             </span>
  2324.             <span>Vocal</span>
  2325.             <span class=\"mtb-count premium-5sur5-badge\" data-bind=\"audio\" style=\"background: rgba(255, 215, 0, 0.15); color: #ffa500;\">0</span>
  2326.             </button>
  2327.           </div>
  2328.         </div>
  2329.       </header>
  2330.         <!-- Navigation par jours - Style Premium compact -->
  2331.         <div class=\"section-days\" style=\"background: #f8fafb; border-radius: 0px; padding: 10px 12px; margin: 12px 0 16px 0; border: 1px solid rgba(65, 162, 170, 0.1);\">
  2332.           <div class=\"date-navigation d-flex align-items-center justify-content-center\" style=\"gap: 0;\">
  2333.             <div class=\"date-container d-flex\" style=\"overflow-x: auto; overflow-y: hidden; gap: 10px; padding: 4px 0; scrollbar-width: thin; scrollbar-color: #41a2aa #f0f0f0;\">
  2334.               ";
  2335.         // line 2199
  2336.         $context['_parent'] = $context;
  2337.         $context['_seq'] = CoreExtension::ensureTraversable((isset($context["listeattach"]) || array_key_exists("listeattach"$context) ? $context["listeattach"] : (function () { throw new RuntimeError('Variable "listeattach" does not exist.'2199$this->source); })()));
  2338.         $context['loop'] = [
  2339.           'parent' => $context['_parent'],
  2340.           'index0' => 0,
  2341.           'index'  => 1,
  2342.           'first'  => true,
  2343.         ];
  2344.         if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) {
  2345.             $length count($context['_seq']);
  2346.             $context['loop']['revindex0'] = $length 1;
  2347.             $context['loop']['revindex'] = $length;
  2348.             $context['loop']['length'] = $length;
  2349.             $context['loop']['last'] = === $length;
  2350.         }
  2351.         foreach ($context['_seq'] as $context["x"] => $context["groupAttach"]) {
  2352.             // line 2200
  2353.             yield "                ";
  2354.             $context["xDate"] = $this->extensions['Twig\Extension\CoreExtension']->convertDate($context["x"]);
  2355.             // line 2201
  2356.             yield "                ";
  2357.             $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.'2201$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse2201));
  2358.             // line 2202
  2359.             yield "                ";
  2360.             $context["todayStr"] = $this->extensions['Twig\Extension\CoreExtension']->formatDate("now""Y-m-d");
  2361.             // line 2203
  2362.             yield "                ";
  2363.             $context["currentDateStr"] = $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.'2203$this->source); })()), "Y-m-d");
  2364.             // line 2204
  2365.             yield "                
  2366.                 ";
  2367.             // line 2205
  2368.             if (((isset($context["xDate"]) || array_key_exists("xDate"$context) ? $context["xDate"] : (function () { throw new RuntimeError('Variable "xDate" does not exist.'2205$this->source); })()) <= (isset($context["finDate"]) || array_key_exists("finDate"$context) ? $context["finDate"] : (function () { throw new RuntimeError('Variable "finDate" does not exist.'2205$this->source); })()))) {
  2369.                 // line 2206
  2370.                 yield "                  ";
  2371.                 // line 2207
  2372.                 yield "                  ";
  2373.                 $context["isPast"] = ((isset($context["currentDateStr"]) || array_key_exists("currentDateStr"$context) ? $context["currentDateStr"] : (function () { throw new RuntimeError('Variable "currentDateStr" does not exist.'2207$this->source); })()) < (isset($context["todayStr"]) || array_key_exists("todayStr"$context) ? $context["todayStr"] : (function () { throw new RuntimeError('Variable "todayStr" does not exist.'2207$this->source); })()));
  2374.                 // line 2208
  2375.                 yield "                  ";
  2376.                 $context["isCurrent"] = ((isset($context["currentDateStr"]) || array_key_exists("currentDateStr"$context) ? $context["currentDateStr"] : (function () { throw new RuntimeError('Variable "currentDateStr" does not exist.'2208$this->source); })()) == (isset($context["todayStr"]) || array_key_exists("todayStr"$context) ? $context["todayStr"] : (function () { throw new RuntimeError('Variable "todayStr" does not exist.'2208$this->source); })()));
  2377.                 // line 2209
  2378.                 yield "                  ";
  2379.                 $context["isFuture"] = ((isset($context["currentDateStr"]) || array_key_exists("currentDateStr"$context) ? $context["currentDateStr"] : (function () { throw new RuntimeError('Variable "currentDateStr" does not exist.'2209$this->source); })()) > (isset($context["todayStr"]) || array_key_exists("todayStr"$context) ? $context["todayStr"] : (function () { throw new RuntimeError('Variable "todayStr" does not exist.'2209$this->source); })()));
  2380.                 // line 2210
  2381.                 yield "                  ";
  2382.                 $context["isFirstDay"] = (CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "isFirstDay", [], "any"falsefalsefalse2210) == "yes");
  2383.                 // line 2211
  2384.                 yield "                  ";
  2385.                 $context["isLastDay"] = (CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "isLastDay", [], "any"falsefalsefalse2211) == "yes");
  2386.                 // line 2212
  2387.                 yield "                  
  2388.                   ";
  2389.                 // line 2214
  2390.                 yield "                  ";
  2391.                 $context["cardClasses"] = ["date-card""premium-day-card"];
  2392.                 // line 2215
  2393.                 yield "                  ";
  2394.                 if ((($tmp = (isset($context["isFuture"]) || array_key_exists("isFuture"$context) ? $context["isFuture"] : (function () { throw new RuntimeError('Variable "isFuture" does not exist.'2215$this->source); })())) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2395.                     // line 2216
  2396.                     yield "                    ";
  2397.                     $context["cardClasses"] = Twig\Extension\CoreExtension::merge((isset($context["cardClasses"]) || array_key_exists("cardClasses"$context) ? $context["cardClasses"] : (function () { throw new RuntimeError('Variable "cardClasses" does not exist.'2216$this->source); })()), ["premium-day-future""notclickable"]);
  2398.                     // line 2217
  2399.                     yield "                  ";
  2400.                 } elseif ((($tmp = (isset($context["isCurrent"]) || array_key_exists("isCurrent"$context) ? $context["isCurrent"] : (function () { throw new RuntimeError('Variable "isCurrent" does not exist.'2217$this->source); })())) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2401.                     // line 2218
  2402.                     yield "                    ";
  2403.                     $context["cardClasses"] = Twig\Extension\CoreExtension::merge((isset($context["cardClasses"]) || array_key_exists("cardClasses"$context) ? $context["cardClasses"] : (function () { throw new RuntimeError('Variable "cardClasses" does not exist.'2218$this->source); })()), ["premium-day-current""active"]);
  2404.                     // line 2219
  2405.                     yield "                  ";
  2406.                 } else {
  2407.                     // line 2220
  2408.                     yield "                    ";
  2409.                     $context["cardClasses"] = Twig\Extension\CoreExtension::merge((isset($context["cardClasses"]) || array_key_exists("cardClasses"$context) ? $context["cardClasses"] : (function () { throw new RuntimeError('Variable "cardClasses" does not exist.'2220$this->source); })()), ["premium-day-past"]);
  2410.                     // line 2221
  2411.                     yield "                    ";
  2412.                     if ((CoreExtension::getAttribute($this->env$this->source$context["loop"], "last", [], "any"falsefalsefalse2221) &&  !(isset($context["isCurrent"]) || array_key_exists("isCurrent"$context) ? $context["isCurrent"] : (function () { throw new RuntimeError('Variable "isCurrent" does not exist.'2221$this->source); })()))) {
  2413.                         // line 2222
  2414.                         yield "                      ";
  2415.                         $context["cardClasses"] = Twig\Extension\CoreExtension::merge((isset($context["cardClasses"]) || array_key_exists("cardClasses"$context) ? $context["cardClasses"] : (function () { throw new RuntimeError('Variable "cardClasses" does not exist.'2222$this->source); })()), ["active"]);
  2416.                         // line 2223
  2417.                         yield "                    ";
  2418.                     }
  2419.                     // line 2224
  2420.                     yield "                  ";
  2421.                 }
  2422.                 // line 2225
  2423.                 yield "
  2424.                   <div
  2425.                     class=\"";
  2426.                 // line 2227
  2427.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::join((isset($context["cardClasses"]) || array_key_exists("cardClasses"$context) ? $context["cardClasses"] : (function () { throw new RuntimeError('Variable "cardClasses" does not exist.'2227$this->source); })()), " "), "html"nulltrue);
  2428.                 yield " position-relative\"
  2429.                     id=\"iconedemoP";
  2430.                 // line 2228
  2431.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index", [], "any"falsefalsefalse2228), "html"nulltrue);
  2432.                 yield "\"
  2433.                     ";
  2434.                 // line 2229
  2435.                 if ((($tmp = (isset($context["isFuture"]) || array_key_exists("isFuture"$context) ? $context["isFuture"] : (function () { throw new RuntimeError('Variable "isFuture" does not exist.'2229$this->source); })())) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2436.                     // line 2230
  2437.                     yield "                      data-tooltip=\"Ce jour n'est pas encore accessible\"
  2438.                       aria-disabled=\"true\"
  2439.                     ";
  2440.                 } else {
  2441.                     // line 2233
  2442.                     yield "                    data-bs-toggle=\"collapse\"
  2443.                     data-bs-target=\"#demP";
  2444.                     // line 2234
  2445.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index", [], "any"falsefalsefalse2234), "html"nulltrue);
  2446.                     yield "\"
  2447.                       data-day-id=\"";
  2448.                     // line 2235
  2449.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["currentDateStr"]) || array_key_exists("currentDateStr"$context) ? $context["currentDateStr"] : (function () { throw new RuntimeError('Variable "currentDateStr" does not exist.'2235$this->source); })()), "html"nulltrue);
  2450.                     yield "\"
  2451.                       aria-expanded=\"false\"
  2452.                       aria-controls=\"demP";
  2453.                     // line 2237
  2454.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index", [], "any"falsefalsefalse2237), "html"nulltrue);
  2455.                     yield "\"
  2456.                     tabindex=\"0\"
  2457.                     ";
  2458.                 }
  2459.                 // line 2240
  2460.                 yield "                  >
  2461.                     ";
  2462.                 // line 2242
  2463.                 yield "                    ";
  2464.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "isFirstDay", [], "any"falsefalsefalse2242) == "yes")) {
  2465.                     // line 2243
  2466.                     yield "                      <span class=\"badge bg-success text-white position-absolute\" style=\"top: 5px; left: 5px; font-size: 0.5rem; padding: 0.2rem 0.2rem;\">
  2467.                         <i class=\"bi bi-play-fill me-1\"></i>
  2468.                       </span>
  2469.                     ";
  2470.                 } elseif ((CoreExtension::getAttribute($this->env$this->source,                 // line 2246
  2471. $context["groupAttach"], "isLastDay", [], "any"falsefalsefalse2246) == "yes")) {
  2472.                     // line 2247
  2473.                     yield "                      <span class=\"badge bg-info text-white position-absolute\" style=\"top: 5px; left: 5px; font-size: 0.5rem; padding: 0.2rem 0.2rem;\">
  2474.                         <i class=\"bi bi-flag-fill ms-1\"></i>
  2475.                       </span>
  2476.                     ";
  2477.                 }
  2478.                 // line 2251
  2479.                 yield "                    
  2480.                     <div class=\"card-content text-center\">
  2481.                       <span class=\"day\">
  2482.                        ";
  2483.                 // line 2254
  2484.                 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.'2254$this->source); })()), "D"), ["Mon" => "lun.""Tue" => "mar.""Wed" => "mer.""Thu" => "jeu.""Fri" => "ven.""Sat" => "sam.""Sun" => "dim."]), "html"nulltrue);
  2485.                 // line 2258
  2486.                 yield "  
  2487.                       </span>
  2488.                       <span class=\"full-date\">
  2489.                         ";
  2490.                 // line 2261
  2491.                 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.'2261$this->source); })()), "d M Y"), ["Jan" => "janv.""Feb" => "fév.""Mar" => "mars""Apr" => "avr.""May" => "mai""Jun" => "juin""Jul" => "juil.""Aug" => "août""Sep" => "sept.""Oct" => "oct.""Nov" => "nov.""Dec" => "déc."]), "html"nulltrue);
  2492.                 // line 2266
  2493.                 yield "
  2494.                       </span>
  2495.                       <ul class=\"media-list-horizontal\">
  2496.                         ";
  2497.                 // line 2269
  2498.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"falsefalsefalse2269) > 0)) {
  2499.                     // line 2270
  2500.                     yield "                          <li><i class=\"bi bi-camera\"></i> ";
  2501.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"falsefalsefalse2270), "html"nulltrue);
  2502.                     yield "</li>
  2503.                         ";
  2504.                 }
  2505.                 // line 2272
  2506.                 yield "                        ";
  2507.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse2272) > 0)) {
  2508.                     // line 2273
  2509.                     yield "                          <li><i class=\"bi bi-mic-fill\"></i> ";
  2510.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse2273), "html"nulltrue);
  2511.                     yield "</li>
  2512.                         ";
  2513.                 }
  2514.                 // line 2275
  2515.                 yield "                        ";
  2516.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"falsefalsefalse2275) > 0)) {
  2517.                     // line 2276
  2518.                     yield "                          <li><i class=\"bi bi-camera-video\"></i> ";
  2519.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"falsefalsefalse2276), "html"nulltrue);
  2520.                     yield "</li>
  2521.                         ";
  2522.                 }
  2523.                 // line 2278
  2524.                 yield "                      </ul>
  2525.                     </div>
  2526.                   </div>
  2527.                 ";
  2528.             }
  2529.             // line 2282
  2530.             yield "              ";
  2531.             ++$context['loop']['index0'];
  2532.             ++$context['loop']['index'];
  2533.             $context['loop']['first'] = false;
  2534.             if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) {
  2535.                 --$context['loop']['revindex0'];
  2536.                 --$context['loop']['revindex'];
  2537.                 $context['loop']['last'] = === $context['loop']['revindex0'];
  2538.             }
  2539.         }
  2540.         $_parent $context['_parent'];
  2541.         unset($context['_seq'], $context['x'], $context['groupAttach'], $context['_parent'], $context['loop']);
  2542.         $context array_intersect_key($context$_parent) + $_parent;
  2543.         // line 2283
  2544.         yield "            </div>
  2545.           </div>
  2546.         </div>
  2547.     <!-- Carte produit flottante -->
  2548.     <div id=\"dynamic-card\" class=\"dynamic-card\" style=\"display:none\">
  2549.       <div id=\"dynamic-card-content\" class=\"dynamic-card-content\" >
  2550.         <!-- Le contenu dynamique (album, pochette, montage vidéo) sera injecté ici -->
  2551.       </div>
  2552.     </div>
  2553.     <!-- Descriptions and Attachments avec sidebar B2C -->
  2554.     <div class=\"container-xxl\" style=\"padding: 0 25px;  margin: 0 auto;\">
  2555.       <div class=\"row g-2 col-md-12\" style=\"margin: 0;\">
  2556.         <div class=\"col-lg-12 col-md-12\" style=\"padding: 0;\">
  2557.           ";
  2558.         // line 2299
  2559.         yield "          <div class=\"container--gallery modern\" data-anchor=\"gallery\" style=\"padding: 0;\">
  2560.             ";
  2561.         // line 2300
  2562.         $context["lastValidIndex"] = 0;
  2563.         // line 2301
  2564.         yield "            ";
  2565.         $context["hasAttachments"] = false;
  2566.         // line 2302
  2567.         yield "      ";
  2568.         $context['_parent'] = $context;
  2569.         $context['_seq'] = CoreExtension::ensureTraversable((isset($context["listeattach"]) || array_key_exists("listeattach"$context) ? $context["listeattach"] : (function () { throw new RuntimeError('Variable "listeattach" does not exist.'2302$this->source); })()));
  2570.         $context['loop'] = [
  2571.           'parent' => $context['_parent'],
  2572.           'index0' => 0,
  2573.           'index'  => 1,
  2574.           'first'  => true,
  2575.         ];
  2576.         if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) {
  2577.             $length count($context['_seq']);
  2578.             $context['loop']['revindex0'] = $length 1;
  2579.             $context['loop']['revindex'] = $length;
  2580.             $context['loop']['length'] = $length;
  2581.             $context['loop']['last'] = === $length;
  2582.         }
  2583.         foreach ($context['_seq'] as $context["x"] => $context["groupAttach"]) {
  2584.             // line 2303
  2585.             yield "      ";
  2586.             $context["xDate"] = $this->extensions['Twig\Extension\CoreExtension']->convertDate($context["x"]);
  2587.             // line 2304
  2588.             yield "      ";
  2589.             $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.'2304$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse2304));
  2590.             // line 2305
  2591.             yield "      ";
  2592.             if (((isset($context["xDate"]) || array_key_exists("xDate"$context) ? $context["xDate"] : (function () { throw new RuntimeError('Variable "xDate" does not exist.'2305$this->source); })()) <= (isset($context["finDate"]) || array_key_exists("finDate"$context) ? $context["finDate"] : (function () { throw new RuntimeError('Variable "finDate" does not exist.'2305$this->source); })()))) {
  2593.                 // line 2306
  2594.                 yield "      ";
  2595.                 $context["lastValidIndex"] = CoreExtension::getAttribute($this->env$this->source$context["loop"], "index", [], "any"falsefalsefalse2306);
  2596.                 // line 2307
  2597.                 yield "      ";
  2598.                 $context["hasAttachments"] = true;
  2599.                 // line 2308
  2600.                 yield "      <div
  2601.         id=\"demP";
  2602.                 // line 2309
  2603.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index", [], "any"falsefalsefalse2309), "html"nulltrue);
  2604.                 yield "\"
  2605.         class=\"collapse ";
  2606.                 // line 2310
  2607.                 if ((CoreExtension::getAttribute($this->env$this->source$context["loop"], "last", [], "any"falsefalsefalse2310) && ((isset($context["xDate"]) || array_key_exists("xDate"$context) ? $context["xDate"] : (function () { throw new RuntimeError('Variable "xDate" does not exist.'2310$this->source); })()) <= (isset($context["finDate"]) || array_key_exists("finDate"$context) ? $context["finDate"] : (function () { throw new RuntimeError('Variable "finDate" does not exist.'2310$this->source); })())))) {
  2608.                     yield "show";
  2609.                 }
  2610.                 yield "\"
  2611.         style=\"padding: 12px 0;\"
  2612.       >
  2613.         <div >
  2614.         <div class=\"entry-header\" style=\"
  2615.     display: none;
  2616.     align-items: center;
  2617.     justify-content: space-between;
  2618.     background: #ffffff;
  2619.     padding: 8px 15px;
  2620.     border-radius: 10px;
  2621.     margin-bottom: 20px;
  2622.     box-shadow: 0 2px 8px rgba(0,0,0,0.05);
  2623.     border-bottom: 1px solid #eee;
  2624.     flex-wrap: wrap;
  2625. \">
  2626.  
  2627.  
  2628.   <!-- Centre : Date + Médias -->
  2629.   <div style=\"
  2630.       flex-grow: 1;
  2631.       display: flex;
  2632.       align-items: center;
  2633.       justify-content: center;
  2634.       flex-wrap: wrap;
  2635.       gap: 12px;
  2636.   \">
  2637.     <!-- Date -->
  2638.     <div style=\"font-weight: bold; font-size: 16px; color: #333;\">
  2639.       ";
  2640.                 // line 2340
  2641.                 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);
  2642.                 // line 2348
  2643.                 yield "
  2644.     </div>
  2645.   <!-- Filtres Médias -->
  2646. <div class=\"filter-icons\" style=\"display: flex; gap: 8px; flex-wrap: wrap;\">
  2647.     <span class=\"filter-badge active\" data-filter=\"all\" title=\"Afficher tout\">
  2648.         <i class=\"bi bi-grid-3x3-gap-fill\" style=\"margin-right: 5px; font-size: 14px;\"></i> Tout
  2649.     </span>
  2650.     ";
  2651.                 // line 2357
  2652.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"falsefalsefalse2357) > 0)) {
  2653.                     // line 2358
  2654.                     yield "    <span class=\"filter-badge\" data-filter=\"photo\" title=\"Filtrer les photos\">
  2655.         <i class=\"bi bi-image\" style=\"margin-right: 5px; font-size: 14px;\"></i> ";
  2656.                     // line 2359
  2657.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"falsefalsefalse2359), "html"nulltrue);
  2658.                     yield "
  2659.     </span>
  2660.     ";
  2661.                 }
  2662.                 // line 2362
  2663.                 yield "
  2664.     ";
  2665.                 // line 2363
  2666.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"falsefalsefalse2363) > 0)) {
  2667.                     // line 2364
  2668.                     yield "    <span class=\"filter-badge\" data-filter=\"video\" title=\"Filtrer les vidéos\">
  2669.         <i class=\"bi bi-camera-video-fill\" style=\"margin-right: 5px; font-size: 14px;\"></i> ";
  2670.                     // line 2365
  2671.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"falsefalsefalse2365), "html"nulltrue);
  2672.                     yield "
  2673.     </span>
  2674.     ";
  2675.                 }
  2676.                 // line 2368
  2677.                 yield "
  2678.     ";
  2679.                 // line 2369
  2680.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse2369) > 0)) {
  2681.                     // line 2370
  2682.                     yield "    <span class=\"filter-badge\" data-filter=\"audio\" title=\"Filtrer les messages audio\">
  2683.         <i class=\"bi bi-mic-fill\" style=\"margin-right: 5px; font-size: 14px;\"></i> ";
  2684.                     // line 2371
  2685.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse2371), "html"nulltrue);
  2686.                     yield "
  2687.     </span>
  2688.     ";
  2689.                 }
  2690.                 // line 2374
  2691.                 yield "</div>
  2692.   </div>
  2693.    
  2694.    
  2695.         </div>
  2696.   <!-- Bouton Jour Suivant -->
  2697.         <!-- Contenu -->
  2698.         <div class=\"entry-content\" id=\"TourContent\">
  2699.           <!-- Dropdown de filtrage par jour -->
  2700.           <div class=\"day-filter-dropdown\" data-day-index=\"";
  2701.                 // line 2392
  2702.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index", [], "any"falsefalsefalse2392), "html"nulltrue);
  2703.                 yield "\">
  2704.             <button class=\"filter-toggle\" type=\"button\" aria-label=\"Options de filtrage\">
  2705.               <i class=\"bi bi-three-dots\"></i>
  2706.             </button>
  2707.             <div class=\"filter-dropdown-menu\">
  2708.               <div class=\"filter-option active\" data-filter=\"all\">
  2709.                 <i class=\"bi bi-grid-3x3-gap-fill\"></i>
  2710.                 <span>Tout</span>
  2711.                 <span class=\"count\" data-count-all>0</span>
  2712.               </div>
  2713.               <div class=\"filter-option\" data-filter=\"photo\">
  2714.                 <i class=\"bi bi-image\"></i>
  2715.                 <span>Photos</span>
  2716.                 <span class=\"count\" data-count-photo>";
  2717.                 // line 2405
  2718.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"truetruefalse2405)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"falsefalsefalse2405), 0)) : (0)), "html"nulltrue);
  2719.                 yield "</span>
  2720.               </div>
  2721.               <div class=\"filter-option\" data-filter=\"video\">
  2722.                 <i class=\"bi bi-camera-video-fill\"></i>
  2723.                 <span>Vidéos</span>
  2724.                 <span class=\"count\" data-count-video>";
  2725.                 // line 2410
  2726.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"truetruefalse2410)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"falsefalsefalse2410), 0)) : (0)), "html"nulltrue);
  2727.                 yield "</span>
  2728.               </div>
  2729.               <div class=\"filter-option\" data-filter=\"audio\">
  2730.                 <i class=\"bi bi-mic-fill\"></i>
  2731.                 <span>Messages</span>
  2732.                 <span class=\"count\" data-count-audio>";
  2733.                 // line 2415
  2734.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"truetruefalse2415)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse2415), 0)) : (0)), "html"nulltrue);
  2735.                 yield "</span>
  2736.               </div>
  2737.             </div>
  2738.           </div>
  2739.                ";
  2740.                 // line 2419
  2741.                 $context['_parent'] = $context;
  2742.                 $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.'2419$this->source); })()), "jourdescripdate", [], "any"falsefalsefalse2419));
  2743.                 foreach ($context['_seq'] as $context["_key"] => $context["description"]) {
  2744.                     // line 2420
  2745.                     yield "      ";
  2746.                     if (($this->extensions['Twig\Extension\CoreExtension']->formatDate(CoreExtension::getAttribute($this->env$this->source$context["description"], "datejourphoto", [], "any"falsefalsefalse2420), "m/d/Y") != "")) {
  2747.                         if (($this->extensions['Twig\Extension\CoreExtension']->formatDate(CoreExtension::getAttribute($this->env$this->source,                         // line 2421
  2748. $context["description"], "datejourphoto", [], "any"falsefalsefalse2421), "m/d/Y") == $this->extensions['Twig\Extension\CoreExtension']->formatDate($context["x"], "m/d/Y"))) {
  2749.                             // line 2422
  2750.                             yield "          <p class=\"description\" style=\"margin-left:2%;width:95%;margin-top:1%;margin-bottom:1%;text-align:left\">
  2751.         
  2752.             ";
  2753.                             // line 2424
  2754.                             yield Twig\Extension\CoreExtension::nl2br($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["description"], "description", [], "any"falsefalsefalse2424), "html"nulltrue));
  2755.                             yield "
  2756.          
  2757.           </p>   ";
  2758.                         }
  2759.                         // line 2426
  2760.                         yield 
  2761.        ";
  2762.                     }
  2763.                 }
  2764.                 $_parent $context['_parent'];
  2765.                 unset($context['_seq'], $context['_key'], $context['description'], $context['_parent']);
  2766.                 $context array_intersect_key($context$_parent) + $_parent;
  2767.                 // line 2428
  2768.                 yield 
  2769.           <!-- Conteneur des photos et vidéos -->
  2770.           <div
  2771.             class=\"rowimag no-margin\"
  2772.             style=\"
  2773.               width: 100%;
  2774.               display: flex;
  2775.               flex-wrap: wrap;
  2776.               margin: 0;
  2777.               box-sizing: border-box;
  2778.             \"
  2779.           >
  2780.             <!-- Afficher les Photos et Vidéos -->
  2781.             ";
  2782.                 // line 2441
  2783.                 $context['_parent'] = $context;
  2784.                 $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "attachments", [], "any"falsefalsefalse2441));
  2785.                 foreach ($context['_seq'] as $context["_key"] => $context["attach"]) {
  2786.                     // line 2442
  2787.                     yield "              ";
  2788.                     if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse2442) == "photo")) {
  2789.                         // line 2443
  2790.                         yield "           
  2791.             <div class=\"column\" data-type=\"";
  2792.                         // line 2444
  2793.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse2444), "html"nulltrue);
  2794.                         yield "\">
  2795.             
  2796.               <div class=\"photo-zoom photo-item\">
  2797.                 <!-- Image sans lien -->
  2798.                 <img src=\"";
  2799.                         // line 2448
  2800.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "path", [], "any"falsefalsefalse2448), "html"nulltrue);
  2801.                         yield "\" alt=\"";
  2802.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse2448), "html"nulltrue);
  2803.                         yield "\" loading=\"lazy\" decoding=\"async\" />
  2804.                 <!-- Icône \"voir\" pour ouvrir le slider -->
  2805.                 <div class=\"view-icon\" onclick=\"viewImage('";
  2806.                         // line 2451
  2807.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "id_attchment", [], "any"falsefalsefalse2451), "html"nulltrue);
  2808.                         yield "', this)\" title=\"Voir en plein écran\">
  2809.                   <i class=\"bi bi-eye-fill\"></i>
  2810.                 </div>
  2811.                 <!-- Icône du cœur avec logique existante -->
  2812.                 <div
  2813.                   class=\"heart-icon\"
  2814.                   id=\"coeur";
  2815.                         // line 2458
  2816.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "id_attchment", [], "any"falsefalsefalse2458), "html"nulltrue);
  2817.                         yield "\"
  2818.                   data-id=\"";
  2819.                         // line 2459
  2820.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "id_attchment", [], "any"falsefalsefalse2459), "html"nulltrue);
  2821.                         yield "\"
  2822.                   data-sejour-id=\"";
  2823.                         // line 2460
  2824.                         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.'2460$this->source); })()), "id", [], "any"falsefalsefalse2460), "html"nulltrue);
  2825.                         yield "\"
  2826.                   data-path=\"";
  2827.                         // line 2461
  2828.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "path", [], "any"falsefalsefalse2461), "html"nulltrue);
  2829.                         yield "\"
  2830.                   data-description=\"";
  2831.                         // line 2462
  2832.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse2462), "html"nulltrue);
  2833.                         yield "\"
  2834.                 >
  2835.                   ";
  2836.                         // line 2464
  2837.                         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.'2464$this->source); })()), "user", [], "any"falsefalsefalse2464)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2838.                             yield " ";
  2839.                             if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["attach"], "is_favorite", [], "any"falsefalsefalse2464)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  2840.                                 // line 2465
  2841.                                 yield "                  <i
  2842.                     class=\"bi bi-heart-fill\"
  2843.                     title=\"Sélectionnée\"
  2844.                     style=\"color: #f56040\"
  2845.                   ></i>
  2846.                   ";
  2847.                             } else {
  2848.                                 // line 2471
  2849.                                 yield "                  <i class=\"bi bi-heart\" title=\"Ajouter à ma sélection\"></i>
  2850.                   ";
  2851.                             }
  2852.                             // line 2472
  2853.                             yield " ";
  2854.                         }
  2855.                         // line 2473
  2856.                         yield "                </div>
  2857.                 <div class=\"photo-actions\" style=\"display: none\">
  2858.                   <button class=\"menu-btn\">⋮</button>
  2859.                   <div class=\"menu-options\">
  2860.                     <button onclick=\"addToPack('tirage')\">
  2861.                       🖨️ Ajouter au tirage
  2862.                     </button>
  2863.                     <button onclick=\"addToPack('numerique')\">
  2864.                       💾 Ajouter au numérique
  2865.                     </button>
  2866.                   </div>
  2867.                 </div>
  2868.               
  2869.               </div>
  2870.               ";
  2871.                         // line 2487
  2872.                         if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse2487) != "")) {
  2873.                             // line 2488
  2874.                             yield "              <h4 class=\"description\">";
  2875.                             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse2488), "html"nulltrue);
  2876.                             yield "</h4>
  2877.               ";
  2878.                         }
  2879.                         // line 2490
  2880.                         yield "            </div>
  2881.             ";
  2882.                     }
  2883.                     // line 2494
  2884.                     yield 
  2885.              ";
  2886.                     // line 2497
  2887.                     if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse2497) == "video")) {
  2888.                         // line 2498
  2889.                         yield "           
  2890.             <div class=\"column\" data-type=\"";
  2891.                         // line 2499
  2892.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse2499), "html"nulltrue);
  2893.                         yield "\">
  2894.                  
  2895.             
  2896.                  <div class=\"video-container\" style=\"position: relative; display: inline-block; width: 100%; border-radius: 8px; overflow: hidden;\">
  2897.                         <video class=\"photo-zoom\" controls controlslist=\"nodownload noplaybackrate\" style=\"width: 100%;\">
  2898.                           <source src=\"";
  2899.                         // line 2504
  2900.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "path", [], "any"falsefalsefalse2504), "html"nulltrue);
  2901.                         yield "\" type=\"video/mp4\" />
  2902.                           Votre navigateur ne supporte pas la lecture vidéo.
  2903.                         </video>
  2904.                       
  2905.                       </div>
  2906.               ";
  2907.                         // line 2509
  2908.                         if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse2509) != "")) {
  2909.                             // line 2510
  2910.                             yield "              <h4 class=\"description\">";
  2911.                             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse2510), "html"nulltrue);
  2912.                             yield "</h4>
  2913.               ";
  2914.                         }
  2915.                         // line 2512
  2916.                         yield "            </div>
  2917.             ";
  2918.                     }
  2919.                     // line 2513
  2920.                     yield 
  2921.             
  2922.             ";
  2923.                 }
  2924.                 $_parent $context['_parent'];
  2925.                 unset($context['_seq'], $context['_key'], $context['attach'], $context['_parent']);
  2926.                 $context array_intersect_key($context$_parent) + $_parent;
  2927.                 // line 2516
  2928.                 yield "          </div>
  2929.           <!-- Section séparée pour les messages audio -->
  2930.           ";
  2931.                 // line 2519
  2932.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse2519) > 0)) {
  2933.                     // line 2520
  2934.                     yield "          <div class=\"audio-messages-section\" style=\"margin-top:15px; border-top: 1px solid #eee; padding: 30px;\">
  2935.             <h4 style=\"margin-bottom: 15px; color: #555\">
  2936.             
  2937.               <i class=\"bi bi-mic-fill\" style=\"margin-right: 8px; color: #ffa500\"></i>
  2938.               Messages vocaux (";
  2939.                     // line 2524
  2940.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse2524), "html"nulltrue);
  2941.                     yield ")
  2942.             </h4>
  2943.             
  2944.             ";
  2945.                     // line 2527
  2946.                     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.'2527$this->source); })()), "codeSejour", [], "any"falsefalsefalse2527), 02) == "PF")) {
  2947.                         // line 2528
  2948.                         yield "              ";
  2949.                         // line 2529
  2950.                         yield "              <div class=\"audio-messages-container\" data-type=\"audio\" style=\"display: flex; flex-wrap: wrap; gap: 15px\">
  2951.                 ";
  2952.                         // line 2530
  2953.                         $context['_parent'] = $context;
  2954.                         $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "attachments", [], "any"falsefalsefalse2530));
  2955.                         foreach ($context['_seq'] as $context["_key"] => $context["attach"]) {
  2956.                             // line 2531
  2957.                             yield "                  ";
  2958.                             if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse2531) == "message")) {
  2959.                                 // line 2532
  2960.                                 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;\">
  2961.                       <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 10px;\">
  2962.                         <i class=\"bi bi-mic-fill\" style=\"font-size: 20px; margin-right: 10px; color: #ffa500\"></i>
  2963.                         <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1\">
  2964.                           <source src=\"";
  2965.                                 // line 2536
  2966.                                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "path", [], "any"falsefalsefalse2536), "html"nulltrue);
  2967.                                 yield "\" type=\"audio/mp3\" />
  2968.                           Votre navigateur ne supporte pas la lecture audio.
  2969.                         </audio>
  2970.                       </div>
  2971.                       ";
  2972.                                 // line 2540
  2973.                                 if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse2540) != "")) {
  2974.                                     // line 2541
  2975.                                     yield "                        <div class=\"audio-description\" style=\"padding-left: 30px\">
  2976.                           <p style=\"margin: 0; font-size: 14px; color: #555; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;\">
  2977.                             ";
  2978.                                     // line 2543
  2979.                                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse2543), "html"nulltrue);
  2980.                                     yield "
  2981.                           </p>
  2982.                         </div>
  2983.                       ";
  2984.                                 }
  2985.                                 // line 2547
  2986.                                 yield "                    </div>
  2987.                   ";
  2988.                             }
  2989.                             // line 2549
  2990.                             yield "                ";
  2991.                         }
  2992.                         $_parent $context['_parent'];
  2993.                         unset($context['_seq'], $context['_key'], $context['attach'], $context['_parent']);
  2994.                         $context array_intersect_key($context$_parent) + $_parent;
  2995.                         // line 2550
  2996.                         yield "              </div>
  2997.             
  2998.             ";
  2999.                     } elseif ((((Twig\Extension\CoreExtension::slice($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source,                     // line 2552
  3000. (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'2552$this->source); })()), "codeSejour", [], "any"falsefalsefalse2552), 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.'2552$this->source); })()), "payment", [], "any"falsefalsefalse2552) == 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.'2552$this->source); })()), "codeSejour", [], "any"falsefalsefalse2552), 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.'2552$this->source); })()), "payment", [], "any"falsefalsefalse2552) == 1)))) {
  3001.                         // line 2553
  3002.                         yield "              ";
  3003.                         // line 2554
  3004.                         yield "              <div class=\"audio-messages-container\" data-type=\"audio\" style=\"display: flex; flex-wrap: wrap; gap: 15px\">
  3005.                 ";
  3006.                         // line 2555
  3007.                         $context['_parent'] = $context;
  3008.                         $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "attachments", [], "any"falsefalsefalse2555));
  3009.                         foreach ($context['_seq'] as $context["_key"] => $context["attach"]) {
  3010.                             // line 2556
  3011.                             yield "                  ";
  3012.                             if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse2556) == "message")) {
  3013.                                 // line 2557
  3014.                                 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;\">
  3015.                       <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 10px;\">
  3016.                         <i class=\"bi bi-mic-fill\" style=\"font-size: 20px; margin-right: 10px; color: #ffa500\"></i>
  3017.                         <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1\">
  3018.                           <source src=\"";
  3019.                                 // line 2561
  3020.                                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "path", [], "any"falsefalsefalse2561), "html"nulltrue);
  3021.                                 yield "\" type=\"audio/mp3\" />
  3022.                           Votre navigateur ne supporte pas la lecture audio.
  3023.                         </audio>
  3024.                       </div>
  3025.                       ";
  3026.                                 // line 2565
  3027.                                 if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse2565) != "")) {
  3028.                                     // line 2566
  3029.                                     yield "                        <div class=\"audio-description\" style=\"padding-left: 30px\">
  3030.                           <p style=\"margin: 0; font-size: 14px; color: #555; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;\">
  3031.                             ";
  3032.                                     // line 2568
  3033.                                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse2568), "html"nulltrue);
  3034.                                     yield "
  3035.                           </p>
  3036.                         </div>
  3037.                       ";
  3038.                                 }
  3039.                                 // line 2572
  3040.                                 yield "                    </div>
  3041.                   ";
  3042.                             }
  3043.                             // line 2574
  3044.                             yield "                ";
  3045.                         }
  3046.                         $_parent $context['_parent'];
  3047.                         unset($context['_seq'], $context['_key'], $context['attach'], $context['_parent']);
  3048.                         $context array_intersect_key($context$_parent) + $_parent;
  3049.                         // line 2575
  3050.                         yield "              </div>
  3051.             
  3052.             ";
  3053.                     } elseif ((((Twig\Extension\CoreExtension::slice($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source,                     // line 2577
  3054. (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'2577$this->source); })()), "codeSejour", [], "any"falsefalsefalse2577), 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.'2577$this->source); })()), "payment", [], "any"falsefalsefalse2577) == 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.'2577$this->source); })()), "codeSejour", [], "any"falsefalsefalse2577), 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.'2577$this->source); })()), "payment", [], "any"falsefalsefalse2577) == 0)))) {
  3055.                         // line 2578
  3056.                         yield "              ";
  3057.                         // line 2579
  3058.                         yield "              <div class=\"audio-messages-container\" style=\"display: flex; flex-wrap: wrap; gap: 15px; opacity: 0.5; pointer-events: none; filter: grayscale(100%);\">
  3059.                 <div class=\"audio-messages-restricted\" data-type=\"audio\" style=\"padding: 20px; background: #f0f0f0; border-radius: 8px; text-align: center; margin-bottom: 15px; width: 100%;\">
  3060.                   <i class=\"bi bi-lock-fill\" style=\"font-size: 24px; color: #808080; margin-bottom: 10px;\"></i>
  3061.                   <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>
  3062.                 </div>
  3063.                 ";
  3064.                         // line 2584
  3065.                         $context['_parent'] = $context;
  3066.                         $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "attachments", [], "any"falsefalsefalse2584));
  3067.                         foreach ($context['_seq'] as $context["_key"] => $context["attach"]) {
  3068.                             // line 2585
  3069.                             yield "                  ";
  3070.                             if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse2585) == "message")) {
  3071.                                 // line 2586
  3072.                                 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;\">
  3073.                       <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 10px;\">
  3074.                         <i class=\"bi bi-mic-fill\" style=\"font-size: 20px; margin-right: 10px; color: #ffa500\"></i>
  3075.                         <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1\" disabled>
  3076.                           <source src=\"";
  3077.                                 // line 2590
  3078.                                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "path", [], "any"falsefalsefalse2590), "html"nulltrue);
  3079.                                 yield "\" type=\"audio/mp3\" />
  3080.                           Votre navigateur ne supporte pas la lecture audio.
  3081.                         </audio>
  3082.                       </div>
  3083.                       ";
  3084.                                 // line 2594
  3085.                                 if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse2594) != "")) {
  3086.                                     // line 2595
  3087.                                     yield "                        <div class=\"audio-description\" style=\"padding-left: 30px\">
  3088.                           <p style=\"margin: 0; font-size: 14px; color: #555; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;\">
  3089.                             ";
  3090.                                     // line 2597
  3091.                                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse2597), "html"nulltrue);
  3092.                                     yield "
  3093.                           </p>
  3094.                         </div>
  3095.                       ";
  3096.                                 }
  3097.                                 // line 2601
  3098.                                 yield "                    </div>
  3099.                   ";
  3100.                             }
  3101.                             // line 2603
  3102.                             yield "                ";
  3103.                         }
  3104.                         $_parent $context['_parent'];
  3105.                         unset($context['_seq'], $context['_key'], $context['attach'], $context['_parent']);
  3106.                         $context array_intersect_key($context$_parent) + $_parent;
  3107.                         // line 2604
  3108.                         yield "              </div>
  3109.             ";
  3110.                     }
  3111.                     // line 2606
  3112.                     yield "          </div>
  3113.         ";
  3114.                 }
  3115.                 // line 2608
  3116.                 yield "        </div>
  3117.       </div>
  3118.     </div>
  3119.     ";
  3120.             }
  3121.             // line 2612
  3122.             yield "    ";
  3123.             ++$context['loop']['index0'];
  3124.             ++$context['loop']['index'];
  3125.             $context['loop']['first'] = false;
  3126.             if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) {
  3127.                 --$context['loop']['revindex0'];
  3128.                 --$context['loop']['revindex'];
  3129.                 $context['loop']['last'] = === $context['loop']['revindex0'];
  3130.             }
  3131.         }
  3132.         $_parent $context['_parent'];
  3133.         unset($context['_seq'], $context['x'], $context['groupAttach'], $context['_parent'], $context['loop']);
  3134.         $context array_intersect_key($context$_parent) + $_parent;
  3135.         // line 2613
  3136.         yield "    ";
  3137.         if ((($tmp =  !(isset($context["hasAttachments"]) || array_key_exists("hasAttachments"$context) ? $context["hasAttachments"] : (function () { throw new RuntimeError('Variable "hasAttachments" does not exist.'2613$this->source); })())) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  3138.             // line 2614
  3139.             yield "  <section class=\"stay-empty-wrapper\">
  3140.   <div class=\"stay-empty-card\">
  3141.       <h2 class=\"stay-empty-title\">Aucune photo pour le moment, c'est normal.</h2>
  3142.     <p class=\"stay-empty-intro\">
  3143.         Le séjour démarre et l'équipe est pleinement avec les enfants : installation, découverte des lieux, premiers temps de vie de groupe.<br>
  3144.         Les premières photos ou messages vocaux sont généralement publiés en fin de journée d'arrivée ou le lendemain matin.
  3145.       </p>
  3146.       <!-- Bloc \"Ce qui va arriver\" + illustration -->
  3147.       <div class=\"stay-empty-expect\">
  3148.         <div class=\"stay-empty-expect-content\">
  3149.           <p class=\"stay-empty-expect-label\">Ce qui va arriver dans les prochaines heures :</p>
  3150.       <ul class=\"stay-empty-list\">
  3151.         <li>
  3152.               <span class=\"stay-empty-list-icon stay-empty-list-icon--check\">
  3153.                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  3154.                   <polyline points=\"20 6 9 17 4 12\"/>
  3155.                 </svg>
  3156.               </span>
  3157.               <span>1 photo ou message « Bien arrivés »</span>
  3158.         </li>
  3159.         <li>
  3160.               <span class=\"stay-empty-list-icon stay-empty-list-icon--photos\">
  3161.                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  3162.                   <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/>
  3163.                   <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/>
  3164.                   <polyline points=\"21 15 16 10 5 21\"/>
  3165.                 </svg>
  3166.               </span>
  3167.               <span>Quelques photos du lieu et du groupe</span>
  3168.         </li>
  3169.         <li>
  3170.               <span class=\"stay-empty-list-icon stay-empty-list-icon--vocal\">
  3171.                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  3172.                   <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\"/>
  3173.                   <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>
  3174.                 </svg>
  3175.               </span>
  3176.               <span>Un message vocal dès que le programme le permet</span>
  3177.         </li>
  3178.       </ul>
  3179.         </div>
  3180.         <!-- Illustration compacte -->
  3181.         <div class=\"stay-empty-illustration\">
  3182.           <svg class=\"stay-empty-phone\" viewBox=\"0 0 120 200\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">
  3183.             <rect x=\"0\" y=\"0\" width=\"120\" height=\"200\" rx=\"18\" fill=\"#1A1A2E\"/>
  3184.             <rect x=\"6\" y=\"10\" width=\"108\" height=\"180\" rx=\"14\" fill=\"#fff\"/>
  3185.             <rect x=\"12\" y=\"22\" width=\"44\" height=\"44\" rx=\"8\" fill=\"#F09E7A\" opacity=\"0.2\"/>
  3186.             <rect x=\"62\" y=\"22\" width=\"46\" height=\"44\" rx=\"8\" fill=\"#41A2AA\" opacity=\"0.2\"/>
  3187.             <rect x=\"12\" y=\"72\" width=\"96\" height=\"56\" rx=\"8\" fill=\"#9B8BF4\" opacity=\"0.15\"/>
  3188.             <circle cx=\"34\" cy=\"44\" r=\"10\" fill=\"#F09E7A\"/>
  3189.             <path d=\"M29 47l4-5 3 3 4-5 5 7H29z\" fill=\"#fff\"/>
  3190.             <circle cx=\"85\" cy=\"44\" r=\"10\" fill=\"#41A2AA\"/>
  3191.             <path d=\"M82 41v6M85 38v9M88 42v4\" stroke=\"#fff\" stroke-width=\"2\" stroke-linecap=\"round\"/>
  3192.             <circle cx=\"60\" cy=\"100\" r=\"12\" fill=\"rgba(255,255,255,0.9)\"/>
  3193.             <path d=\"M56 94l10 6-10 6V94z\" fill=\"#9B8BF4\"/>
  3194.             <rect x=\"12\" y=\"138\" width=\"96\" height=\"44\" rx=\"8\" fill=\"#F8FAFB\"/>
  3195.             <circle cx=\"34\" cy=\"160\" r=\"8\" fill=\"#E5E9F0\"/>
  3196.             <circle cx=\"60\" cy=\"160\" r=\"8\" fill=\"#41A2AA\"/>
  3197.             <circle cx=\"86\" cy=\"160\" r=\"8\" fill=\"#E5E9F0\"/>
  3198.             <rect x=\"42\" y=\"4\" width=\"36\" height=\"5\" rx=\"2.5\" fill=\"#1A1A2E\"/>
  3199.           </svg>
  3200.           <div class=\"stay-empty-bubble stay-empty-bubble--arrived\">
  3201.             <span class=\"stay-empty-bubble-icon\">
  3202.               <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  3203.                 <polyline points=\"20 6 9 17 4 12\"/>
  3204.               </svg>
  3205.             </span>
  3206.             Bien arrivés !
  3207.           </div>
  3208.           <div class=\"stay-empty-bubble stay-empty-bubble--photos\">
  3209.             <span class=\"stay-empty-bubble-icon\">
  3210.               <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  3211.                 <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/>
  3212.                 <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/>
  3213.                 <polyline points=\"21 15 16 10 5 21\"/>
  3214.               </svg>
  3215.             </span>
  3216.             +12 photos
  3217.           </div>
  3218.           <span class=\"stay-empty-illustration-label\">Exemple de nouvelles à venir</span>
  3219.         </div>
  3220.       </div>
  3221.       <!-- Note rassurante -->
  3222.       <div class=\"stay-empty-reassurance\">
  3223.         <svg class=\"stay-empty-reassurance-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  3224.           <path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\"/>
  3225.         </svg>
  3226.         <p>En cas de besoin important, l'école ou l'organisateur vous contactera directement, comme d'habitude.</p>
  3227.       </div>
  3228.       <!-- CTA -->
  3229.       <div class=\"stay-empty-footer\">
  3230.         <a href=\"";
  3231.             // line 2714
  3232.             yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("ParametresParent");
  3233.             yield "\" class=\"stay-empty-cta\">
  3234.           <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  3235.             <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>
  3236.             <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>
  3237.           </svg>
  3238.           Gérer mes notifications
  3239.         </a>
  3240.     </div>
  3241.   </div>
  3242. </section>
  3243.   <div style=\"height: 200px;\"></div>
  3244.     ";
  3245.         }
  3246.         // line 2727
  3247.         yield "    
  3248.     <!-- JavaScript pour les pills et la gestion du nouveau contenu -->
  3249.     <script>
  3250.       document.addEventListener('DOMContentLoaded', function() {
  3251.         // Valider les liens de produits au chargement
  3252.         setTimeout(() => {
  3253.           if (typeof window.validateProductLinks === 'function') {
  3254.             window.validateProductLinks();
  3255.           }
  3256.         }, 1000);
  3257.         
  3258.         // ⚡ OPTIMISATION: Event delegation avec throttling pour éviter les clics multiples
  3259.         let clickThrottleTimeout = null;
  3260.         document.addEventListener('click', function(e) {
  3261.           // Throttling pour éviter les clics multiples rapides
  3262.           if (clickThrottleTimeout) return;
  3263.           
  3264.           const pill = e.target.closest('.stat-pill');
  3265.           if (pill) {
  3266.             clickThrottleTimeout = setTimeout(() => {
  3267.               clickThrottleTimeout = null;
  3268.             }, 100);
  3269.             
  3270.             // ⚡ OPTIMISÉ: Une seule boucle pour gérer les états actifs
  3271.             const statPills = document.querySelectorAll('.stat-pill');
  3272.             for (let i = 0; i < statPills.length; i++) {
  3273.               const p = statPills[i];
  3274.               if (p && p.classList) {
  3275.                 if (p === pill) {
  3276.                   p.classList.add('active');
  3277.                 } else {
  3278.                   p.classList.remove('active');
  3279.                 }
  3280.               }
  3281.             }
  3282.             
  3283.             // Déclencher le filtrage du contenu
  3284.             const filter = pill.getAttribute('data-filter');
  3285.             if (typeof window.filterContent === 'function') {
  3286.               window.filterContent(filter);
  3287.             }
  3288.           }
  3289.         });
  3290.         // Fonction de filtrage du contenu - globale
  3291.         window.filterContent = function(filter) {
  3292.           // ⚡ OPTIMISÉ: Suppression des console.log en production
  3293.           if (window.location.hostname === 'localhost' || window.location.hostname.includes('dev')) {
  3294.             console.log('Filtrage par:', filter);
  3295.           }
  3296.           
  3297.           const dateNavigation = document.querySelector('.date-navigation');
  3298.           const sectionDays = document.querySelector('.section-days');
  3299.           
  3300.           if (filter === 'favoris') {
  3301.             // Afficher la vue des favoris
  3302.             showFavoritesView();
  3303.           } else if (filter === 'audio') {
  3304.             // Afficher la vue des messages audio
  3305.             showAudiosView();
  3306.           } else if (filter === 'photos') {
  3307.             // Ouvrir le carrousel du jour actif ou du dernier jour
  3308.             openCurrentDayCarousel();
  3309.           } else {
  3310.             // Restaurer la vue normale des jours
  3311.             showDaysView();
  3312.           }
  3313.         }
  3314.         // Fonction pour afficher la vue des favoris - globale
  3315.         window.showFavoritesView = function() {
  3316.           const sectionDays = document.querySelector('.section-days');
  3317.           const containerGallery = document.querySelector('.container--gallery');
  3318.           
  3319.           // Masquer le container gallery
  3320.           if (containerGallery) {
  3321.             containerGallery.style.display = 'none';
  3322.           }
  3323.           
  3324.           // Mettre à jour l'état des boutons
  3325.           updatePhotosButtonState('favorites');
  3326.           updateAudioButtonState('favorites');
  3327.           updateFavoritesButtonState('favorites');
  3328.           
  3329.           const favoriteCount = getCurrentFavoriteCount();
  3330.           
  3331.           // sla vue des favoris avec e-commerce
  3332.           const favoritesHTML = `
  3333.             <div class=\"favorites-ecommerce-view\">
  3334.               <!-- Header avec progression -->
  3335.               <div class=\"favorites-header\">
  3336.                 <div class=\"favorites-title\">
  3337.                   <h3>Vos souvenirs sélectionnés</h3>
  3338.                   <span class=\"favorites-count\" id=\"favorites-count\">\${favoriteCount} photos</span>
  3339.                 </div>
  3340.                 <button class=\"btn-back-to-days\" onclick=\"window.showDaysView()\">
  3341.                   <i class=\"bi bi-arrow-left\"></i>
  3342.                   Retour aux jours
  3343.                 </button>
  3344.               </div>
  3345.             
  3346.               <!-- Grille des favoris -->
  3347.               <div class=\"favorites-content\">
  3348.                 <div class=\"favorites-grid\" id=\"favoritesGrid\">
  3349.                   \${generateFavoritesGrid()}
  3350.                 </div>
  3351.                 
  3352.                 <!-- CTA discret et premium pour rediriger vers la boutique -->
  3353.                 <a href=\"";
  3354.         // line 2837
  3355.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("boutique5sur5");
  3356.         yield "\" class=\"premium-cta-subtle\" style=\"margin: 20px 0; padding: 16px 20px; background: rgba(65, 162, 170, 0.04); border: 1px solid rgba(65, 162, 170, 0.15); border-radius: 12px; cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; justify-content: space-between; gap: 12px; text-decoration: none;\">
  3357.                   <div style=\"display: flex; align-items: center; gap: 12px; flex: 1;\">
  3358.                     <div style=\"width: 40px; height: 40px; background: rgba(65, 162, 170, 0.1); border-radius: 10px; display: flex; align-items: center; justify-content: center; flex-shrink: 0;\">
  3359.                       <i class=\"bi bi-gift\" style=\"font-size: 18px; color: #41A2AA;\"></i>
  3360.                     </div>
  3361.                     <div style=\"flex: 1; min-width: 0;\">
  3362.                       <p style=\"margin: 0; font-size: 14px; font-weight: 600; color: #1a1a1a; line-height: 1.4;\">Créer des souvenirs avec vos \${favoriteCount} photos</p>
  3363.                       <p style=\"margin: 4px 0 0 0; font-size: 12px; color: #6b7280; line-height: 1.4;\">Albums, tirages et livres personnalisés</p>
  3364.                     </div>
  3365.                   </div>
  3366.                   <i class=\"bi bi-chevron-right\" style=\"font-size: 18px; color: #41A2AA; flex-shrink: 0;\"></i>
  3367.                 </a>
  3368.               </div>
  3369.             </div>
  3370.           `;
  3371.           
  3372.           sectionDays.innerHTML = favoritesHTML;
  3373.         }
  3374.         // Fonction pour afficher la vue des messages audio - globale
  3375.         window.showAudiosView = function() {
  3376.           const sectionDays = document.querySelector('.section-days');
  3377.           const containerGallery = document.querySelector('.container--gallery');
  3378.           
  3379.           // Masquer le container gallery
  3380.           if (containerGallery) {
  3381.             containerGallery.style.display = 'none';
  3382.           }
  3383.           
  3384.           // Mettre à jour l'état des boutons
  3385.           updatePhotosButtonState('audios');
  3386.           updateAudioButtonState('audios');
  3387.           updateFavoritesButtonState('audios');
  3388.           
  3389.           // Collecter tous les messages audio de tous les jours
  3390.           const allAudioMessages = [];
  3391.           const audioItems = document.querySelectorAll('.audio-message-item[data-type=\"audio\"]');
  3392.           
  3393.           audioItems.forEach(item => {
  3394.             const audio = item.querySelector('audio source');
  3395.             const description = item.querySelector('.audio-description p');
  3396.             const dayContainer = item.closest('[id^=\"demP\"]');
  3397.             let dayTitle = 'Jour inconnu';
  3398.             
  3399.             if (dayContainer) {
  3400.               // Trouver le titre du jour
  3401.               const dayIndex = dayContainer.id.replace('demP', '');
  3402.               const dayCard = document.querySelector(`[data-target=\"#demP\${dayIndex}\"]`);
  3403.               if (dayCard) {
  3404.                 dayTitle = dayCard.textContent.trim();
  3405.               } else {
  3406.                 // Essayer de trouver dans les cartes de date
  3407.                 const dateCard = document.querySelector(`.date-card[data-bs-target=\"#demP\${dayIndex}\"], .date-card[data-target=\"#demP\${dayIndex}\"]`);
  3408.                 if (dateCard) {
  3409.                   const dateText = dateCard.querySelector('.date-text, .card-title, h5, .title-line');
  3410.                   if (dateText) {
  3411.                     dayTitle = dateText.textContent.trim();
  3412.                   }
  3413.                 }
  3414.               }
  3415.             }
  3416.             
  3417.             if (audio) {
  3418.               allAudioMessages.push({
  3419.                 src: audio.src,
  3420.                 description: description ? description.textContent.trim() : '',
  3421.                 day: dayTitle,
  3422.                 isRestricted: item.closest('.audio-messages-container[style*=\"opacity: 0.5\"]') !== null
  3423.               });
  3424.             }
  3425.           });
  3426.           
  3427.           // Créer la vue des messages audio
  3428.           const audiosHTML = `
  3429.             <div class=\"audios-view\">
  3430.               <!-- Header -->
  3431.               <div class=\"audios-header\" style=\"display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding: 20px; background: #f8f9fa; border-radius: 10px;\">
  3432.                 <div class=\"audios-title\">
  3433.                   <h3><span class=\"icon-telephone-voicemail\">
  3434.   <i class=\"bi bi-telephone-fill tel\"  style=\"color: #ffd700;font-size:1.5em\"></i>
  3435.   <i class=\"bi bi-voicemail vm\" style=\"color: #ffd700;font-size: 0.9rem;
  3436.     transform: translate(-40%, -46%);\"></i>
  3437. </span>
  3438.                   <span class=\"audios-count\">\${allAudioMessages.length} messages</span>
  3439.                 </div>
  3440.                 <button class=\"btn-back-to-days\" onclick=\"window.showDaysView()\" style=\"background: #6c757d; color: white; border: none; padding: 8px 16px; border-radius: 5px; cursor: pointer;\">
  3441.                   <i class=\"bi bi-arrow-left\"></i>
  3442.                   Retour aux jours
  3443.                 </button>
  3444.               </div>
  3445.               <!-- Grille des messages audio -->
  3446.               <div class=\"audios-content\" style=\"display: flex; flex-wrap: wrap; gap: 20px;\">
  3447.                 \${allAudioMessages.map(msg => `
  3448.                   <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%);' : ''}\">
  3449.                     \${msg.day && msg.day !== 'Jour inconnu' ? `
  3450.                       <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;\">
  3451.                         \${msg.day}
  3452.                       </div>
  3453.                     ` : ''}
  3454.                     <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 12px;\">
  3455.                       <i class=\"bi bi-mic-fill\" style=\"font-size: 24px; margin-right: 15px; color: #ffa500;\"></i>
  3456.                       <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1; border-radius: 5px;\" \${msg.isRestricted ? 'disabled' : ''}>
  3457.                         <source src=\"\${msg.src}\" type=\"audio/mp3\" />
  3458.                         Votre navigateur ne supporte pas la lecture audio.
  3459.                       </audio>
  3460.                     </div>
  3461.                     \${msg.description ? `
  3462.                       <div class=\"audio-description\" style=\"padding-left: 39px;\">
  3463.                         <p style=\"margin: 0; font-size: 14px; color: #666; line-height: 1.4;\">\${msg.description}</p>
  3464.                       </div>
  3465.                     ` : ''}
  3466.                     \${msg.isRestricted ? `
  3467.                       <div class=\"audio-restricted-notice\" style=\"text-align: center; margin-top: 10px; padding: 8px; background: #fff3cd; border-radius: 5px; border: 1px solid #ffeaa7;\">
  3468.                         <i class=\"bi bi-lock-fill\" style=\"color: #856404; margin-right: 5px;\"></i>
  3469.                         <small style=\"color: #856404;\">Accès premium requis</small>
  3470.                       </div>
  3471.                     ` : ''}
  3472.                   </div>
  3473.                 `).join('')}
  3474.               </div>
  3475.               
  3476.               \${allAudioMessages.length === 0 ? `
  3477.                 <div class=\"no-audios\" style=\"text-align: center; padding: 60px 20px; color: #6c757d;\">
  3478.                   <i class=\"bi bi-mic\" style=\"font-size: 4rem; margin-bottom: 20px; opacity: 0.3;\"></i>
  3479.                   <h4>Aucun message vocal</h4>
  3480.                   <p>Il n'y a pas encore de messages vocaux dans ce séjour.</p>
  3481.                 </div>
  3482.               ` : ''}
  3483.             </div>
  3484.           `;
  3485.           
  3486.           sectionDays.innerHTML = audiosHTML;
  3487.         }
  3488.         
  3489.         // Variables pour sauvegarder le contenu original
  3490.         let originalDaysContent = null;
  3491.         
  3492.         // Sauvegarder le contenu original au chargement
  3493.         document.addEventListener('DOMContentLoaded', function() {
  3494.           setTimeout(() => {
  3495.             const containerGallery = document.querySelector('.container--gallery');
  3496.             if (containerGallery) {
  3497.               originalDaysContent = containerGallery.outerHTML;
  3498.             }
  3499.           }, 1000);
  3500.         });
  3501.         
  3502.       
  3503.         // Fonction pour ouvrir le carrousel contextuel - globale
  3504.         window.openCurrentDayCarousel = function() {
  3505.           // Détecter la vue active
  3506.           const currentView = detectCurrentView();
  3507.           
  3508.           switch (currentView) {
  3509.             case 'favorites':
  3510.               openFavoritesCarousel();
  3511.               break;
  3512.             case 'audios':
  3513.               // Dans la vue audios, pas de carrousel photos pertinent
  3514.               console.log('Carrousel photos non disponible dans la vue audios');
  3515.               return;
  3516.             case 'days':
  3517.             default:
  3518.               openActiveDayCarousel();
  3519.               break;
  3520.           }
  3521.         }
  3522.         
  3523.         // Fonction pour mettre à jour l'état du bouton photos selon le contexte
  3524.         function updatePhotosButtonState(currentView) {
  3525.           const photosBtn = document.querySelector('.mtb-btn[data-filter=\"photos\"]');
  3526.           if (!photosBtn) return;
  3527.           
  3528.           const btnIcon = photosBtn.querySelector('i');
  3529.           const btnCount = photosBtn.querySelector('.mtb-count');
  3530.           
  3531.           switch (currentView) {
  3532.             case 'favorites':
  3533.               // Dans les favoris : bouton actif, ouvre le carrousel des favoris
  3534.               photosBtn.style.opacity = '1';
  3535.               photosBtn.style.pointerEvents = 'auto';
  3536.               photosBtn.title = 'Voir le carrousel des favoris';
  3537.               if (btnIcon) btnIcon.style.color = '#007bff';
  3538.               if (btnCount) btnCount.style.display = 'none'; // Cacher le compteur
  3539.               break;
  3540.               
  3541.             case 'audios':
  3542.               // Dans les audios : bouton désactivé
  3543.               photosBtn.style.opacity = '0.4';
  3544.               photosBtn.style.pointerEvents = 'none';
  3545.               photosBtn.title = 'Carrousel non disponible dans la vue audios';
  3546.               if (btnIcon) btnIcon.style.color = '#6c757d';
  3547.               if (btnCount) btnCount.style.display = 'none';
  3548.               break;
  3549.               
  3550.             case 'days':
  3551.             default:
  3552.               // Vue normale : utiliser la logique existante du carrousel
  3553.               photosBtn.style.opacity = '1';
  3554.               photosBtn.style.pointerEvents = 'auto';
  3555.               photosBtn.title = 'Voir les photos du jour actif';
  3556.               if (btnIcon) btnIcon.style.color = '';
  3557.               if (btnCount) btnCount.style.display = 'none'; // Cacher le compteur pour éviter la confusion
  3558.               break;
  3559.           }
  3560.         }
  3561.         
  3562.         // Fonction pour mettre à jour l'état du bouton audio selon le contexte
  3563.         window.updateAudioButtonState = function updateAudioButtonState(currentView) {
  3564.           const audioBtn = document.querySelector('.mtb-btn[data-filter=\"audio\"]');
  3565.           if (!audioBtn) return;
  3566.           
  3567.           const btnCount = audioBtn.querySelector('.mtb-count');
  3568.           
  3569.           switch (currentView) {
  3570.             case 'favorites':
  3571.               // Dans les favoris : pas d'action sur le compteur audio
  3572.               break;
  3573.               
  3574.             case 'audios':
  3575.               // Dans les audios : afficher le nombre total calculé par le frontend
  3576.               const totalAudioCount = document.querySelectorAll('.audio-message-item[data-type=\"audio\"]').length;
  3577.               if (btnCount) {
  3578.                 btnCount.textContent = totalAudioCount;
  3579.               }
  3580.               break;
  3581.               
  3582.             case 'days':
  3583.             default:
  3584.               // Vue normale : compter les audios du jour actif
  3585.               const activeDayAudioCount = countActiveDayAudios();
  3586.               if (btnCount) {
  3587.                 btnCount.textContent = activeDayAudioCount;
  3588.               }
  3589.               break;
  3590.           }
  3591.         }
  3592.         
  3593.         // Fonction pour mettre à jour l'état du bouton favoris selon le contexte
  3594.         window.updateFavoritesButtonState = function updateFavoritesButtonState(currentView) {
  3595.           const favoritesBtn = document.querySelector('.mtb-btn[data-filter=\"favoris\"]');
  3596.           if (!favoritesBtn) return;
  3597.           
  3598.           const btnIcon = favoritesBtn.querySelector('i');
  3599.           const btnCount = favoritesBtn.querySelector('.mtb-count');
  3600.           
  3601.           // ✅ IMPORTANT : Le bouton favoris reste TOUJOURS accessible, peu importe la vue
  3602.           switch (currentView) {
  3603.             case 'favorites':
  3604.               // Dans les favoris : bouton actif marqué visuellement
  3605.               favoritesBtn.style.opacity = '1';
  3606.               favoritesBtn.style.pointerEvents = 'auto';
  3607.               favoritesBtn.title = 'Vous êtes dans la vue favoris';
  3608.               if (btnIcon) btnIcon.style.color = '#f56040';
  3609.               if (btnCount) btnCount.style.display = 'inline';
  3610.               favoritesBtn.classList.add('active');
  3611.               break;
  3612.               
  3613.             case 'audios':
  3614.               // Dans les audios : bouton reste actif et accessible ✅
  3615.               favoritesBtn.style.opacity = '1';
  3616.               favoritesBtn.style.pointerEvents = 'auto';
  3617.               favoritesBtn.title = 'Voir les favoris';
  3618.               if (btnIcon) btnIcon.style.color = '#f56040';
  3619.               if (btnCount) btnCount.style.display = 'inline';
  3620.               favoritesBtn.classList.remove('active');
  3621.               break;
  3622.               
  3623.             case 'days':
  3624.             default:
  3625.               // Vue normale : bouton normal et accessible
  3626.               favoritesBtn.style.opacity = '1';
  3627.               favoritesBtn.style.pointerEvents = 'auto';
  3628.               favoritesBtn.title = 'Voir les favoris';
  3629.               if (btnIcon) btnIcon.style.color = '#f56040';
  3630.               if (btnCount) btnCount.style.display = 'inline';
  3631.               favoritesBtn.classList.remove('active');
  3632.               break;
  3633.           }
  3634.         }
  3635.         
  3636.         // Fonction pour compter les audios du jour actif (réutilise la même logique)
  3637.         // ⚡ OPTIMISÉ: Cache des éléments DOM pour éviter les requêtes répétitives
  3638.         let cachedActiveDay = null;
  3639.         let cachedAudioCount = 0;
  3640.         let lastCacheTime = 0;
  3641.         const CACHE_DURATION = 1000; // 1 seconde
  3642.         
  3643.         function countActiveDayAudios() {
  3644.           const now = Date.now();
  3645.           
  3646.           // Utiliser le cache si récent
  3647.           if (cachedActiveDay && (now - lastCacheTime) < CACHE_DURATION) {
  3648.             return cachedAudioCount;
  3649.           }
  3650.           
  3651.           // Trouver le jour actuellement ouvert
  3652.           let activeDay = document.querySelector('.collapse.show[id^=\"demP\"]');
  3653.           
  3654.           // Si aucun jour ouvert, prendre le dernier jour
  3655.           if (!activeDay) {
  3656.             const allDays = document.querySelectorAll('.collapse[id^=\"demP\"]');
  3657.             activeDay = allDays[allDays.length - 1];
  3658.           }
  3659.           
  3660.           if (!activeDay) {
  3661.             cachedActiveDay = null;
  3662.             cachedAudioCount = 0;
  3663.             lastCacheTime = now;
  3664.             return 0;
  3665.           }
  3666.           
  3667.           // Compter les messages audio dans ce jour
  3668.           const audiosInDay = activeDay.querySelectorAll('.audio-message-item[data-type=\"audio\"]');
  3669.           const count = audiosInDay.length;
  3670.           
  3671.           // Mettre à jour le cache
  3672.           cachedActiveDay = activeDay;
  3673.           cachedAudioCount = count;
  3674.           lastCacheTime = now;
  3675.           
  3676.           return count;
  3677.         }
  3678.         
  3679.         // Fonction pour détecter la vue active
  3680.         // ⚡ OPTIMISÉ: Cache de la vue active pour éviter les requêtes DOM répétitives
  3681.         let cachedCurrentView = null;
  3682.         let lastViewCheck = 0;
  3683.         const VIEW_CACHE_DURATION = 500; // 500ms
  3684.         
  3685.         function detectCurrentView() {
  3686.           const now = Date.now();
  3687.           
  3688.           // Utiliser le cache si récent
  3689.           if (cachedCurrentView && (now - lastViewCheck) < VIEW_CACHE_DURATION) {
  3690.             return cachedCurrentView;
  3691.           }
  3692.           
  3693.           let view = 'days';
  3694.           if (document.querySelector('.favorites-ecommerce-view')) {
  3695.             view = 'favorites';
  3696.           } else if (document.querySelector('.audios-view')) {
  3697.             view = 'audios';
  3698.           }
  3699.           
  3700.           // Mettre à jour le cache
  3701.           cachedCurrentView = view;
  3702.           lastViewCheck = now;
  3703.           
  3704.           return view;
  3705.         }
  3706.         
  3707.         // ⚡ OPTIMISÉ: Cache global des éléments DOM fréquemment utilisés
  3708.         const domCache = {
  3709.           favoritesGrid: null,
  3710.           lastFavoritesUpdate: 0,
  3711.           CACHE_DURATION: 2000 // 2 secondes
  3712.         };
  3713.         
  3714.         function getCachedFavorites() {
  3715.           const now = Date.now();
  3716.           if (!domCache.favoritesGrid || (now - domCache.lastFavoritesUpdate) > domCache.CACHE_DURATION) {
  3717.             domCache.favoritesGrid = document.querySelector('.favorites-grid');
  3718.             domCache.lastFavoritesUpdate = now;
  3719.           }
  3720.           return domCache.favoritesGrid;
  3721.         }
  3722.         
  3723.         // Fonction pour ouvrir le carrousel des favoris
  3724.         function openFavoritesCarousel() {
  3725.           const favoritesGrid = getCachedFavorites();
  3726.           const favoriteItems = favoritesGrid ? favoritesGrid.querySelectorAll('.favorite-item') : [];
  3727.           if (favoriteItems.length > 0) {
  3728.             // Trouver le premier favori avec une action de vue
  3729.             const firstFavorite = favoriteItems[0];
  3730.             const viewBtn = firstFavorite.querySelector('.btn-view-favorite');
  3731.             if (viewBtn && viewBtn.onclick) {
  3732.               viewBtn.click();
  3733.             } else {
  3734.               // Fallback : extraire l'ID du data-id et utiliser viewImage
  3735.               const favoriteId = firstFavorite.dataset.id;
  3736.               if (favoriteId && typeof window.viewImage === 'function') {
  3737.                 window.viewImage(favoriteId, firstFavorite);
  3738.               }
  3739.             }
  3740.           } else {
  3741.             console.log('Aucun favori trouvé pour ouvrir le carrousel');
  3742.           }
  3743.         }
  3744.         
  3745.         // Fonction pour ouvrir le carrousel du jour actif
  3746.         function openActiveDayCarousel() {
  3747.           // Trouver le jour actuellement ouvert (avec classe 'show')
  3748.           let activeDay = document.querySelector('.collapse.show[id^=\"demP\"]');
  3749.           
  3750.           // Si aucun jour n'est ouvert, prendre le dernier jour
  3751.           if (!activeDay) {
  3752.             const allDays = document.querySelectorAll('.collapse[id^=\"demP\"]');
  3753.             activeDay = allDays[allDays.length - 1]; // Dernier jour
  3754.           }
  3755.           
  3756.           if (!activeDay) {
  3757.             console.warn('Aucun jour trouvé pour ouvrir le carrousel');
  3758.             return;
  3759.           }
  3760.           
  3761.           // Trouver la première photo de ce jour
  3762.           const viewIcon = activeDay.querySelector('.view-icon[onclick*=\"viewImage\"]');
  3763.           if (viewIcon) {
  3764.             // Extraire l'ID de la photo du onclick
  3765.             const onclickAttr = viewIcon.getAttribute('onclick');
  3766.             const match = onclickAttr.match(/viewImage\\('(\\d+)'/);
  3767.             if (match) {
  3768.               const imageId = match[1];
  3769.               // Ouvrir le slider avec cette image
  3770.               if (typeof window.viewImage === 'function') {
  3771.                 window.viewImage(imageId, viewIcon);
  3772.               }
  3773.             }
  3774.           } else {
  3775.             // Fallback : chercher dans tous les jours
  3776.             const allDays = document.querySelectorAll('.collapse[id^=\"demP\"]');
  3777.             for (let day of allDays) {
  3778.               const photoInDay = day.querySelector('.view-icon[onclick*=\"viewImage\"]');
  3779.               if (photoInDay) {
  3780.                 photoInDay.click();
  3781.                 break;
  3782.               }
  3783.             }
  3784.           }
  3785.         }
  3786.         // Fonction pour afficher la vue normale des jours - globale
  3787.         window.showDaysView = function() {
  3788.           const sectionDays = document.querySelector('.section-days');
  3789.           const containerGallery = document.querySelector('.container--gallery');
  3790.           
  3791.           // Si la section days contient des vues spéciales (favoris/audios), les supprimer
  3792.           if (sectionDays && (sectionDays.innerHTML.includes('favorites-ecommerce-view') || sectionDays.innerHTML.includes('audios-view'))) {
  3793.             // Restaurer le contenu original si disponible
  3794.             if (originalDaysContent) {
  3795.               sectionDays.innerHTML = originalDaysContent;
  3796.             } else {
  3797.               // Fallback : recharger la page si pas de sauvegarde
  3798.               location.reload();
  3799.               return;
  3800.             }
  3801.           }
  3802.           
  3803.           // Restaurer la visibilité du container gallery
  3804.           if (containerGallery) {
  3805.             containerGallery.style.display = 'block';
  3806.           }
  3807.           
  3808.           // Appeler le filtre \"all\" pour restaurer l'affichage complet
  3809.           if (typeof window.filterContent === 'function') {
  3810.             window.filterContent('toutVoir');
  3811.           }
  3812.           
  3813.           // Mettre à jour l'état des boutons
  3814.           updatePhotosButtonState('days');
  3815.           updateAudioButtonState('days');
  3816.           updateFavoritesButtonState('days');
  3817.         }
  3818.         // Fonction pour générer les cartes de jours (alternative simple)
  3819.         function generateDaysCards() {
  3820.           // Cette fonction pourrait régénérer les cartes, mais pour simplifier
  3821.           // on recharge la page dans showDaysView()
  3822.           return '';
  3823.         }
  3824.         // Fonction pour revenir à la vue des jours
  3825.      
  3826.         // Fonction pour générer la grille des favoris
  3827.         function generateFavoritesGrid() {
  3828.           const favorites = getFavoriteItems();
  3829.           
  3830.           if (favorites.length === 0) {
  3831.             return `
  3832.               <div class=\"no-favorites\">
  3833.                 <i class=\"bi bi-heart\" style=\"font-size: 3rem; color: #ccc; margin-bottom: 1rem;\"></i>
  3834.                 <h4>Aucun favori sélectionné</h4>
  3835.                 <p>Cliquez sur <i class=\"bi bi-heart\" style=\"color: #e91e63;\"></i> sur vos photos préférées pour les ajouter ici.</p>
  3836.               </div>
  3837.             `;
  3838.           }
  3839.           
  3840.           return favorites.map(item => `
  3841.             <div class=\"favorite-item photo-item\" data-id=\"\${item.id}\" style=\"position: relative; width: 100%; aspect-ratio: 1; border-radius: 12px; overflow: hidden; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); background: #f0f0f0;\">
  3842.               \${item.type === 'image' ? 
  3843.                 `<img src=\"\${item.url}\" alt=\"Photo favorite\" loading=\"lazy\" style=\"width: 100%; height: 100%; object-fit: cover; display: block;\">` :
  3844.                 item.type === 'video' ? 
  3845.                 `<video src=\"\${item.url}\" poster=\"\${item.thumbnail}\" style=\"width: 100%; height: 100%; object-fit: cover; display: block;\"></video>
  3846.                  <div class=\"video-overlay\" style=\"position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; background: rgba(0,0,0,0.3);\"><i class=\"bi bi-play-circle\" style=\"font-size: 48px; color: white;\"></i></div>` :
  3847.                 `<div class=\"audio-item\" style=\"width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; background: linear-gradient(135deg, rgba(65, 162, 170, 0.1) 0%, rgba(245, 96, 64, 0.1) 100%);\">
  3848.                    <i class=\"bi bi-mic-fill\" style=\"font-size: 32px; color: #41A2AA; margin-bottom: 8px;\"></i>
  3849.                    <span style=\"font-size: 14px; color: #6b7280; font-weight: 600;\">Audio \${item.duration || '00:00'}</span>
  3850.                  </div>`
  3851.               }
  3852.               <!-- Actions overlay -->
  3853.               <div class=\"favorite-actions\" style=\"position: absolute; top: 8px; right: 8px; display: flex; gap: 6px; opacity: 0; transition: opacity 0.3s ease;\">
  3854.                 <button class=\"btn-view-favorite\" onclick=\"viewFavorite('\${item.id}')\" title=\"Voir en grand\" style=\"width: 32px; height: 32px; border-radius: 8px; background: rgba(255,255,255,0.9); border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.1);\">
  3855.                   <i class=\"bi bi-eye\" style=\"font-size: 14px; color: #41A2AA;\"></i>
  3856.                 </button>
  3857.                 <button class=\"btn-remove-favorite\" onclick=\"removeFavorite('\${item.id}')\" title=\"Retirer des favoris\" style=\"width: 32px; height: 32px; border-radius: 8px; background: rgba(255,255,255,0.9); border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.1);\">
  3858.                   <i class=\"bi bi-heart-fill\" style=\"font-size: 14px; color: #f56040;\"></i>
  3859.                 </button>
  3860.               </div>
  3861.             </div>
  3862.           `).join('');
  3863.         }
  3864.         // Fonction pour réorganiser la grille des favoris
  3865.         function reorganizeFavoritesGrid() {
  3866.           const favoritesGrid = document.getElementById('favoritesGrid');
  3867.           if (!favoritesGrid) return;
  3868.           
  3869.           const remainingItems = favoritesGrid.querySelectorAll('.favorite-item');
  3870.           if (remainingItems.length === 0) {
  3871.             // Afficher le message \"Aucun favori\"
  3872.             favoritesGrid.innerHTML = `
  3873.               <div class=\"no-favorites\">
  3874.                 <i class=\"bi bi-heart\" style=\"font-size: 3rem; color: #ccc; margin-bottom: 1rem;\"></i>
  3875.                 <h4>Aucun favori sélectionné</h4>
  3876.                 <p>Cliquez sur <i class=\"bi bi-heart\" style=\"color: #e91e63;\"></i> sur vos photos préférées pour les ajouter ici.</p>
  3877.               </div>
  3878.             `;
  3879.           } else {
  3880.             // Réorganiser les éléments restants avec une animation douce
  3881.             remainingItems.forEach((item, index) => {
  3882.               item.style.transition = 'all 0.3s ease';
  3883.               item.style.order = index;
  3884.             });
  3885.           }
  3886.         }
  3887.         // Fonction pour récupérer les éléments favoris
  3888.         function getFavoriteItems() {
  3889.           const favorites = [];
  3890.           
  3891.           // ⚡ OPTIMISÉ: Cache et parcours plus efficace des favoris
  3892.           const heartIcons = document.querySelectorAll('.heart-icon');
  3893.           for (let i = 0; i < heartIcons.length; i++) {
  3894.             const heartIcon = heartIcons[i];
  3895.             const heartFill = heartIcon.querySelector('.bi-heart-fill');
  3896.             if (heartFill) {
  3897.               const id = heartIcon.getAttribute('data-id');
  3898.               const path = heartIcon.getAttribute('data-path');
  3899.               const description = heartIcon.getAttribute('data-description');
  3900.               
  3901.               if (id && path) {
  3902.                 // Déterminer le type de média
  3903.                 let type = 'image';
  3904.                 let url = path;
  3905.                 let thumbnail = path;
  3906.                 
  3907.                 if (path.includes('.mp4') || path.includes('.mov') || path.includes('.avi')) {
  3908.                   type = 'video';
  3909.                   thumbnail = path.replace(/\\.(mp4|mov|avi)\$/i, '_thumb.jpg');
  3910.                 } else if (path.includes('.mp3') || path.includes('.wav') || path.includes('.m4a')) {
  3911.                   type = 'audio';
  3912.                   url = path;
  3913.                 }
  3914.                 
  3915.                 // Récupérer la date depuis le conteneur parent
  3916.                 const dateCard = heartIcon.closest('[id^=\"demP\"]');
  3917.                 let date = 'Date inconnue';
  3918.                 if (dateCard) {
  3919.                   const dateElement = dateCard.querySelector('.full-date, .day-title');
  3920.                   if (dateElement) {
  3921.                     date = dateElement.textContent.trim();
  3922.                   }
  3923.                 }
  3924.                 
  3925.                 favorites.push({
  3926.                   id: id,
  3927.                   url: url,
  3928.                   thumbnail: thumbnail,
  3929.                   type: type,
  3930.                   date: date,
  3931.                   description: description || ''
  3932.                 });
  3933.               }
  3934.             }
  3935.           }
  3936.           
  3937.           // ⚡ OPTIMISÉ: Log conditionnel pour réduire l'impact performance
  3938.           if (favorites.length > 0) {
  3939.             console.log('Favoris trouvés:', favorites.length);
  3940.           }
  3941.           return favorites;
  3942.         }
  3943.         // Rendre les fonctions accessibles globalement
  3944.         window.viewFavorite = viewFavorite;
  3945.         window.removeFavorite = removeFavorite;
  3946.         window.getFavoriteItems = getFavoriteItems;
  3947.         // Fonction pour supprimer un favori
  3948.         function removeFavorite(id) {
  3949.          
  3950.           const heartIcon = document.querySelector(`[data-id=\"\${id}\"]`);
  3951.          
  3952.           if (heartIcon) {
  3953.             const heartFill = heartIcon.querySelector('.bi-heart-fill');
  3954.             if (heartFill && heartFill.classList) {
  3955.               heartFill.classList.remove('bi-heart-fill');
  3956.               heartFill.classList.add('bi-heart');
  3957.               heartFill.style.color = '';
  3958.             }
  3959.           }
  3960.           const favoriteItem = document.querySelector(`.favorite-item[data-id=\"\${id}\"]`);
  3961.         
  3962.           if (favoriteItem) {
  3963.             // Animation de disparition puis suppression complète
  3964.             favoriteItem.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
  3965.             favoriteItem.style.opacity = '0';
  3966.             favoriteItem.style.transform = 'scale(0.8)';
  3967.             
  3968.             setTimeout(() => {
  3969.               favoriteItem.remove();
  3970.               
  3971.               // Appeler la fonction métier si présente
  3972.               const heartIcon = document.querySelector(`#coeur\${id}`);
  3973.               const sejourId = heartIcon && heartIcon.dataset.sejourId ? heartIcon.dataset.sejourId : '';
  3974.               supprimerFavoris(id, sejourId);
  3975.               
  3976.               // Mettre à jour les compteurs
  3977.               updateAllFavoriteCounters();
  3978.               
  3979.               // Réorganiser la grille si nécessaire
  3980.               reorganizeFavoritesGrid();
  3981.             }, 300);
  3982.       
  3983.      
  3984.    
  3985.   }
  3986.           
  3987.         }
  3988.         // Slider plein écran pour les favoris
  3989.         class FavoritesSlider {
  3990.           constructor() {
  3991.             this.currentIndex = 0;
  3992.             this.favorites = [];
  3993.             this.isOpen = false;
  3994.             this.touchStartX = 0;
  3995.             this.touchEndX = 0;
  3996.           }
  3997.           open(favoriteId) {
  3998.             console.log('Ouverture du slider pour:', favoriteId);
  3999.             
  4000.             // Récupérer tous les favoris images
  4001.             this.favorites = getFavoriteItems().filter(item => item.type === 'image');
  4002.             
  4003.             if (this.favorites.length === 0) {
  4004.               console.error('Aucun favori image trouvé');
  4005.               return;
  4006.             }
  4007.             // Trouver l'index de l'image courante
  4008.             this.currentIndex = this.favorites.findIndex(fav => fav.id === favoriteId);
  4009.             if (this.currentIndex === -1) this.currentIndex = 0;
  4010.             console.log('Index courant:', this.currentIndex, 'Total:', this.favorites.length);
  4011.             this.createSlider();
  4012.             this.showSlide(this.currentIndex);
  4013.             this.attachEvents();
  4014.             this.isOpen = true;
  4015.             // Animation d'ouverture immédiate pour favoris avec diagnostic
  4016.             setTimeout(() => {
  4017.               if (window.diagnoseSliderDisplay) {
  4018.                 window.diagnoseSliderDisplay('#favoritesSlider');
  4019.               }
  4020.             }, 50);
  4021.           }
  4022.           createSlider() {
  4023.             // ⚡ OPTIMISATION: Créer le slider seulement quand nécessaire
  4024.             if (document.querySelector('#favoritesSlider')) {
  4025.               return; // Déjà créé, ne pas recréer
  4026.             }
  4027.             
  4028.             // Structure HTML minimale et optimisée
  4029.             const sliderHTML = `
  4030.               <div class=\"favorites-slider\" id=\"favoritesSlider\" style=\"
  4031.                 position: fixed !important; 
  4032.                 top: 0 !important; 
  4033.                 left: 0 !important; 
  4034.                 width: 100% !important; 
  4035.                 height: 100% !important; 
  4036.                 background: rgba(0,0,0,0.95) !important; 
  4037.                 z-index: 9999 !important; 
  4038.                 display: flex !important; 
  4039.                 align-items: center !important; 
  4040.                 justify-content: center !important; 
  4041.                 opacity: 1 !important; 
  4042.                 visibility: visible !important;
  4043.               \">
  4044.                 <div class=\"slider-overlay\"></div>
  4045.                 
  4046.                 <!-- Header avec contrôles -->
  4047.                 <div class=\"slider-header\">
  4048.                   <div class=\"slider-controls\">
  4049.                     <button class=\"slider-btn favorite-btn\" title=\"Retirer des favoris\">
  4050.                       <i class=\"bi bi-heart-fill\"></i>
  4051.                     </button>
  4052.                     <button class=\"slider-btn zoom-btn\" title=\"Zoom\">
  4053.                       <i class=\"bi bi-zoom-in\"></i>
  4054.                     </button>
  4055.                     <button class=\"slider-btn close-btn\" title=\"Fermer\">
  4056.                       <i class=\"bi bi-x-lg\"></i>
  4057.                     </button>
  4058.                   </div>
  4059.                 </div>
  4060.                 <!-- Navigation -->
  4061.                 <button class=\"slider-nav prev-btn\" title=\"Précédent\">
  4062.                   <i class=\"bi bi-arrow-left-circle-fill\"></i>
  4063.                 </button>
  4064.                 <button class=\"slider-nav next-btn\" title=\"Suivant\">
  4065.                   <i class=\"bi bi-arrow-right-circle-fill\"></i>
  4066.                 </button>
  4067.                 <!-- Container des slides -->
  4068.                 <div class=\"slider-container\">
  4069.                   <div class=\"slider-track\" id=\"sliderTrack\">
  4070.                     \${this.favorites.map((fav, index) => `
  4071.                       <div class=\"slide\" data-index=\"\${index}\">
  4072.                         <div class=\"slide-content\">
  4073.                           <img src=\"\${fav.url}\" alt=\"\${fav.description || 'Photo favorite'}\" 
  4074.                                loading=\"\${index <= 2 ? 'eager' : 'lazy'}\"
  4075.                                draggable=\"false\">
  4076.                         </div>
  4077.                         <div class=\"slide-info\">
  4078.                           <h4>\${fav.description || 'Photo favorite'}</h4>
  4079.                           <p>\${fav.date || 'Date inconnue'}</p>
  4080.                         </div>
  4081.                       </div>
  4082.                     `).join('')}
  4083.                   </div>
  4084.                 </div>
  4085.                 <!-- Thumbnails -->
  4086.                 <div class=\"slider-thumbnails\">
  4087.                   \${this.favorites.map((fav, index) => `
  4088.                     <div class=\"thumbnail \${index === this.currentIndex ? 'active' : ''}\" 
  4089.                          data-index=\"\${index}\">
  4090.                       <img src=\"\${fav.url}\" alt=\"Thumbnail \${index + 1}\">
  4091.                     </div>
  4092.                   `).join('')}
  4093.                 </div>
  4094.               </div>
  4095.             `;
  4096.             // Injecter dans le DOM
  4097.             document.body.insertAdjacentHTML('beforeend', sliderHTML);
  4098.           }
  4099.           showSlide(index) {
  4100.             if (index < 0 || index >= this.favorites.length) return;
  4101.             this.currentIndex = index;
  4102.             const track = document.getElementById('sliderTrack');
  4103.             const translateX = -index * 100;
  4104.             
  4105.             track.style.transform = `translateX(\${translateX}%)`;
  4106.             // ⚡ OPTIMISÉ: Éviter forEach sur querySelectorAll (mémoire)
  4107.             const thumbnails = document.querySelectorAll('.thumbnail');
  4108.             for (let i = 0; i < thumbnails.length; i++) {
  4109.               const thumb = thumbnails[i];
  4110.               if (thumb?.classList) {
  4111.                 thumb.classList.toggle('active', i === index);
  4112.               }
  4113.             }
  4114.             // Mettre à jour le bouton favori
  4115.             const currentFav = this.favorites[index];
  4116.             const favoriteBtn = document.querySelector('.slider-controls .favorite-btn');
  4117.             if (favoriteBtn && currentFav) {
  4118.               favoriteBtn.setAttribute('data-id', currentFav.id);
  4119.             }
  4120.           }
  4121.           nextSlide() {
  4122.             const nextIndex = (this.currentIndex + 1) % this.favorites.length;
  4123.             this.showSlide(nextIndex);
  4124.           }
  4125.           prevSlide() {
  4126.             const prevIndex = (this.currentIndex - 1 + this.favorites.length) % this.favorites.length;
  4127.             this.showSlide(prevIndex);
  4128.           }
  4129.           close() {
  4130.             if (!this.isOpen) return;
  4131.             const slider = document.querySelector('.favorites-slider');
  4132.             if (slider && slider.classList) {
  4133.               slider.classList.remove('active');
  4134.               
  4135.               setTimeout(() => {
  4136.                 slider.remove();
  4137.                 this.isOpen = false;
  4138.               }, 300);
  4139.             }
  4140.           }
  4141.           attachEvents() {
  4142.             const slider = document.getElementById('favoritesSlider');
  4143.             
  4144.             // Bouton fermer
  4145.             slider.querySelector('.close-btn').addEventListener('click', () => this.close());
  4146.             
  4147.             // Navigation
  4148.             slider.querySelector('.prev-btn').addEventListener('click', () => this.prevSlide());
  4149.             slider.querySelector('.next-btn').addEventListener('click', () => this.nextSlide());
  4150.             
  4151.             // ⚡ OPTIMISÉ: Event delegation au lieu de listeners multiples
  4152.             const thumbContainer = slider.querySelector('.thumbnails-container') || slider;
  4153.             if (thumbContainer && !thumbContainer.hasAttribute('data-thumb-delegated')) {
  4154.               thumbContainer.addEventListener('click', (e) => {
  4155.                 const thumb = e.target.closest('.thumbnail');
  4156.                 if (thumb) {
  4157.                   const thumbnails = slider.querySelectorAll('.thumbnail');
  4158.                   const index = Array.from(thumbnails).indexOf(thumb);
  4159.                   if (index !== -1) this.showSlide(index);
  4160.                 }
  4161.               });
  4162.               thumbContainer.setAttribute('data-thumb-delegated', 'true');
  4163.             }
  4164.             // Bouton favori
  4165.             slider.querySelector('.favorite-btn').addEventListener('click', (e) => {
  4166.               const favoriteId = e.currentTarget.getAttribute('data-id');
  4167.               if (favoriteId) {
  4168.                 removeFavorite(favoriteId);
  4169.                 // Recharger le slider avec les favoris mis à jour
  4170.                 setTimeout(() => {
  4171.                   this.close();
  4172.                   if (getFavoriteItems().filter(item => item.type === 'image').length > 0) {
  4173.                     this.open(this.favorites[0]?.id);
  4174.                   }
  4175.                 }, 100);
  4176.               }
  4177.             });
  4178.             // Clavier
  4179.             document.addEventListener('keydown', this.handleKeyboard.bind(this));
  4180.             
  4181.             // Clic sur overlay pour fermer
  4182.             slider.querySelector('.slider-overlay').addEventListener('click', () => this.close());
  4183.             // Touch/swipe sur mobile
  4184.             const track = slider.querySelector('.slider-track');
  4185.             track.addEventListener('touchstart', this.handleTouchStart.bind(this), { passive: true });
  4186.             track.addEventListener('touchend', this.handleTouchEnd.bind(this), { passive: true });
  4187.             // Zoom sur clic simple (5 niveaux) + double-clic (legacy)
  4188.             slider.querySelectorAll('.slide img').forEach(img => {
  4189.               let zoomLevel = 1;
  4190.               let isDragging = false;
  4191.               let startX, startY, translateX = 0, translateY = 0;
  4192.               
  4193.               // Zoom sur clic simple (nouveau système 5 niveaux)
  4194.               img.addEventListener('click', (e) => {
  4195.                 e.preventDefault();
  4196.                 e.stopPropagation();
  4197.                 
  4198.                 // Cycle à travers 5 niveaux de zoom
  4199.                 switch(zoomLevel) {
  4200.                   case 1: zoomLevel = 1.5; break;  // 1x → 1.5x
  4201.                   case 1.5: zoomLevel = 2; break;  // 1.5x → 2x
  4202.                   case 2: zoomLevel = 3; break;    // 2x → 3x
  4203.                   case 3: zoomLevel = 4; break;    // 3x → 4x
  4204.                   case 4: zoomLevel = 5; break;    // 4x → 5x
  4205.                   case 5: 
  4206.                     zoomLevel = 1;                 // 5x → 1x (reset)
  4207.                     translateX = 0;
  4208.                     translateY = 0;
  4209.                     break;
  4210.                 }
  4211.                 console.log('FavoritesSlider - Zoom niveau:', zoomLevel);
  4212.                 img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  4213.                 
  4214.                 // Curseur selon le niveau
  4215.                 if (zoomLevel === 1) {
  4216.                   img.style.cursor = 'zoom-in';
  4217.                   img.removeAttribute('data-zoomed');
  4218.                 } else if (zoomLevel === 5) {
  4219.                   img.style.cursor = 'zoom-out';
  4220.                   img.setAttribute('data-zoomed', zoomLevel);
  4221.                 } else {
  4222.                   img.style.cursor = 'zoom-in';
  4223.                   img.setAttribute('data-zoomed', zoomLevel);
  4224.                 }
  4225.               });
  4226.               
  4227.               // Drag pour déplacer l'image zoomée
  4228.               img.addEventListener('mousedown', (e) => {
  4229.                 if (zoomLevel > 1) {
  4230.                   isDragging = true;
  4231.                   startX = e.clientX - translateX;
  4232.                   startY = e.clientY - translateY;
  4233.                   img.style.cursor = 'grabbing';
  4234.                   e.preventDefault();
  4235.                   e.stopPropagation();
  4236.                 }
  4237.               });
  4238.               const handleMouseMove = (e) => {
  4239.                 if (isDragging && zoomLevel > 1) {
  4240.                   translateX = e.clientX - startX;
  4241.                   translateY = e.clientY - startY;
  4242.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  4243.                 }
  4244.               };
  4245.               const handleMouseUp = () => {
  4246.                 if (isDragging) {
  4247.                   isDragging = false;
  4248.                   if (zoomLevel === 1) {
  4249.                     img.style.cursor = 'zoom-in';
  4250.                   } else if (zoomLevel === 5) {
  4251.                     img.style.cursor = 'zoom-out';
  4252.                   } else {
  4253.                     img.style.cursor = 'zoom-in';
  4254.                   }
  4255.                 }
  4256.               };
  4257.               document.addEventListener('mousemove', handleMouseMove);
  4258.               document.addEventListener('mouseup', handleMouseUp);
  4259.               // Support tactile pour mobile
  4260.               img.addEventListener('touchstart', (e) => {
  4261.                 if (zoomLevel > 1 && e.touches.length === 1) {
  4262.                   isDragging = true;
  4263.                   const touch = e.touches[0];
  4264.                   startX = touch.clientX - translateX;
  4265.                   startY = touch.clientY - translateY;
  4266.                   e.preventDefault();
  4267.                 }
  4268.               });
  4269.               img.addEventListener('touchmove', (e) => {
  4270.                 if (isDragging && zoomLevel > 1 && e.touches.length === 1) {
  4271.                   const touch = e.touches[0];
  4272.                   translateX = touch.clientX - startX;
  4273.                   translateY = touch.clientY - startY;
  4274.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  4275.                   e.preventDefault();
  4276.                 }
  4277.               });
  4278.               img.addEventListener('touchend', () => {
  4279.                 isDragging = false;
  4280.               });
  4281.               // Initialiser le curseur
  4282.               img.style.cursor = 'zoom-in';
  4283.               
  4284.               // Garder aussi le double-clic pour compatibilité (legacy)
  4285.               img.addEventListener('dblclick', this.handleZoom.bind(this));
  4286.             });
  4287.           }
  4288.           handleKeyboard(e) {
  4289.             if (!this.isOpen) return;
  4290.             
  4291.             switch(e.key) {
  4292.               case 'Escape':
  4293.                 this.close();
  4294.                 break;
  4295.               case 'ArrowLeft':
  4296.                 e.preventDefault();
  4297.                 this.prevSlide();
  4298.                 break;
  4299.               case 'ArrowRight':
  4300.                 e.preventDefault();
  4301.                 this.nextSlide();
  4302.                 break;
  4303.             }
  4304.           }
  4305.           handleTouchStart(e) {
  4306.             this.touchStartX = e.changedTouches[0].screenX;
  4307.           }
  4308.           handleTouchEnd(e) {
  4309.             this.touchEndX = e.changedTouches[0].screenX;
  4310.             this.handleSwipe();
  4311.           }
  4312.           handleSwipe() {
  4313.             const swipeThreshold = 50;
  4314.             const diff = this.touchStartX - this.touchEndX;
  4315.             if (Math.abs(diff) > swipeThreshold) {
  4316.               if (diff > 0) {
  4317.                 this.nextSlide(); // Swipe left -> next
  4318.               } else {
  4319.                 this.prevSlide(); // Swipe right -> prev
  4320.               }
  4321.             }
  4322.           }
  4323.           handleZoom(e) {
  4324.             const img = e.target;
  4325.             
  4326.             // Vérifier que l'élément et ses propriétés existent
  4327.             if (!img || !img.classList) {
  4328.               console.warn('Élément image invalide pour le zoom');
  4329.               return;
  4330.             }
  4331.             
  4332.             // Gérer les différents niveaux de zoom
  4333.             if (img.classList.contains('zoom-4x')) {
  4334.               // Retour à la taille normale
  4335.               img.classList.remove('zoom-4x', 'zoom-3x', 'zoom-2x', 'zoomed');
  4336.               img.style.cursor = 'pointer';
  4337.               img.style.transform = 'scale(1)'; // Réinitialiser la position
  4338.             } else if (img.classList.contains('zoom-3x')) {
  4339.               // Passer au zoom 4x
  4340.               img.classList.remove('zoom-3x');
  4341.               img.classList.add('zoom-4x');
  4342.               img.style.cursor = 'zoom-out';
  4343.               img.style.transform = 'scale(4)'; // Réinitialiser la position
  4344.             } else if (img.classList.contains('zoom-2x')) {
  4345.               // Passer au zoom 3x
  4346.               img.classList.remove('zoom-2x');
  4347.               img.classList.add('zoom-3x');
  4348.               img.style.cursor = 'zoom-in';
  4349.               img.style.transform = 'scale(3)'; // Réinitialiser la position
  4350.             } else if (img.classList.contains('zoomed')) {
  4351.               // Passer au zoom 2x
  4352.               img.classList.remove('zoomed');
  4353.               img.classList.add('zoom-2x');
  4354.               img.style.cursor = 'zoom-in';
  4355.               img.style.transform = 'scale(2)'; // Réinitialiser la position
  4356.             } else {
  4357.               // Premier zoom (1.5x)
  4358.               img.classList.add('zoomed');
  4359.               img.style.cursor = 'zoom-in';
  4360.               img.style.transform = 'scale(1.5)'; // Réinitialiser la position
  4361.             }
  4362.           }
  4363.         }
  4364.         // Slider universel pour toutes les images (favoris + galerie normale)
  4365.         class UniversalImageSlider {
  4366.           constructor() {
  4367.             this.currentIndex = 0;
  4368.             this.images = [];
  4369.             this.isOpen = false;
  4370.             this.touchStartX = 0;
  4371.             this.touchEndX = 0;
  4372.           }
  4373.           // Ouvrir avec une image spécifique depuis les favoris
  4374.           openFromFavorites(favoriteId) {
  4375.             console.log('Ouverture du slider depuis favoris:', favoriteId);
  4376.             
  4377.             // Récupérer tous les favoris images
  4378.             this.images = getFavoriteItems().filter(item => item.type === 'image');
  4379.             
  4380.             if (this.images.length === 0) {
  4381.               console.error('Aucun favori image trouvé');
  4382.               return;
  4383.             }
  4384.             // Trouver l'index de l'image courante
  4385.             this.currentIndex = this.images.findIndex(img => img.id === favoriteId);
  4386.             if (this.currentIndex === -1) this.currentIndex = 0;
  4387.             this.openSlider();
  4388.           }
  4389.           // Ouvrir avec une image spécifique depuis la galerie normale
  4390.           openFromGallery(imageId, dayContainer) {
  4391.             console.log('Ouverture du slider depuis galerie:', imageId, dayContainer);
  4392.             
  4393.             // Récupérer toutes les images du jour courant
  4394.             const dayImages = [];
  4395.             
  4396.             // Chercher dans le container du jour (peut être .dynamic-card ou autre)
  4397.             let photoItems;
  4398.             if (dayContainer) {
  4399.               photoItems = dayContainer.querySelectorAll('.photo-item');
  4400.             } else {
  4401.               // Fallback: chercher dans tout le document
  4402.               photoItems = document.querySelectorAll('.photo-item');
  4403.             }
  4404.             
  4405.             console.log('Photo items trouvés:', photoItems.length);
  4406.             
  4407.             photoItems.forEach(item => {
  4408.               const img = item.querySelector('img');
  4409.               const heartIcon = item.querySelector('.heart-icon');
  4410.               
  4411.               console.log('Processing item:', {
  4412.                 img: !!img,
  4413.                 heartIcon: !!heartIcon,
  4414.                 imgSrc: img ? img.src : null,
  4415.                 heartIconId: heartIcon ? heartIcon.getAttribute('data-id') : null
  4416.               });
  4417.               
  4418.               if (img && heartIcon) {
  4419.                 dayImages.push({
  4420.                   id: heartIcon.getAttribute('data-id'),
  4421.                   url: heartIcon.getAttribute('data-path') || img.src,
  4422.                   description: heartIcon.getAttribute('data-description') || img.alt || 'Photo',
  4423.                   date: '', // Pas de date spécifique pour les images de galerie
  4424.                   type: 'image'
  4425.                 });
  4426.               }
  4427.             });
  4428.             console.log('Images trouvées:', dayImages);
  4429.             this.images = dayImages;
  4430.             
  4431.             if (this.images.length === 0) {
  4432.               console.error('Aucune image trouvée dans ce jour');
  4433.               // Essayer de créer au moins l'image courante
  4434.               const currentHeartIcon = document.querySelector(`[data-id=\"\${imageId}\"]`);
  4435.               if (currentHeartIcon) {
  4436.                 const currentImg = currentHeartIcon.closest('.photo-item').querySelector('img');
  4437.                 if (currentImg) {
  4438.                   this.images = [{
  4439.                     id: imageId,
  4440.                     url: currentHeartIcon.getAttribute('data-path') || currentImg.src,
  4441.                     description: currentHeartIcon.getAttribute('data-description') || currentImg.alt || 'Photo',
  4442.                     date: '',
  4443.                     type: 'image'
  4444.                   }];
  4445.                   console.log('Image de fallback créée:', this.images);
  4446.                 }
  4447.               }
  4448.               
  4449.               if (this.images.length === 0) {
  4450.                 return;
  4451.               }
  4452.             }
  4453.             // Trouver l'index de l'image courante
  4454.             this.currentIndex = this.images.findIndex(img => img.id === imageId);
  4455.             if (this.currentIndex === -1) this.currentIndex = 0;
  4456.             console.log('Index trouvé:', this.currentIndex);
  4457.             this.openSlider();
  4458.           }
  4459.           openSlider() {
  4460.             console.log('=== openSlider appelée ===');
  4461.             console.log('Index courant:', this.currentIndex, 'Total:', this.images.length);
  4462.             console.log('Images à afficher:', this.images);
  4463.             // Supprimer tout slider existant
  4464.             const existingSlider = document.querySelector('.universal-slider');
  4465.             if (existingSlider) {
  4466.               console.log('Suppression du slider existant');
  4467.               existingSlider.remove();
  4468.             }
  4469.             this.createSlider();
  4470.             this.showSlide(this.currentIndex);
  4471.             this.attachEvents();
  4472.             this.isOpen = true;
  4473.               // Animation d'ouverture immédiate et garantie avec diagnostic
  4474.               setTimeout(() => {
  4475.                 if (window.diagnoseSliderDisplay) {
  4476.                   window.diagnoseSliderDisplay('#universalSlider');
  4477.                 }
  4478.               }, 50);
  4479.           }
  4480.           createSlider() {
  4481.             // ⚡ OPTIMISATION: Créer seulement si nécessaire
  4482.             if (document.querySelector('#universalSlider')) {
  4483.               return; // Déjà créé
  4484.             }
  4485.             
  4486.             console.log('Création slider pour', this.images.length, 'images');
  4487.             
  4488.             // HTML optimisé et minimal
  4489.             const sliderHTML = `
  4490.               <div class=\"universal-slider\" id=\"universalSlider\" style=\"
  4491.                 position: fixed !important; 
  4492.                 top: 0 !important; 
  4493.                 left: 0 !important; 
  4494.                 width: 100% !important; 
  4495.                 height: 100% !important; 
  4496.                 background: rgba(0,0,0,0.95) !important; 
  4497.                 z-index: 9999 !important; 
  4498.                 display: flex !important; 
  4499.                 align-items: center !important; 
  4500.                 justify-content: center !important; 
  4501.                 opacity: 1 !important; 
  4502.                 visibility: visible !important;
  4503.               \">
  4504.                 <div class=\"slider-overlay\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; cursor: pointer;\"></div>
  4505.                 
  4506.                 <!-- Header avec contrôles -->
  4507.                 <div class=\"slider-header\" style=\"
  4508.                   position: absolute; 
  4509.                   top: 20px; 
  4510.                   right: 20px; 
  4511.                   display: flex; 
  4512.                   align-items: center; 
  4513.                   gap: 15px; 
  4514.                   z-index: 10001;
  4515.                 \">
  4516.                   <button class=\"slider-btn close-btn\" title=\"Fermer\" style=\"
  4517.                     background: rgba(255,255,255,0.2); 
  4518.                     border: none; 
  4519.                     color: white; 
  4520.                     width: 40px; 
  4521.                     height: 40px; 
  4522.                     border-radius: 50%; 
  4523.                     cursor: pointer; 
  4524.                     display: flex; 
  4525.                     align-items: center; 
  4526.                     justify-content: center;
  4527.                     transition: background 0.2s ease;
  4528.                   \">
  4529.                     <i class=\"bi bi-x-lg\"></i>
  4530.                   </button>
  4531.                 </div>
  4532.                 <!-- Navigation -->
  4533.                 <button class=\"slider-nav prev-btn\" title=\"Précédent\" style=\"
  4534.                   position: absolute; 
  4535.                   left: 20px; 
  4536.                   top: 50%; 
  4537.                   transform: translateY(-50%); 
  4538.                   background: rgba(255,255,255,0.2); 
  4539.                   border: none; 
  4540.                   color: white; 
  4541.                   width: 50px; 
  4542.                   height: 50px; 
  4543.                   border-radius: 50%; 
  4544.                   cursor: pointer; 
  4545.                   display: \${this.images.length > 1 ? 'flex' : 'none'}; 
  4546.                   align-items: center; 
  4547.                   justify-content: center; 
  4548.                   z-index: 10001;
  4549.                   transition: background 0.2s ease;
  4550.                 \">
  4551.                   <i class=\"bi bi-arrow-left-circle-fill\" style=\"font-size: 20px;\"></i>
  4552.                 </button>
  4553.                 <button class=\"slider-nav next-btn\" title=\"Suivant\" style=\"
  4554.                   position: absolute; 
  4555.                   right: 20px; 
  4556.                   top: 50%; 
  4557.                   transform: translateY(-50%); 
  4558.                   background: rgba(255,255,255,0.2); 
  4559.                   border: none; 
  4560.                   color: white; 
  4561.                   width: 50px; 
  4562.                   height: 50px; 
  4563.                   border-radius: 50%; 
  4564.                   cursor: pointer; 
  4565.                   display: \${this.images.length > 1 ? 'flex' : 'none'}; 
  4566.                   align-items: center; 
  4567.                   justify-content: center; 
  4568.                   z-index: 10001;
  4569.                   transition: background 0.2s ease;
  4570.                 \">
  4571.                   <i class=\"bi bi-arrow-right-circle-fill\" style=\"font-size: 20px;\"></i>
  4572.                 </button>
  4573.                 <!-- Container des slides -->
  4574.                 <div class=\"slider-container\" style=\"
  4575.                   position: relative; 
  4576.                   width: 90%; 
  4577.                   height: 90%; 
  4578.                   display: flex; 
  4579.                   align-items: center; 
  4580.                   justify-content: center; 
  4581.                   z-index: 10000;
  4582.                 \">
  4583.                   <div class=\"slider-track\" id=\"universalSliderTrack\" style=\"
  4584.                     position: relative; 
  4585.                     width: 100%; 
  4586.                     height: 100%; 
  4587.                     display: flex; 
  4588.                     align-items: center; 
  4589.                     justify-content: center;
  4590.                     overflow: hidden;
  4591.                   \">
  4592.                     \${this.images.map((img, index) => `
  4593.                       <div class=\"slide\" data-index=\"\${index}\" style=\"
  4594.                         position: absolute; 
  4595.                         width: 100%; 
  4596.                         height: 100%; 
  4597.                         display: \${index === 0 ? 'flex' : 'none'}; 
  4598.                         align-items: center; 
  4599.                         justify-content: center; 
  4600.                         flex-direction: column;
  4601.                       \">
  4602.                         <div class=\"slide-content\" style=\"
  4603.                           position: relative; 
  4604.                           max-width: 100%; 
  4605.                           max-height: 90%; 
  4606.                           display: flex; 
  4607.                           align-items: center; 
  4608.                           justify-content: center;
  4609.                         \">
  4610.                           <img src=\"\${img.url}\" alt=\"\${img.description || 'Photo'}\" 
  4611.                                loading=\"\${index <= 2 ? 'eager' : 'lazy'}\"
  4612.                                draggable=\"false\"
  4613.                                style=\"
  4614.                                  max-width: 100%; 
  4615.                                  max-height: 100%; 
  4616.                                  object-fit: contain; 
  4617.                                  cursor: zoom-in;
  4618.                                  transition: transform 0.3s ease;
  4619.                                  user-select: none;
  4620.                                \">
  4621.                         </div>
  4622.                         \${img.description ? `
  4623.                         <div class=\"slide-info\" style=\"
  4624.                           position: absolute; 
  4625.                           bottom: 60px; 
  4626.                           left: 50%; 
  4627.                           transform: translateX(-50%); 
  4628.                           text-align: center; 
  4629.                           color: white; 
  4630.                           background: rgba(0,0,0,0.6); 
  4631.                           padding: 8px 16px; 
  4632.                           border-radius: 20px; 
  4633.                           max-width: 80%;
  4634.                           font-size: 14px;
  4635.                         \">
  4636.                           \${img.description}
  4637.                         </div>
  4638.                         ` : ''}
  4639.                       </div>
  4640.                     `).join('')}
  4641.                   </div>
  4642.                 </div>
  4643.                 <!-- Galerie de thumbnails révolutionnaire -->
  4644.                 <div class=\"cinema-gallery\" style=\"
  4645.                   position: absolute; 
  4646.                   bottom: 0; 
  4647.                   left: 0; 
  4648.                   right: 0;
  4649.                   height: 180px;
  4650.                   background: linear-gradient(0deg, rgba(0,0,0,0.95) 0%, rgba(0,0,0,0.7) 50%, transparent 100%);
  4651.                   z-index: 10001;
  4652.                   display: flex;
  4653.                   flex-direction: column;
  4654.                   justify-content: flex-end;
  4655.                   padding: 0 20px 20px;
  4656.                 \">
  4657.                   
  4658.                   <!-- Info header avec compteur élégant -->
  4659.                   <div class=\"gallery-header\" style=\"
  4660.                     display: flex;
  4661.                     justify-content: space-between;
  4662.                     align-items: center;
  4663.                     margin-bottom: 15px;
  4664.                   \">
  4665.                     <div class=\"photo-counter\" style=\"
  4666.                       color: white;
  4667.                       font-size: 16px;
  4668.                       font-weight: 600;
  4669.                       display: flex;
  4670.                       align-items: center;
  4671.                       gap: 8px;
  4672.                     \">
  4673.                       <div style=\"
  4674.                         width: 8px;
  4675.                         height: 8px;
  4676.                         background: #10b981;
  4677.                         border-radius: 50%;
  4678.                         animation: pulse 2s infinite;
  4679.                       \"></div>
  4680.                       <span>\${(this.currentIndex || 0) + 1}</span>
  4681.                       <span style=\"opacity: 0.6;\">sur</span>
  4682.                       <span>\${this.images.length}</span>
  4683.                     </div>
  4684.                     <div class=\"gallery-controls\" style=\"
  4685.                       display: flex;
  4686.                       gap: 12px;
  4687.                       align-items: center;
  4688.                     \">
  4689.                       <div style=\"color: rgba(255,255,255,0.7); font-size: 12px;\">
  4690.                         Clic = Zoom 5x • Drag = Déplacer
  4691.                       </div>
  4692.                     </div>
  4693.                   </div>
  4694.                   
  4695.                   <!-- Carrousel de thumbnails cinématographique -->
  4696.                   <div class=\"cinema-carousel\" style=\"
  4697.                     position: relative;
  4698.                     height: 80px;
  4699.                     overflow: hidden;
  4700.                   \">
  4701.                     <!-- Container scrollable -->
  4702.                     <div class=\"carousel-track\" id=\"carouselTrack\" style=\"
  4703.                       display: flex;
  4704.                       gap: 12px;
  4705.                       height: 100%;
  4706.                       overflow-x: auto;
  4707.                       overflow-y: hidden;
  4708.                       scroll-behavior: smooth;
  4709.                       scrollbar-width: none;
  4710.                       -ms-overflow-style: none;
  4711.                       padding: 0 50px;
  4712.                     \">
  4713.                       \${this.images.map((img, index) => `
  4714.                         <div class=\"cinema-thumb \${index === 0 ? 'active' : ''}\" 
  4715.                              data-index=\"\${index}\" 
  4716.                              style=\"
  4717.                                flex: 0 0 auto;
  4718.                                width: \${index === 0 ? '100px' : '70px'};
  4719.                                height: 70px;
  4720.                                border-radius: 8px;
  4721.                                overflow: hidden;
  4722.                                cursor: pointer;
  4723.                                position: relative;
  4724.                                transition: transform 0.2s ease, opacity 0.2s ease;
  4725.                                transform: \${index === 0 ? 'translateY(-4px)' : 'translateY(0)'};
  4726.                                opacity: \${index === 0 ? '1' : '0.7'};
  4727.                                border: \${index === 0 ? '2px solid #10b981' : '1px solid rgba(255,255,255,0.3)'};
  4728.                              \"
  4729.                              onmouseenter=\"
  4730.                                if (\${index} !== (window.universalSlider?.currentIndex || 0)) {
  4731.                                  this.style.opacity = '0.9';
  4732.                                }
  4733.                              \"
  4734.                              onmouseleave=\"
  4735.                                if (\${index} !== (window.universalSlider?.currentIndex || 0)) {
  4736.                                  this.style.opacity = '0.7';
  4737.                                }
  4738.                              \">
  4739.                           
  4740.                           <!-- Image principale -->
  4741.                           <img src=\"\${img.url}\" 
  4742.                                alt=\"\${img.description || 'Photo'}\" 
  4743.                                loading=\"lazy\" 
  4744.                                decoding=\"async\"
  4745.                                style=\"
  4746.                                  width: 100%; 
  4747.                                  height: 100%; 
  4748.                                  object-fit: cover;
  4749.                                \">
  4750.                           
  4751.                           <!-- Numéro simplifié -->
  4752.                           <div class=\"thumb-number\" style=\"
  4753.                             position: absolute;
  4754.                             top: 4px;
  4755.                             right: 4px;
  4756.                             background: \${index === 0 ? '#10b981' : 'rgba(0,0,0,0.8)'};
  4757.                             color: white;
  4758.                             font-size: 10px;
  4759.                             font-weight: 500;
  4760.                             padding: 2px 5px;
  4761.                             border-radius: 4px;
  4762.                             min-width: 16px;
  4763.                             text-align: center;
  4764.                           \">
  4765.                             \${index + 1}
  4766.                           </div>
  4767.                           
  4768.                           <!-- Indicateur actif simplifié -->
  4769.                           \${index === 0 ? `
  4770.                           <div class=\"active-indicator\" style=\"
  4771.                             position: absolute;
  4772.                             bottom: -1px;
  4773.                             left: 50%;
  4774.                             transform: translateX(-50%);
  4775.                             width: 16px;
  4776.                             height: 2px;
  4777.                             background: #10b981;
  4778.                             border-radius: 1px;
  4779.                           \"></div>
  4780.                           ` : ''}
  4781.                           
  4782.                           <!-- Preview au hover pour les non-actifs -->
  4783.                           \${index !== 0 ? `
  4784.                           <div class=\"hover-preview\" style=\"
  4785.                             position: absolute;
  4786.                             bottom: -40px;
  4787.                             left: 50%;
  4788.                             transform: translateX(-50%);
  4789.                             background: rgba(0,0,0,0.9);
  4790.                             color: white;
  4791.                             font-size: 11px;
  4792.                             padding: 4px 8px;
  4793.                             border-radius: 6px;
  4794.                             opacity: 0;
  4795.                             pointer-events: none;
  4796.                             transition: all 0.3s ease;
  4797.                             white-space: nowrap;
  4798.                             z-index: 1000;
  4799.                           \">
  4800.                             Photo \${index + 1}
  4801.                           </div>
  4802.                           ` : ''}
  4803.                         </div>
  4804.                       `).join('')}
  4805.                     </div>
  4806.                     
  4807.                     <!-- Gradients de fade sur les côtés -->
  4808.                     <div style=\"
  4809.                       position: absolute;
  4810.                       left: 0;
  4811.                       top: 0;
  4812.                       bottom: 0;
  4813.                       width: 50px;
  4814.                       background: linear-gradient(90deg, rgba(0,0,0,0.8), transparent);
  4815.                       pointer-events: none;
  4816.                       z-index: 1;
  4817.                     \"></div>
  4818.                     <div style=\"
  4819.                       position: absolute;
  4820.                       right: 0;
  4821.                       top: 0;
  4822.                       bottom: 0;
  4823.                       width: 50px;
  4824.                       background: linear-gradient(-90deg, rgba(0,0,0,0.8), transparent);
  4825.                       pointer-events: none;
  4826.                       z-index: 1;
  4827.                     \"></div>
  4828.                   </div>
  4829.                 </div>
  4830.                 <!-- Animations CSS Optimisées -->
  4831.                 <style>
  4832.                   /* Optimisation: animations réduites et ciblées */
  4833.                   @keyframes pulse {
  4834.                     0%, 100% { opacity: 1; }
  4835.                     50% { opacity: 0.7; }
  4836.                   }
  4837.                   
  4838.                   /* Suppression du glow coûteux - remplacé par border simple */
  4839.                   .cinema-thumb.active .active-indicator {
  4840.                     background: #10b981;
  4841.                     animation: none; /* Suppression de l'animation glow */
  4842.                   }
  4843.                   
  4844.                   /* Hover optimisé - moins d'effets */
  4845.                   .cinema-thumb:hover .hover-preview {
  4846.                     opacity: 1 !important;
  4847.                     bottom: -35px !important;
  4848.                   }
  4849.                   
  4850.                   /* Masquer scrollbar */
  4851.                   .carousel-track::-webkit-scrollbar {
  4852.                     display: none;
  4853.                   }
  4854.                   
  4855.                   /* Optimisation: will-change pour les éléments animés */
  4856.                   .cinema-thumb {
  4857.                     will-change: transform, filter;
  4858.                   }
  4859.                   
  4860.                   .progress-bar {
  4861.                     will-change: width;
  4862.                   }
  4863.                 </style>
  4864.               </div>
  4865.             `;
  4866.             // Injecter dans le DOM
  4867.             console.log('Ajout du slider au DOM');
  4868.             document.body.insertAdjacentHTML('beforeend', sliderHTML);
  4869.             
  4870.             // Vérifier que le slider a été ajouté
  4871.             const addedSlider = document.querySelector('#universalSlider');
  4872.             console.log('Slider ajouté:', !!addedSlider);
  4873.             if (addedSlider) {
  4874.               console.log('Slider trouvé dans le DOM');
  4875.               console.log('Styles du slider:', {
  4876.                 display: addedSlider.style.display,
  4877.                 opacity: addedSlider.style.opacity,
  4878.                 visibility: addedSlider.style.visibility,
  4879.                 zIndex: addedSlider.style.zIndex,
  4880.                 position: addedSlider.style.position
  4881.               });
  4882.               console.log('Slider dans viewport:', addedSlider.getBoundingClientRect());
  4883.             } else {
  4884.               console.error('Erreur: slider non trouvé après ajout');
  4885.             }
  4886.           }
  4887.           showSlide(index) {
  4888.             console.log('=== showSlide appelée ===', 'index:', index, 'total:', this.images.length);
  4889.             if (index < 0 || index >= this.images.length) {
  4890.               console.log('Index invalide, arrêt');
  4891.               return;
  4892.             }
  4893.             this.currentIndex = index;
  4894.             // Masquer toutes les slides et afficher seulement la courante
  4895.             const slides = document.querySelectorAll('#universalSlider .slide');
  4896.             console.log('Slides trouvées:', slides.length);
  4897.             slides.forEach((slide, i) => {
  4898.               slide.style.display = i === index ? 'flex' : 'none';
  4899.               console.log(`Slide \${i}:`, i === index ? 'visible' : 'cachée');
  4900.             });
  4901.             // Mettre à jour le compteur
  4902.             const currentSlideSpan = document.querySelector('#universalSlider .current-slide');
  4903.             if (currentSlideSpan) {
  4904.               currentSlideSpan.textContent = index + 1;
  4905.               console.log('Compteur mis à jour:', index + 1);
  4906.             }
  4907.             // Mettre à jour les boutons de navigation
  4908.             const prevBtn = document.querySelector('#universalSlider .prev-btn');
  4909.             const nextBtn = document.querySelector('#universalSlider .next-btn');
  4910.             
  4911.             if (prevBtn) {
  4912.               prevBtn.style.opacity = index > 0 ? '1' : '0.5';
  4913.             }
  4914.             if (nextBtn) {
  4915.               nextBtn.style.opacity = index < this.images.length - 1 ? '1' : '0.5';
  4916.             }
  4917.             // Mettre à jour la galerie cinématographique
  4918.             this.updateCinemaGallery(index);
  4919.             // Mettre à jour le bouton favori
  4920.             this.updateFavoriteButton();
  4921.           }
  4922.           updateCinemaGallery(activeIndex) {
  4923.             // Mettre à jour la progress bar (optimisé)
  4924.             const progressBar = document.querySelector('.progress-bar');
  4925.             if (progressBar) {
  4926.               progressBar.style.width = `\${(activeIndex + 1) / this.images.length * 100}%`;
  4927.             }
  4928.             // Mettre à jour le compteur (optimisé)
  4929.             const counter = document.querySelector('.photo-counter span');
  4930.             if (counter) {
  4931.               counter.textContent = activeIndex + 1;
  4932.             }
  4933.             // Mettre à jour les thumbnails - optimisé avec moins de calculs
  4934.             const cinemaThumbs = document.querySelectorAll('.cinema-thumb');
  4935.             cinemaThumbs.forEach((thumb, i) => {
  4936.               const isActive = i === activeIndex;
  4937.               
  4938.               // Optimisation: changements minimaux
  4939.               if (isActive) {
  4940.                 thumb.style.width = '100px';
  4941.                 thumb.style.transform = 'translateY(-4px)';
  4942.                 thumb.style.opacity = '1';
  4943.                 thumb.style.borderColor = '#10b981';
  4944.                 thumb.style.borderWidth = '2px';
  4945.                 
  4946.                 // Numéro actif - simplifié
  4947.                 const number = thumb.querySelector('.thumb-number');
  4948.                 if (number) {
  4949.                   number.style.background = '#10b981';
  4950.                 }
  4951.               } else {
  4952.                 thumb.style.width = '70px';
  4953.                 thumb.style.transform = 'translateY(0)';
  4954.                 thumb.style.opacity = '0.7';
  4955.                 thumb.style.borderColor = 'rgba(255,255,255,0.3)';
  4956.                 thumb.style.borderWidth = '1px';
  4957.                 
  4958.                 // Numéro inactif - simplifié
  4959.                 const number = thumb.querySelector('.thumb-number');
  4960.                 if (number) {
  4961.                   number.style.background = 'rgba(0,0,0,0.8)';
  4962.                 }
  4963.               }
  4964.             });
  4965.             // Auto-scroll optimisé avec throttling
  4966.             if (!this.scrollTimeout) {
  4967.               this.scrollTimeout = setTimeout(() => {
  4968.                 const track = document.getElementById('carouselTrack');
  4969.                 const activeThumb = document.querySelector(`.cinema-thumb[data-index=\"\${activeIndex}\"]`);
  4970.                 if (track && activeThumb) {
  4971.                   const scrollLeft = activeThumb.offsetLeft - (track.clientWidth / 2) + (activeThumb.clientWidth / 2);
  4972.                   track.scrollTo({
  4973.                     left: scrollLeft,
  4974.                     behavior: 'smooth'
  4975.                   });
  4976.                 }
  4977.                 this.scrollTimeout = null;
  4978.               }, 50); // Throttle à 50ms
  4979.             }
  4980.           }
  4981.           updateFavoriteButton() {
  4982.             const currentImage = this.images[this.currentIndex];
  4983.             const favoriteBtn = document.querySelector('.slider-controls .favorite-btn');
  4984.             
  4985.             if (favoriteBtn && currentImage) {
  4986.               favoriteBtn.setAttribute('data-id', currentImage.id);
  4987.               
  4988.               // Vérifier si l'image est déjà en favoris
  4989.               const heartIcon = document.querySelector(`[data-id=\"\${currentImage.id}\"]`);
  4990.               const isFavorite = heartIcon && heartIcon.querySelector('i.bi-heart-fill');
  4991.               
  4992.               const icon = favoriteBtn.querySelector('i');
  4993.               if (isFavorite) {
  4994.                 icon.className = 'bi bi-heart-fill';
  4995.                 favoriteBtn.style.color = '#e91e63';
  4996.               } else {
  4997.                 icon.className = 'bi bi-heart';
  4998.                 favoriteBtn.style.color = 'white';
  4999.               }
  5000.             }
  5001.           }
  5002.           nextSlide() {
  5003.             const nextIndex = (this.currentIndex + 1) % this.images.length;
  5004.             this.showSlide(nextIndex);
  5005.           }
  5006.           prevSlide() {
  5007.             const prevIndex = (this.currentIndex - 1 + this.images.length) % this.images.length;
  5008.             this.showSlide(prevIndex);
  5009.           }
  5010.           close() {
  5011.             if (!this.isOpen) return;
  5012.             const slider = document.querySelector('.universal-slider');
  5013.             if (slider) {
  5014.               slider.classList.remove('active');
  5015.               
  5016.               setTimeout(() => {
  5017.                 slider.remove();
  5018.                 this.isOpen = false;
  5019.               }, 300);
  5020.             }
  5021.           }
  5022.           attachEvents() {
  5023.             console.log('=== attachEvents appelée ===');
  5024.             const slider = document.getElementById('universalSlider');
  5025.             if (!slider) {
  5026.               console.error('Slider non trouvé pour attachEvents');
  5027.               return;
  5028.             }
  5029.             console.log('Slider trouvé pour attachEvents');
  5030.             
  5031.             // Bouton fermer
  5032.             const closeBtn = slider.querySelector('.close-btn');
  5033.             if (closeBtn) {
  5034.               console.log('Bouton fermer trouvé');
  5035.               closeBtn.addEventListener('click', () => {
  5036.                 console.log('Clic fermer');
  5037.                 this.close();
  5038.               });
  5039.             }
  5040.             
  5041.             // Navigation
  5042.             const prevBtn = slider.querySelector('.prev-btn');
  5043.             const nextBtn = slider.querySelector('.next-btn');
  5044.             if (prevBtn) {
  5045.               console.log('Bouton précédent trouvé');
  5046.               prevBtn.addEventListener('click', () => {
  5047.                 console.log('Clic précédent');
  5048.                 this.prevSlide();
  5049.               });
  5050.             }
  5051.             if (nextBtn) {
  5052.               console.log('Bouton suivant trouvé');
  5053.               nextBtn.addEventListener('click', () => {
  5054.                 console.log('Clic suivant');
  5055.                 this.nextSlide();
  5056.               });
  5057.             }
  5058.             // Navigation cinématographique des thumbnails
  5059.             const cinemaThumbs = slider.querySelectorAll('.cinema-thumb');
  5060.             cinemaThumbs.forEach((thumb, index) => {
  5061.               thumb.addEventListener('click', () => {
  5062.                 console.log('Clic cinema thumbnail:', index);
  5063.                 this.showSlide(index);
  5064.                 this.updateCinemaGallery(index);
  5065.               });
  5066.             });
  5067.             console.log('Cinema thumbnails cliquables:', cinemaThumbs.length);
  5068.             // Clic sur overlay pour fermer
  5069.             const overlay = slider.querySelector('.slider-overlay');
  5070.             if (overlay) {
  5071.               overlay.addEventListener('click', () => {
  5072.                 console.log('Clic overlay');
  5073.                 this.close();
  5074.               });
  5075.             }
  5076.             // Clavier
  5077.             this.keyboardHandler = this.handleKeyboard.bind(this);
  5078.             document.addEventListener('keydown', this.keyboardHandler);
  5079.             console.log('Événements clavier attachés');
  5080.             // Zoom sur les images
  5081.             this.attachZoomEvents(slider);
  5082.             console.log('Événements zoom attachés');
  5083.             console.log('Événements attachés avec succès');
  5084.           }
  5085.           close() {
  5086.             console.log('=== close appelée ===');
  5087.             const slider = document.querySelector('.universal-slider');
  5088.             if (slider) {
  5089.               console.log('Fermeture du slider');
  5090.               // Animation de fermeture
  5091.               slider.style.opacity = '0';
  5092.               
  5093.               setTimeout(() => {
  5094.                 slider.remove();
  5095.                 console.log('Slider supprimé du DOM');
  5096.                 
  5097.                 // Nettoyer les événements
  5098.                 if (this.keyboardHandler) {
  5099.                   document.removeEventListener('keydown', this.keyboardHandler);
  5100.                   this.keyboardHandler = null;
  5101.                 }
  5102.                 
  5103.                 this.isOpen = false;
  5104.               }, 300);
  5105.             }
  5106.           }
  5107.           nextSlide() {
  5108.             if (this.currentIndex < this.images.length - 1) {
  5109.               this.showSlide(this.currentIndex + 1);
  5110.             }
  5111.           }
  5112.           prevSlide() {
  5113.             if (this.currentIndex > 0) {
  5114.               this.showSlide(this.currentIndex - 1);
  5115.             }
  5116.           }
  5117.           handleKeyboard(e) {
  5118.             if (!this.isOpen) return;
  5119.             
  5120.             switch (e.key) {
  5121.               case 'Escape':
  5122.                 this.close();
  5123.                 break;
  5124.               case 'ArrowLeft':
  5125.                 this.prevSlide();
  5126.                 break;
  5127.               case 'ArrowRight':
  5128.                 this.nextSlide();
  5129.                 break;
  5130.             }
  5131.           }
  5132.           attachZoomEvents(slider) {
  5133.             // Fonctionnalité de zoom à 5 niveaux pour les images
  5134.             const images = slider.querySelectorAll('.slide img');
  5135.             images.forEach(img => {
  5136.               let zoomLevel = 1; // 1x, 1.5x, 2x, 3x, 4x, 5x
  5137.               let isDragging = false;
  5138.               let startX = 0;
  5139.               let startY = 0;
  5140.               let translateX = 0;
  5141.               let translateY = 0;
  5142.               // Clic simple pour zoom progressif (5 niveaux)
  5143.               img.addEventListener('click', (e) => {
  5144.                 e.preventDefault();
  5145.                 e.stopPropagation();
  5146.                 
  5147.                 // Cycle à travers 5 niveaux de zoom
  5148.                 switch(zoomLevel) {
  5149.                   case 1: zoomLevel = 1.5; break;  // 1x → 1.5x
  5150.                   case 1.5: zoomLevel = 2; break;  // 1.5x → 2x
  5151.                   case 2: zoomLevel = 3; break;    // 2x → 3x
  5152.                   case 3: zoomLevel = 4; break;    // 3x → 4x
  5153.                   case 4: zoomLevel = 5; break;    // 4x → 5x
  5154.                   case 5: 
  5155.                     zoomLevel = 1;                 // 5x → 1x (reset)
  5156.                     translateX = 0;
  5157.                     translateY = 0;
  5158.                     break;
  5159.                 }
  5160.                 console.log('Zoom niveau:', zoomLevel);
  5161.                 img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  5162.                 
  5163.                 // Curseur selon le niveau
  5164.                 if (zoomLevel === 1) {
  5165.                   img.style.cursor = 'zoom-in';
  5166.                   img.removeAttribute('data-zoomed');
  5167.                 } else if (zoomLevel === 5) {
  5168.                   img.style.cursor = 'zoom-out';
  5169.                   img.setAttribute('data-zoomed', zoomLevel);
  5170.                 } else {
  5171.                   img.style.cursor = 'zoom-in';
  5172.                   img.setAttribute('data-zoomed', zoomLevel);
  5173.                 }
  5174.               });
  5175.               // Drag pour déplacer l'image zoomée
  5176.               img.addEventListener('mousedown', (e) => {
  5177.                 if (zoomLevel > 1) {
  5178.                   isDragging = true;
  5179.                   startX = e.clientX - translateX;
  5180.                   startY = e.clientY - translateY;
  5181.                   img.style.cursor = 'grabbing';
  5182.                   e.preventDefault();
  5183.                   e.stopPropagation();
  5184.                 }
  5185.               });
  5186.               // Mousemove global pour le drag
  5187.               const handleMouseMove = (e) => {
  5188.                 if (isDragging && zoomLevel > 1) {
  5189.                   translateX = e.clientX - startX;
  5190.                   translateY = e.clientY - startY;
  5191.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  5192.                 }
  5193.               };
  5194.               // Mouseup global pour arrêter le drag
  5195.               const handleMouseUp = () => {
  5196.                 if (isDragging) {
  5197.                   isDragging = false;
  5198.                   if (zoomLevel === 1) {
  5199.                     img.style.cursor = 'zoom-in';
  5200.                   } else if (zoomLevel === 5) {
  5201.                     img.style.cursor = 'zoom-out';
  5202.                   } else {
  5203.                     img.style.cursor = 'zoom-in';
  5204.                   }
  5205.                 }
  5206.               };
  5207.               document.addEventListener('mousemove', handleMouseMove);
  5208.               document.addEventListener('mouseup', handleMouseUp);
  5209.               // Touch support pour mobile
  5210.               img.addEventListener('touchstart', (e) => {
  5211.                 if (zoomLevel > 1 && e.touches.length === 1) {
  5212.                   isDragging = true;
  5213.                   const touch = e.touches[0];
  5214.                   startX = touch.clientX - translateX;
  5215.                   startY = touch.clientY - translateY;
  5216.                   e.preventDefault();
  5217.                 }
  5218.               });
  5219.               img.addEventListener('touchmove', (e) => {
  5220.                 if (isDragging && zoomLevel > 1 && e.touches.length === 1) {
  5221.                   const touch = e.touches[0];
  5222.                   translateX = touch.clientX - startX;
  5223.                   translateY = touch.clientY - startY;
  5224.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  5225.                   e.preventDefault();
  5226.                 }
  5227.               });
  5228.               img.addEventListener('touchend', () => {
  5229.                 isDragging = false;
  5230.               });
  5231.               // Initialiser le curseur
  5232.               img.style.cursor = 'zoom-in';
  5233.             });
  5234.           }
  5235.         }
  5236.         // ⚡ OPTIMISATION MAJEURE: Sliders lazy (créés seulement quand utilisés)
  5237.         let favoritesSlider = null;
  5238.         let universalSlider = null;
  5239.         
  5240.         // Fonctions pour créer les sliders à la demande
  5241.         function getFavoritesSlider() {
  5242.           if (!favoritesSlider) {
  5243.             favoritesSlider = new FavoritesSlider();
  5244.           }
  5245.           return favoritesSlider;
  5246.         }
  5247.         
  5248.         function getUniversalSlider() {
  5249.           if (!universalSlider) {
  5250.             universalSlider = new UniversalImageSlider();
  5251.           }
  5252.           return universalSlider;
  5253.         }
  5254.         // Fonction pour voir un favori avec le slider plein écran
  5255.         function viewFavorite(id) {
  5256.           console.log('Ouverture du slider pour favori:', id);
  5257.           // ⚡ OPTIMISÉ: Utiliser le slider lazy
  5258.           const slider = getUniversalSlider();
  5259.           if (slider && slider.openFromFavorites) {
  5260.             slider.openFromFavorites(id);
  5261.           } else {
  5262.             console.error('Erreur slider favoris');
  5263.           }
  5264.         }
  5265.         // Fonction pour voir une image depuis la galerie normale
  5266.         function viewImage(imageId, clickedElement) {
  5267.           console.log('=== viewImage appelée ===');
  5268.           console.log('imageId:', imageId);
  5269.           console.log('clickedElement:', clickedElement);
  5270.           
  5271.           // Trouver le container du jour - peut être plusieurs niveaux au-dessus
  5272.           let dayContainer = clickedElement;
  5273.           
  5274.           // Remonter jusqu'à trouver un container approprié
  5275.           while (dayContainer && dayContainer !== document.body) {
  5276.             console.log('Checking element:', dayContainer.tagName, dayContainer.className, dayContainer.id);
  5277.             if (dayContainer && dayContainer.classList && (
  5278.                 dayContainer.classList.contains('dynamic-card') || 
  5279.                 dayContainer.classList.contains('collapse') ||
  5280.                 dayContainer.id && dayContainer.id.startsWith('demP')
  5281.             )) {
  5282.               break;
  5283.             }
  5284.             dayContainer = dayContainer.parentElement;
  5285.           }
  5286.           
  5287.           // ⚡ OPTIMISÉ: Logs réduits pour performance
  5288.           
  5289.           // ⚡ OPTIMISÉ: Utiliser le slider lazy
  5290.           const slider = getUniversalSlider();
  5291.           if (slider && slider.openFromGallery) {
  5292.             slider.openFromGallery(imageId, dayContainer);
  5293.           } else {
  5294.             console.error('Erreur slider galerie');
  5295.           }
  5296.         }
  5297.         // ⚡ OPTIMISÉ: Fonctions globales avec sliders lazy
  5298.         window.viewImage = viewImage;
  5299.         window.viewFavorite = viewFavorite;
  5300.         window.getUniversalSlider = getUniversalSlider; // Fonction lazy au lieu de l'instance
  5301.         // Variables globales pour éviter les ReferenceError
  5302.         if (typeof favoriteCount === 'undefined') {
  5303.           window.favoriteCount = 0;
  5304.         }
  5305.         if (typeof favButton === 'undefined') {
  5306.           window.favButton = null;
  5307.         }
  5308.         if (typeof favoriteButton === 'undefined') {
  5309.           window.favoriteButton = null;
  5310.         }
  5311.         if (typeof purchaseAlertTimeout === 'undefined') {
  5312.           window.purchaseAlertTimeout = null;
  5313.         }
  5314.         
  5315.         // Définir favoriteCount globalement pour éviter les ReferenceError
  5316.         let favoriteCount = window.favoriteCount || 0;
  5317.         // Fonction de sécurité pour vérifier les éléments DOM
  5318.         function safeAddEventListener(selector, event, callback) {
  5319.           const element = document.querySelector(selector);
  5320.           if (element) {
  5321.             element.addEventListener(event, callback);
  5322.           } else {
  5323.             console.warn(`Élément non trouvé: \${selector}`);
  5324.           }
  5325.         }
  5326.         // Fonction utilitaire pour manipuler classList de manière sécurisée
  5327.         function safeClassList(element, action, ...classes) {
  5328.           if (!element || !element.classList) {
  5329.             console.warn('Élément ou classList invalide:', element);
  5330.             return false;
  5331.           }
  5332.           
  5333.           try {
  5334.             switch(action) {
  5335.               case 'add':
  5336.                 element.classList.add(...classes);
  5337.                 break;
  5338.               case 'remove':
  5339.                 element.classList.remove(...classes);
  5340.                 break;
  5341.               case 'toggle':
  5342.                 return element.classList.toggle(classes[0], classes[1]);
  5343.               case 'contains':
  5344.                 return element.classList.contains(classes[0]);
  5345.               default:
  5346.                 console.warn('Action classList inconnue:', action);
  5347.                 return false;
  5348.             }
  5349.             return true;
  5350.           } catch (error) {
  5351.             console.warn('Erreur lors de la manipulation de classList:', error);
  5352.             return false;
  5353.           }
  5354.         }
  5355.         // Rendre la fonction utilitaire globale
  5356.         window.safeClassList = safeClassList;
  5357.         // Fonction pour sécuriser automatiquement tous les accès à classList
  5358.         function secureClassListAccess() {
  5359.           // Intercepter les erreurs classList globalement
  5360.           window.addEventListener('error', function(e) {
  5361.             if (e.message && (e.message.includes('classList') || e.message.includes('Cannot read properties of null'))) {
  5362.               console.warn('Erreur DOM interceptée et corrigée:', e.message, 'Ligne:', e.lineno, 'Fichier:', e.filename);
  5363.               e.preventDefault(); // Empêcher l'erreur de se propager
  5364.               return true;
  5365.             }
  5366.           });
  5367.           
  5368.           // Intercepter les erreurs non catchées
  5369.           window.addEventListener('unhandledrejection', function(e) {
  5370.             if (e.reason && e.reason.message && e.reason.message.includes('classList')) {
  5371.               console.warn('Promise rejection classList interceptée:', e.reason.message);
  5372.               e.preventDefault();
  5373.               return true;
  5374.             }
  5375.           });
  5376.           
  5377.           console.log('Système de sécurisation DOM/classList activé');
  5378.         }
  5379.         // Activer la sécurisation
  5380.         secureClassListAccess();
  5381.         // Fonction de diagnostic pour vérifier l'affichage du slider
  5382.         function diagnoseSliderDisplay(sliderId) {
  5383.           const slider = document.querySelector(sliderId);
  5384.           if (!slider) {
  5385.             console.error('Diagnostic: Slider non trouvé -', sliderId);
  5386.             return false;
  5387.           }
  5388.           
  5389.           const styles = window.getComputedStyle(slider);
  5390.           const rect = slider.getBoundingClientRect();
  5391.           
  5392.           console.log('=== DIAGNOSTIC SLIDER ===', sliderId);
  5393.           console.log('Élément présent:', !!slider);
  5394.           console.log('Styles calculés:', {
  5395.             display: styles.display,
  5396.             opacity: styles.opacity,
  5397.             visibility: styles.visibility,
  5398.             zIndex: styles.zIndex,
  5399.             position: styles.position
  5400.           });
  5401.           console.log('Position/Taille:', rect);
  5402.           console.log('Dans le viewport:', rect.width > 0 && rect.height > 0);
  5403.           console.log('Parent:', slider.parentElement?.tagName);
  5404.           
  5405.           // Vérifier les règles CSS qui pourraient masquer le slider
  5406.           const hiddenReasons = [];
  5407.           if (styles.display === 'none') hiddenReasons.push('display: none');
  5408.           if (styles.opacity === '0') hiddenReasons.push('opacity: 0');
  5409.           if (styles.visibility === 'hidden') hiddenReasons.push('visibility: hidden');
  5410.           if (parseInt(styles.zIndex) < 0) hiddenReasons.push('z-index négatif');
  5411.           
  5412.           if (hiddenReasons.length > 0) {
  5413.             console.warn('Raisons du masquage:', hiddenReasons);
  5414.             
  5415.             // Forcer l'affichage
  5416.             console.log('Forçage de l\\'affichage...');
  5417.             slider.style.display = 'flex';
  5418.             slider.style.opacity = '1';
  5419.             slider.style.visibility = 'visible';
  5420.             slider.style.zIndex = '9999';
  5421.             slider.style.position = 'fixed';
  5422.             slider.style.top = '0';
  5423.             slider.style.left = '0';
  5424.             slider.style.width = '100%';
  5425.             slider.style.height = '100%';
  5426.             
  5427.             console.log('Slider forcé visible');
  5428.           } else {
  5429.             console.log('✅ Slider devrait être visible');
  5430.           }
  5431.           
  5432.           return true;
  5433.         }
  5434.         // Rendre la fonction globale
  5435.         window.diagnoseSliderDisplay = diagnoseSliderDisplay;
  5436.         // Fonction de sécurité pour checkFavorites
  5437.         function checkFavorites() {
  5438.           try {
  5439.             let count = 0;
  5440.             if (typeof getFavoriteItems === 'function') {
  5441.               count = getFavoriteItems().length;
  5442.             } else {
  5443.               // Fallback : compter depuis le DOM
  5444.               const giftCount = document.getElementById('giftCount');
  5445.               if (giftCount && giftCount.textContent) {
  5446.                 count = parseInt(giftCount.textContent.trim()) || 0;
  5447.               }
  5448.             }
  5449.             
  5450.             // Mettre à jour les variables globales
  5451.             window.favoriteCount = count;
  5452.             favoriteCount = count;
  5453.             
  5454.             console.log('Favoris vérifiés:', count);
  5455.             return count;
  5456.           } catch (error) {
  5457.             console.warn('Erreur lors de la vérification des favoris:', error);
  5458.             return 0;
  5459.           }
  5460.         }
  5461.         // Rendre checkFavorites globale si elle n'existe pas
  5462.         if (typeof window.checkFavorites === 'undefined') {
  5463.           window.checkFavorites = checkFavorites;
  5464.         }
  5465.         // Initialisation sécurisée après chargement du DOM
  5466.         document.addEventListener('DOMContentLoaded', function() {
  5467.           console.log('=== DOM chargé, initialisation des sliders ===');
  5468.           console.log('viewImage disponible:', typeof window.viewImage);
  5469.           console.log('viewFavorite disponible:', typeof window.viewFavorite);
  5470.           console.log('universalSlider disponible:', typeof window.universalSlider);
  5471.           
  5472.           // Vérifier que les éléments critiques existent
  5473.           const criticalElements = [
  5474.             'filtre_photos_voir',
  5475.             // Ajoutez d'autres IDs critiques ici si nécessaire
  5476.           ];
  5477.           
  5478.           criticalElements.forEach(id => {
  5479.             const element = document.getElementById(id);
  5480.             if (element) {
  5481.               console.log(`✓ Élément trouvé: \${id}`);
  5482.             } else {
  5483.               console.warn(`⚠ Élément manquant: \${id}`);
  5484.             }
  5485.           });
  5486.           
  5487.           // Initialiser checkFavorites si la fonction existe
  5488.           if (typeof window.checkFavorites === 'function') {
  5489.             window.checkFavorites();
  5490.           }
  5491.         });
  5492.       
  5493.         // Fonction pour obtenir l'image d'un produit selon son type
  5494.         function getProductImage(productId) {
  5495.           const productImages = {
  5496.             'album': '/images/produit/Album5sur5-3.jpg',
  5497.             'digital': '/images/produit/photoNumerique.jpg', 
  5498.             'prints': '/images/produit/PochettePhoto5sur5-2.jpg',
  5499.             'calendrier': '/images/produit/Calendrier5sur5-1.jpg',
  5500.             'livre': '/images/produit/LivreSouvenir5sur5-1.jpg',
  5501.             'coffret': '/images/produit/CoffretCadeau5sur5-2.jpg',
  5502.             'retro': '/images/produit/PochetteRetro5sur5-1.jpg'
  5503.           };
  5504.           
  5505.           return productImages[productId] || '/images/produit/albumm.PNG';
  5506.         }
  5507.         
  5508.         // Fonction pour générer les suggestions de produits (synchronisées avec ecommerce-sidebar)
  5509.         // 🗑️ SUPPRIMÉ : generateProductSuggestions() - remplacé par le sidebar e-commerce
  5510.         // Le sidebar e-commerce (sidebar-ecommerce-pro.js) gère maintenant tous les produits
  5511.         // de manière centralisée et dynamique
  5512.         // Fonction pour obtenir le nombre actuel de favoris
  5513.         function getCurrentFavoriteCount() {
  5514.           return getFavoriteItems().length;
  5515.         }
  5516.         // 🎯 SUPPRIMÉ: Fonction dupliquée - la vraie est dans parent-toasts.js
  5517.         // Cette fonction était en conflit avec updateProductSuggestions() de parent-toasts.js
  5518.         // qui gère déjà les mises à jour dynamiques avec dates et contexte
  5519.         
  5520.         // Fonction legacy pour compatibilité (redirige vers parent-toasts.js)
  5521.         window.updateProductSuggestionsLive = function(favoriteCount) {
  5522.           console.log('[Legacy] updateProductSuggestionsLive appelé, redirection vers parent-toasts.js');
  5523.           // La vraie logique est dans parent-toasts.js > updateProductSuggestions()
  5524.           // qui est appelée automatiquement par le MutationObserver
  5525.         }
  5526.         // Gestion du localStorage pour l'indicateur \"nouveau contenu\"
  5527.         const lastVisitKey = 'lastVisitISO';
  5528.         const currentVisit = new Date().toISOString();
  5529.         
  5530.         // Sauvegarder la visite actuelle
  5531.         localStorage.setItem(lastVisitKey, currentVisit);
  5532.         
  5533.         // Vérifier et marquer les jours avec nouveau contenu
  5534.         const dateCards = document.querySelectorAll('.date-card.modern-card');
  5535.         dateCards.forEach(card => {
  5536.           // Ici vous devriez comparer avec updatedAt du backend
  5537.           // Pour l'instant, on simule avec un attribut data-updated
  5538.           const updatedAt = card.getAttribute('data-updated');
  5539.           if (updatedAt) {
  5540.             const lastVisit = localStorage.getItem(lastVisitKey);
  5541.             if (new Date(updatedAt) > new Date(lastVisit)) {
  5542.               if (card && card.classList) {
  5543.                 card.classList.add('has-new-content');
  5544.               }
  5545.               // Ajouter le badge \"nouveau\" si pas déjà présent
  5546.               if (!card.querySelector('.badge-new')) {
  5547.                 const badge = document.createElement('span');
  5548.                 badge.className = 'badge-new';
  5549.                 badge.setAttribute('aria-label', 'Nouveau contenu');
  5550.                 card.querySelector('.title-line').appendChild(badge);
  5551.               }
  5552.             }
  5553.           }
  5554.         });
  5555.         // Gestion des aria-label dynamiques pour les cartes de jours
  5556.         dateCards.forEach(card => {
  5557.           const dayText = card.querySelector('.day').textContent.trim();
  5558.           const dateText = card.querySelector('.full-date').textContent.trim();
  5559.           const photos = card.querySelector('.media-list-horizontal li:nth-child(1)')?.textContent.trim() || '0';
  5560.           const audios = card.querySelector('.media-list-horizontal li:nth-child(2)')?.textContent.trim() || '0';
  5561.           const videos = card.querySelector('.media-list-horizontal li:nth-child(3)')?.textContent.trim() || '0';
  5562.           
  5563.           const ariaLabel = `Contenu du \${dateText} : \${photos} photos, \${audios} audios, \${videos} vidéos`;
  5564.           card.setAttribute('aria-label', ariaLabel);
  5565.         });
  5566.       });
  5567.     </script>
  5568.     
  5569.     <!-- Make sure we're showing the right content by default if no valid content is marked 'show' -->
  5570.     ";
  5571.         // line 5176
  5572.         if (((isset($context["lastValidIndex"]) || array_key_exists("lastValidIndex"$context) ? $context["lastValidIndex"] : (function () { throw new RuntimeError('Variable "lastValidIndex" does not exist.'5176$this->source); })()) > 0)) {
  5573.             // line 5177
  5574.             yield "    <script>
  5575.       document.addEventListener('DOMContentLoaded', function() {
  5576.         // Check if no content is showing
  5577.         if (document.querySelectorAll('.container--gallery .collapse.show').length === 0) {
  5578.           // Show the content for the last valid date
  5579.           var lastValidContent = document.getElementById('demP";
  5580.             // line 5182
  5581.             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.'5182$this->source); })()), "html"nulltrue);
  5582.             yield "');
  5583.           if (lastValidContent) {
  5584.             if (lastValidContent.classList) {
  5585.               lastValidContent.classList.add('show');
  5586.             }
  5587.             
  5588.             // Also mark the corresponding date card as active
  5589.             var dateCards = document.querySelectorAll('.date-card');
  5590.             if (dateCards.length >= ";
  5591.             // line 5190
  5592.             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.'5190$this->source); })()), "html"nulltrue);
  5593.             yield ") {
  5594.               dateCards.forEach(card => {
  5595.                 if (card && card.classList) {
  5596.                   card.classList.remove('active');
  5597.                 }
  5598.               });
  5599.               const targetCard = dateCards[";
  5600.             // line 5196
  5601.             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.'5196$this->source); })()) - 1), "html"nulltrue);
  5602.             yield "];
  5603.               if (targetCard && targetCard.classList) {
  5604.                 targetCard.classList.add('active');
  5605.               }
  5606.             }
  5607.           }
  5608.         }
  5609.       });
  5610.     </script>
  5611.     ";
  5612.         }
  5613.         // line 5206
  5614.         yield "  </div>
  5615. </div>
  5616.   ";
  5617.         
  5618.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  5619.         
  5620.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  5621.         yield from [];
  5622.     }
  5623.     // line 5209
  5624.     /**
  5625.      * @return iterable<null|scalar|\Stringable>
  5626.      */
  5627.     public function block_Javascript(array $context, array $blocks = []): iterable
  5628.     {
  5629.         $macros $this->macros;
  5630.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  5631.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""Javascript"));
  5632.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  5633.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""Javascript"));
  5634.         // line 5210
  5635.         yield "  ";
  5636.         yield from $this->yieldParentBlock("Javascript"$context$blocks);
  5637.         yield "
  5638.   <script>// Gestion de la sidebar des favoris
  5639. document.addEventListener('DOMContentLoaded', function() {
  5640.     const sidebar = document.getElementById('favorites-sidebar');
  5641.     const openBtn = document.getElementById('openFavoritesSidebar');
  5642.     const closeBtn = document.querySelector('.favorites-close');
  5643.     const giftButton = document.querySelector('.gift-button');
  5644.     function openSidebar() {
  5645.         if (sidebar && sidebar.classList) {
  5646.           sidebar.classList.add('active');
  5647.           updateFavoritesSidebar();
  5648.         }
  5649.     }
  5650.     function closeSidebar() {
  5651.         if (sidebar && sidebar.classList) {
  5652.           sidebar.classList.remove('active');
  5653.         }
  5654.     }
  5655.     function updateFavoritesSidebar() {
  5656.         const grid = document.getElementById('favorites-grid');
  5657.         const counter = document.getElementById('favorites-counter');
  5658.         const emptyState = document.getElementById('favorites-empty-state');
  5659.         const progress = document.getElementById('favorites-progress');
  5660.         
  5661.         const mesFavCount = document.getElementById('mesFavCount');
  5662.         const count = mesFavCount ? getFavorisCount() : 0;
  5663.         counter.textContent = count;
  5664.         
  5665.         if (count === 0) {
  5666.             emptyState.style.display = 'flex';
  5667.             grid.style.display = 'none';
  5668.         } else {
  5669.             emptyState.style.display = 'none';
  5670.             grid.style.display = 'grid';
  5671.             const percentage = (count / 20) * 100;
  5672.             progress.style.width = `\${percentage}%`;
  5673.         }
  5674.     }
  5675.     if (openBtn) {
  5676.         openBtn.addEventListener('click', openSidebar);
  5677.     }
  5678.     if (favButton) {
  5679.         favButton.addEventListener('click', openSidebar);
  5680.     }
  5681.     if (closeBtn) {
  5682.         closeBtn.addEventListener('click', closeSidebar);
  5683.     }
  5684.     document.addEventListener('click', (e) => {
  5685.         if (sidebar && sidebar.classList && sidebar.classList.contains('active') && 
  5686.             !sidebar.contains(e.target) && 
  5687.             (!favButton || !favButton.contains(e.target)) && 
  5688.             (!openBtn || !openBtn.contains(e.target))) {
  5689.             closeSidebar();
  5690.         }
  5691.     });
  5692. });
  5693. // Modification des fonctions existantes
  5694. const originalAddFavoris = window.AddFavoris;
  5695. window.AddFavoris = function(\$id, \$idSejour, \$urlimg, \$description) {
  5696.     if (originalAddFavoris) {
  5697.         originalAddFavoris(\$id, \$idSejour, \$urlimg, \$description);
  5698.     }
  5699.     
  5700.   
  5701.     
  5702.     // Vérifier si la sidebar est ouverte - noter que nous vérifions la valeur CSS right: 0
  5703.     if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  5704.         // Recharger les favoris
  5705.         loadFavorites();
  5706.     }
  5707. };
  5708. const originalSupprimerFavoris = window.supprimerFavoris;
  5709. window.supprimerFavoris = function(\$id, \$idSejour) {
  5710.     if (originalSupprimerFavoris) {
  5711.         originalSupprimerFavoris(\$id, \$idSejour);
  5712.     }
  5713.     
  5714.     // Mettre à jour tous les compteurs de favoris
  5715.     updateAllFavoriteCounters();
  5716.     
  5717.     // Vérifier si la sidebar est ouverte
  5718.     if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  5719.         // Recharger les favoris
  5720.         loadFavorites();
  5721.     }
  5722. };
  5723. // Variables globales
  5724. let selectedFavorites = [];
  5725. let allFavorites = [];
  5726. // Fonction pour mettre à jour la sidebar
  5727. function loadFavorites() {
  5728.     \$(\"#favorites-grid\").html(\"<div style='text-align:center;padding:20px;'>Chargement...</div>\");
  5729.     
  5730.     \$.ajax({
  5731.         url: \"/Parent/mes-favoris\",
  5732.         type: \"GET\",
  5733.         dataType: \"json\",
  5734.         success: function(data) {
  5735.             \$(\"#favorites-grid\").empty();
  5736.             allFavorites = data.data || [];
  5737.             
  5738.             if (allFavorites.length > 0) {
  5739.                 \$(\"#favorites-empty-state\").hide();
  5740.                 
  5741.                 \$.each(allFavorites, function(i, fav) {
  5742.                     var isSelected = selectedFavorites.includes(fav.id);
  5743.                     
  5744.                     var item = \$(\"<div class='favorite-item' style='position:relative;border-radius:8px;overflow:hidden;aspect-ratio:1;cursor:pointer;'></div>\");
  5745.                     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\");
  5746.                     
  5747.                     // Overlay de sélection
  5748.                     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>\");
  5749.                     
  5750.                     // Icône de sélection
  5751.                     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>\");
  5752.                     if (isSelected) {
  5753.                         checkIcon.append(\"<i class='bi bi-check' style='color:white;font-size:16px;'></i>\");
  5754.                     }
  5755.                     
  5756.                     selectionOverlay.append(checkIcon);
  5757.                     
  5758.                     // Overlay d'action (bouton supprimer)
  5759.                     var actionOverlay = \$(\"<div class='action-overlay' style='position:absolute;top:5px;right:5px;opacity:0;transition:opacity 0.2s;'></div>\");
  5760.                   
  5761.                     actionOverlay.append(deleteBtn);
  5762.                     
  5763.                     // Ajouter les événements
  5764.                     item.hover(
  5765.                         function() { \$(this).find(\".action-overlay\").css(\"opacity\", \"1\"); },
  5766.                         function() { \$(this).find(\".action-overlay\").css(\"opacity\", \"0\"); }
  5767.                     );
  5768.                     
  5769.                     item.click(function() {
  5770.                         toggleSelection(fav.id, \$(this).find(\".selection-overlay > div\"));
  5771.                     });
  5772.                     
  5773.                     item.append(img).append(selectionOverlay).append(actionOverlay);
  5774.                     \$(\"#favorites-grid\").append(item);
  5775.                 });
  5776.                 
  5777.                 \$(\"#favorites-counter\").text(allFavorites.length);
  5778.                 
  5779.                 // Mettre à jour le compteur sur le bouton également
  5780.                 \$(\"#openFavoritesSidebar span\").text(allFavorites.length);
  5781.                 
  5782.                 // Mettre à jour l'interface produits
  5783.                 updateProductsView();
  5784.                 
  5785.             } else {
  5786.                 \$(\"#favorites-empty-state\").show();
  5787.                 \$(\"#favorites-counter\").text(\"0\");
  5788.                 \$(\"#openFavoritesSidebar span\").text(\"0\");
  5789.                 \$(\"#selection-count\").text(\"0\");
  5790.                 updateProductsView();
  5791.             }
  5792.         },
  5793.         error: function() {
  5794.             \$(\"#favorites-grid\").html(\"<div style='color:red;text-align:center;padding:20px;'>Erreur de chargement</div>\");
  5795.         }
  5796.     });
  5797. }
  5798. // Fonction pour supprimer un favori
  5799. function removeFavorite(id) {
  5800.     \$.ajax({
  5801.         url: \"/Parent/remove-favorite/\" + id,
  5802.         type: \"POST\",
  5803.         success: function() {
  5804.             // Retirer de la sélection si présent
  5805.             selectedFavorites = selectedFavorites.filter(favId => favId != id);
  5806.             
  5807.             // Mettre à jour le compteur de sélection
  5808.             \$(\"#selection-count\").text(selectedFavorites.length);
  5809.             
  5810.             // Recharger les favoris
  5811.             loadFavorites();
  5812.             
  5813.             // Mettre à jour tous les compteurs de favoris
  5814.             updateAllFavoriteCounters();
  5815.             
  5816.             // Mettre à jour l'interface produits
  5817.             updateProductsView();
  5818.         },
  5819.         error: function() {
  5820.             alert(\"Erreur lors de la suppression du favori\");
  5821.         }
  5822.     });
  5823. }
  5824. // Fonction pour basculer la sélection d'une photo
  5825. function toggleSelection(id, checkElement) {
  5826.     const index = selectedFavorites.indexOf(id);
  5827.     
  5828.     if (index === -1) {
  5829.         // Ajouter à la sélection
  5830.         selectedFavorites.push(id);
  5831.         checkElement.css(\"background\", \"#F56040\");
  5832.         checkElement.html(\"<i class='bi bi-check' style='color:white;font-size:16px;'></i>\");
  5833.     } else {
  5834.         // Retirer de la sélection
  5835.         selectedFavorites.splice(index, 1);
  5836.         checkElement.css(\"background\", \"transparent\");
  5837.         checkElement.html(\"\");
  5838.     }
  5839.     
  5840.     // Mettre à jour le compteur
  5841.     \$(\"#selection-count\").text(selectedFavorites.length);
  5842.     
  5843.     // Mettre à jour l'interface produits
  5844.     updateProductsView();
  5845. }
  5846. // Fonction pour mettre à jour la vue des produits
  5847. function updateProductsView() {
  5848.     const current = selectedFavorites.length;
  5849.     \$(\"#product-photo-count\").text(current);
  5850.     
  5851.     let remainingForAlbum = Math.max(0, 20 - current);
  5852.     let remainingForPochette = Math.max(0, 12 - current);
  5853.     let remainingForPack = Math.max(0, 12 - current);
  5854.     const progressBar = (count, total, color) => `
  5855.         <div style=\"margin: 5px 0;\">
  5856.             <div style=\"background-color: #e9ecef; border-radius: 5px; overflow: hidden; height: 8px;\">
  5857.                 <div style=\"width: \${(count / total) * 100}%; background-color: \${color}; height: 100%;\"></div>
  5858.             </div>
  5859.             <small style=\"font-size: 12px;\">\${count}/\${total} photos</small>
  5860.         </div>
  5861.     `;
  5862.     // Liste des produits
  5863.     const products = [
  5864.         {
  5865.             name: \"Pack numérique (20 photos)\",
  5866.             required: 20,
  5867.             remaining: Math.max(0, 20 - current),
  5868.             image: \"/images/produit/photoNumerique.jpg\",
  5869.             color: \"#4caf50\",
  5870.             link: \"";
  5871.         // line 5458
  5872.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("PackPhotosNumerique_Favoris", ["nbr" => 20]);
  5873.         yield "\",
  5874.         },
  5875.        +
  5876.         {
  5877.             name: \"Pochette photo (12 photos)\",
  5878.             required: 12,
  5879.             remaining: Math.max(0, 12 - current),
  5880.             image: \"/images/produit/PochettePhoto5sur5-2.jpg\",
  5881.             color: \"#2196f3\",
  5882.             link: \"";
  5883.         // line 5467
  5884.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("AjoutPochettePhotos_Favoris", ["nbr" => 12]);
  5885.         yield "\",
  5886.         },
  5887.     ].sort((a, b) => a.remaining - b.remaining);
  5888.     const productList = products
  5889.         .map((product) => {
  5890.             const count = current;
  5891.             const total = product.required;
  5892.             const remaining = product.remaining;
  5893.             return `
  5894.                 <li style=\"margin-bottom: 20px;\">
  5895.                     <div style=\"display: flex; align-items: center; gap: 10px;\">
  5896.                         <img src=\"\${product.image}\" alt=\"\${product.name}\" style=\"width: 70px; height: 70px; border-radius: 5px; object-fit: cover;\" />
  5897.                         <div style=\"flex: 1;\">
  5898.                             <strong style=\"font-size: 14px;\">\${product.name}</strong>
  5899.                             \${progressBar(count, total, product.color)}
  5900.                             \${
  5901.                                 `<small style=\"color: \${product.color}; font-size: 12px;\">
  5902.                                     Encore \${remaining} photos pour compléter \${product.name.toLowerCase()}
  5903.                                 </small>
  5904.                                 <button
  5905.                                     style=\"
  5906.                                         margin-top: 5px;
  5907.                                         padding: 6px 12px;
  5908.                                         background-color: \${product.color};
  5909.                                         color: white;
  5910.                                         border: none;
  5911.                                         border-radius: 5px;
  5912.                                         font-size: 13px;
  5913.                                         cursor: pointer;
  5914.                                     \"
  5915.                                     onclick=\"window.location.href='\${product.link}'\"
  5916.                                 >
  5917.                                     Commander
  5918.                                 </button>`
  5919.                             }
  5920.                         </div>
  5921.                     </div>
  5922.                 </li>
  5923.             `;
  5924.         })
  5925.         .join(\"\");
  5926.     const boutiqueButton = `
  5927.         <li style=\"margin-top: 25px; text-align: center;\">
  5928.             <button
  5929.                 style=\"
  5930.                     padding: 8px 15px;
  5931.                     background-color: #F56040;
  5932.                     color: white;
  5933.                     border: none;
  5934.                     border-radius: 5px;
  5935.                     font-size: 14px;
  5936.                     width: 170px;
  5937.                     height: 40px;
  5938.                     cursor: pointer;
  5939.                 \"
  5940.                 onclick=\"window.location.href='";
  5941.         // line 5525
  5942.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("boutique5sur5");
  5943.         yield "'\"
  5944.             >
  5945.                 Voir toute la boutique
  5946.             </button>
  5947.         </li>
  5948.     `;
  5949.     \$(\"#product-list\").html(productList + boutiqueButton);
  5950. }
  5951. // Modifications au script existant
  5952. \$(document).ready(function() {
  5953.     // Fonctions pour ouvrir/fermer la sidebar
  5954.     \$(\"#openFavoritesSidebar\").click(function() {
  5955.         \$(\"#favorites-sidebar\").css(\"right\", \"0\");
  5956.         loadFavorites();
  5957.     });
  5958.     
  5959.     \$(\"#close-favorites-btn\").click(function() {
  5960.         closeFavoritesSidebar();
  5961.     });
  5962.     
  5963.     // Fonction pour fermer la sidebar
  5964.     window.closeFavoritesSidebar = function() {
  5965.         \$(\"#favorites-sidebar\").css(\"right\", \"-500px\");
  5966.     };
  5967.     
  5968.     // Tout sélectionner / Tout désélectionner
  5969.     \$(\"#select-all-btn\").click(function() {
  5970.         if (selectedFavorites.length === allFavorites.length) {
  5971.             // Tout désélectionner
  5972.             selectedFavorites = [];
  5973.             \$(\".selection-overlay > div\").css(\"background\", \"transparent\").html(\"\");
  5974.             \$(this).text(\"Tout sélectionner\");
  5975.         } else {
  5976.             // Tout sélectionner
  5977.             selectedFavorites = allFavorites.map(fav => fav.id);
  5978.             \$(\".selection-overlay > div\").css(\"background\", \"#F56040\").html(\"<i class='bi bi-check' style='color:white;font-size:16px;'></i>\");
  5979.             \$(this).text(\"Tout désélectionner\");
  5980.         }
  5981.         
  5982.         // Mettre à jour le compteur
  5983.         \$(\"#selection-count\").text(selectedFavorites.length);
  5984.         
  5985.         // Mettre à jour l'interface produits
  5986.         updateProductsView();
  5987.     });
  5988.     
  5989.     // Gestion des onglets
  5990.     \$(\".sidebar-tab\").click(function() {
  5991.         \$(\".sidebar-tab\").removeClass(\"active\").css({
  5992.             \"color\": \"#666\",
  5993.             \"border-bottom\": \"none\"
  5994.         });
  5995.         \$(this).addClass(\"active\").css({
  5996.             \"color\": \"#F56040\",
  5997.             \"border-bottom\": \"2px solid #F56040\"
  5998.         });
  5999.         
  6000.         const tabId = \$(this).attr(\"id\");
  6001.         \$(\".tab-content\").hide();
  6002.         
  6003.         if (tabId === \"tab-photos\") {
  6004.             \$(\"#photos-content\").show();
  6005.         } else if (tabId === \"tab-products\") {
  6006.             \$(\"#products-content\").show();
  6007.         }
  6008.     });
  6009.     
  6010.     // Modifier les fonctions existantes pour intercepter l'ajout/suppression de favoris
  6011.     const originalAddFavoris = window.AddFavoris;
  6012.     window.AddFavoris = function(\$id, \$idSejour, \$urlimg, \$description) {
  6013.         if (originalAddFavoris) {
  6014.             originalAddFavoris(\$id, \$idSejour, \$urlimg, \$description);
  6015.         }
  6016.         
  6017.         // Mettre à jour tous les compteurs de favoris
  6018.         updateAllFavoriteCounters();
  6019.         
  6020.         // Recharger les favoris si la sidebar est ouverte
  6021.         if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  6022.             loadFavorites();
  6023.         }
  6024.     };
  6025.     const originalSupprimerFavoris = window.supprimerFavoris;
  6026.     window.supprimerFavoris = function(\$id, \$idSejour) {
  6027.         if (originalSupprimerFavoris) {
  6028.             originalSupprimerFavoris(\$id, \$idSejour);
  6029.         }
  6030.         
  6031.         // Mettre à jour tous les compteurs de favoris
  6032.         updateAllFavoriteCounters();
  6033.         
  6034.         // Recharger les favoris si la sidebar est ouverte
  6035.         if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  6036.             // Retirer de la sélection si présent
  6037.             selectedFavorites = selectedFavorites.filter(favId => favId != \$id);
  6038.             loadFavorites();
  6039.         }
  6040.     };
  6041.     
  6042.     // Fermer en cliquant en dehors
  6043.     \$(document).click(function(event) {
  6044.         if (!\$(event.target).closest(\"#favorites-sidebar\").length && 
  6045.             !\$(event.target).closest(\"#openFavoritesSidebar\").length && 
  6046.             \$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  6047.             closeFavoritesSidebar();
  6048.         }
  6049.     });
  6050. });
  6051. // Initialisation de la sidebar
  6052. \$(document).ready(function() {
  6053.     // Fonctions pour ouvrir/fermer la sidebar
  6054.     \$(\"#openFavoritesSidebar\").click(function() {
  6055.         \$(\"#favorites-sidebar\").css(\"right\", \"0\");
  6056.         loadFavorites();
  6057.     });
  6058.     
  6059.     \$(\"#close-favorites-btn\").click(function() {
  6060.         \$(\"#favorites-sidebar\").css(\"right\", \"-500px\");
  6061.     });
  6062.     
  6063.     // Fermer en cliquant en dehors
  6064.     \$(document).click(function(event) {
  6065.         if (!\$(event.target).closest(\"#favorites-sidebar\").length && 
  6066.             !\$(event.target).closest(\"#openFavoritesSidebar\").length && 
  6067.             \$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  6068.             \$(\"#favorites-sidebar\").css(\"right\", \"-500px\");
  6069.         }
  6070.     });
  6071. });
  6072.   </script>
  6073.   <script src=\"";
  6074.         // line 5658
  6075.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("js/splide.min.js"), "html"nulltrue);
  6076.         yield "\" defer></script>
  6077.    
  6078. <script>
  6079.   document.addEventListener('DOMContentLoaded', function () {
  6080.     const openBtn = document.getElementById('openFavoritesSidebar');
  6081.     const sidebar = document.getElementById('favorites-sidebar');
  6082.     const closeBtn = document.getElementById('favorites-close');
  6083.     if (openBtn && sidebar) {
  6084.       openBtn.addEventListener('click', () => {
  6085.         if (sidebar && sidebar.classList) {
  6086.           sidebar.classList.add('active');
  6087.         }
  6088.       });
  6089.     }
  6090.     if (closeBtn && sidebar) {
  6091.       closeBtn.addEventListener('click', () => {
  6092.         if (sidebar && sidebar.classList) {
  6093.           sidebar.classList.remove('active');
  6094.         }
  6095.       });
  6096.     }
  6097.   });
  6098. </script>
  6099.  
  6100. <script>
  6101. document.addEventListener('DOMContentLoaded', function() {
  6102.   const filterBadges = document.querySelectorAll('.filter-badge');
  6103.   filterBadges.forEach(badge => {
  6104.     badge.addEventListener('click', function() {
  6105.       // Désactiver tous les badges
  6106.       filterBadges.forEach(b => {
  6107.         if (b && b.classList) {
  6108.           b.classList.remove('active');
  6109.         }
  6110.       });
  6111.       // Activer le badge cliqué
  6112.       if (this && this.classList) {
  6113.         this.classList.add('active');
  6114.       }
  6115.     });
  6116.   });
  6117. });
  6118. </script>
  6119.   <script
  6120.     type=\"text/javascript\"
  6121.     src=\"";
  6122.         // line 5711
  6123.         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);
  6124.         yield "\"
  6125.   ></script>
  6126.   <script>
  6127. document.addEventListener('DOMContentLoaded', function () {
  6128.   const prevButtons = document.querySelectorAll('.btn-prev-day');
  6129.   const nextButtons = document.querySelectorAll('.btn-next-day');
  6130.   const dateCards = document.querySelectorAll('.date-card.modern-card');
  6131.   const collapseSections = document.querySelectorAll('.collapse');
  6132.   // 🎯 MEDIA TOOLBAR CAPSULE - État global et logique (Senior UX)
  6133.   (() => {
  6134.     // État global de filtre
  6135.     const MediaFilter = { current: 'all' };
  6136.     // Compteurs dynamiques
  6137.     const counters = { photo: 0, audio: 0, video: 0, fav: 0 };
  6138.     
  6139.     const updateCounts = () => {
  6140.       // Compter les médias dans le DOM
  6141.       counters.photo = document.querySelectorAll('.photo-item, [data-media-type=\"photo\"]').length;
  6142.       counters.video = document.querySelectorAll('[data-media-type=\"video\"]').length;
  6143.       counters.audio = document.querySelectorAll('.audio-message-item[data-type=\"audio\"]').length;
  6144.       // NE PAS recalculer seulement les favoris - ils utilisent ";
  6145.         // line 5733
  6146.         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.'5733$this->source); })()), "html"nulltrue);
  6147.         yield "
  6148.       
  6149.       // Mettre à jour l'affichage (sauf favoris)
  6150.       Object.entries(counters).forEach(([k, v]) => {
  6151.         if (k !== 'fav') { // Garder seulement le compteur favoris intact
  6152.           document.querySelectorAll(`.mtb-count[data-bind=\"\${k}\"]`).forEach(el => el.textContent = v);
  6153.         }
  6154.       });
  6155.     };
  6156.     // Simple fonction pour le filtre actuel
  6157.     function setActive(filter) {
  6158.       MediaFilter.current = filter;
  6159.       
  6160.       // Exception : ne pas ajouter de classe active au bouton photos
  6161.       if (filter === 'photos') {
  6162.         const photosBtn = document.querySelector('.mtb-btn[data-filter=\"photos\"]');
  6163.         if (photosBtn) {
  6164.           photosBtn.classList.remove('active', 'is-active');
  6165.         }
  6166.       }
  6167.     }
  6168.     // Fonction simplifiée qui mappe et appelle filterContent
  6169.     function applyFilter(filter) {
  6170.       // Mapper les filtres de la capsule vers les filtres existants si nécessaire
  6171.       const filterMap = {
  6172.         'all': 'toutVoir',
  6173.         'photos': 'photos', 
  6174.         'audio': 'audio',
  6175.         'videos': 'videos',
  6176.         'favoris': 'favoris'
  6177.       };
  6178.       
  6179.       const mappedFilter = filterMap[filter] || filter;
  6180.       
  6181.       // Pour le filtre \"all\", s'assurer que la vue des jours est restaurée
  6182.       if (filter === 'all') {
  6183.         const containerGallery = document.querySelector('.container--gallery');
  6184.         if (containerGallery) {
  6185.           containerGallery.style.display = 'block';
  6186.         }
  6187.       }
  6188.       
  6189.       if (typeof window.filterContent === 'function') {
  6190.         window.filterContent(mappedFilter);
  6191.       } else {
  6192.         console.error('window.filterContent n\\'est pas disponible');
  6193.       }
  6194.     }
  6195.     // Click handlers - exactement la même logique que stat-pill
  6196.     document.addEventListener('click', (e) => {
  6197.       const btn = e.target.closest('.mtb-btn');
  6198.       if (!btn) return;
  6199.       // Bouton fermer
  6200.       if (btn.classList.contains('mtb-close')) {
  6201.         document.querySelector('.media-toolbar')?.remove();
  6202.         return;
  6203.       }
  6204.       const filter = btn.dataset.filter;
  6205.       if (!filter) return;
  6206.       // 🎯 CAS SPÉCIAL : Bouton favoris (filtre + ouvre sidebar, JAMAIS de modification du compteur)
  6207.       if (filter === 'favoris') {
  6208.         console.log('💗 BOUTON FAVORIS CLIQUÉ - Vue favoris + ouverture sidebar');
  6209.         
  6210.         // 🛡️ Protection ABSOLUE : empêcher TOUTE propagation vers d'autres handlers
  6211.         e.stopPropagation();
  6212.         e.stopImmediatePropagation();
  6213.         e.preventDefault();
  6214.         
  6215.         // 1️⃣ Activer visuellement le bouton favoris
  6216.         const mtbBtns = document.querySelectorAll('.mtb-btn[data-filter]');
  6217.         mtbBtns.forEach(b => {
  6218.           if (b === btn) {
  6219.             b.classList.add('active');
  6220.           } else {
  6221.             b.classList.remove('active');
  6222.           }
  6223.         });
  6224.         
  6225.         // 2️⃣ Filtrer la galerie pour afficher uniquement les favoris
  6226.         if (typeof window.filterContent === 'function') {
  6227.           window.filterContent('favoris');
  6228.         } else {
  6229.           console.error('❌ window.filterContent non disponible');
  6230.         }
  6231.         
  6232.         // 3️⃣ Ouvrir le sidebar e-commerce via le bouton cadeau
  6233.         const giftButton = document.getElementById('gift-button-trigger');
  6234.         if (giftButton) {
  6235.           console.log('🎁 Ouverture du sidebar via bouton cadeau');
  6236.           setTimeout(() => giftButton.click(), 100); // Petit délai pour éviter les conflits
  6237.         } else {
  6238.           console.warn('⚠️ Bouton cadeau non trouvé');
  6239.         }
  6240.         
  6241.         return; // ⛔ SORTIE IMMÉDIATE - pas de traitement supplémentaire
  6242.       }
  6243.       // 🎯 CAS SPÉCIAL : Bouton audio avec 0 message → afficher popover
  6244.       if (filter === 'audio') {
  6245.         const audioCount = btn.querySelector('.mtb-count[data-bind=\"audio\"]');
  6246.         const count = audioCount ? parseInt(audioCount.textContent.trim()) : 0;
  6247.         
  6248.         if (count === 0) {
  6249.           console.log('🎤 Bouton audio cliqué avec 0 message - affichage popover');
  6250.           
  6251.           e.stopPropagation();
  6252.           e.preventDefault();
  6253.           
  6254.           // Afficher le popover premium
  6255.           showAudioEmptyPopover(btn);
  6256.           return; // ⛔ Ne pas filtrer si 0 message
  6257.         }
  6258.       }
  6259.       // Exception pour le bouton photos : ne pas modifier les états actifs
  6260.       if (btn.dataset.filter === 'photos') {
  6261.         // Pour le bouton photos, ne pas toucher aux autres boutons
  6262.         // Juste exécuter l'action sans changer les états
  6263.       } else {
  6264.         // Pour les autres boutons : gérer les états actifs normalement
  6265.         const mtbBtns = document.querySelectorAll('.mtb-btn[data-filter]');
  6266.         for (let i = 0; i < mtbBtns.length; i++) {
  6267.           const b = mtbBtns[i];
  6268.           if (b && b.classList) {
  6269.             if (b === btn) {
  6270.               b.classList.add('active');
  6271.             } else {
  6272.               b.classList.remove('active');
  6273.             }
  6274.           }
  6275.         }
  6276.       }
  6277.       
  6278.       // Déclencher le filtrage du contenu - même logique que stat-pill
  6279.       console.log('mtb-btn click:', filter, 'filterContent type:', typeof window.filterContent);
  6280.       if (typeof window.filterContent === 'function') {
  6281.         window.filterContent(filter);
  6282.       } else {
  6283.         console.error('window.filterContent n\\'est pas une fonction!');
  6284.       }
  6285.     });
  6286.     // Expose un setter global
  6287.     window.setMediaFilter = (filter) => {
  6288.       // Pour le bouton photos : ne pas modifier les états
  6289.       if (filter !== 'photos') {
  6290.         setActive(filter);
  6291.       }
  6292.       applyFilter(filter);
  6293.     };
  6294.     // 🛡️ PROTECTION ABSOLUE : Empêcher TOUTE interaction directe avec le compteur favoris
  6295.     document.addEventListener('DOMContentLoaded', () => {
  6296.       const mesFavCount = document.getElementById('mesFavCount');
  6297.       if (mesFavCount) {
  6298.         // Bloquer tous les clics directs sur le compteur
  6299.         mesFavCount.addEventListener('click', (e) => {
  6300.           console.log('⚠️ Clic sur mesFavCount bloqué');
  6301.           e.stopPropagation();
  6302.           e.stopImmediatePropagation();
  6303.           e.preventDefault();
  6304.           return false;
  6305.         }, true); // Capture phase pour intercepter avant tout autre listener
  6306.         
  6307.         // Empêcher le double-clic
  6308.         mesFavCount.addEventListener('dblclick', (e) => {
  6309.           console.log('⚠️ Double-clic sur mesFavCount bloqué');
  6310.           e.stopPropagation();
  6311.           e.stopImmediatePropagation();
  6312.           e.preventDefault();
  6313.           return false;
  6314.         }, true);
  6315.         
  6316.         // Ajouter un style pour indiquer visuellement que c'est non-cliquable
  6317.         mesFavCount.style.pointerEvents = 'none';
  6318.         mesFavCount.style.userSelect = 'none';
  6319.         
  6320.         console.log('🛡️ Protection mesFavCount activée - compteur non-cliquable');
  6321.       }
  6322.       
  6323.       // 🎤 Initialiser l'état du bouton audio (griser si 0 message)
  6324.       initAudioButtonState();
  6325.     });
  6326.     // 🎤 Fonction pour afficher le popover \"Pas de message audio\"
  6327.     function showAudioEmptyPopover(btn) {
  6328.       // Supprimer les popovers existants
  6329.       const existingPopover = document.querySelector('.audio-empty-popover');
  6330.       if (existingPopover) {
  6331.         existingPopover.remove();
  6332.       }
  6333.       
  6334.       // Créer le popover
  6335.       const popover = document.createElement('div');
  6336.       popover.className = 'audio-empty-popover';
  6337.       popover.innerHTML = `
  6338.         <div class=\"audio-popover-content\">
  6339.           <div class=\"audio-popover-icon\">
  6340.             <i class=\"bi bi-mic-mute-fill\"></i>
  6341.           </div>
  6342.           <div class=\"audio-popover-text\">
  6343.             <strong>Aucun message audio</strong>
  6344.             <p>Pas de message audio soumis pour l'instant</p>
  6345.           </div>
  6346.         </div>
  6347.       `;
  6348.       
  6349.       // Positionner le popover
  6350.       document.body.appendChild(popover);
  6351.       
  6352.       const btnRect = btn.getBoundingClientRect();
  6353.       popover.style.position = 'fixed';
  6354.       popover.style.top = `\${btnRect.bottom + 10}px`;
  6355.       popover.style.left = `\${btnRect.left + (btnRect.width / 2)}px`;
  6356.       popover.style.transform = 'translateX(-50%)';
  6357.       
  6358.       // Animation d'entrée
  6359.       setTimeout(() => popover.classList.add('show'), 10);
  6360.       
  6361.       // Auto-fermeture après 3 secondes
  6362.       setTimeout(() => {
  6363.         popover.classList.remove('show');
  6364.         setTimeout(() => popover.remove(), 300);
  6365.       }, 3000);
  6366.       
  6367.       // Fermer au clic ailleurs
  6368.       const closeOnClick = (e) => {
  6369.         if (!popover.contains(e.target) && !btn.contains(e.target)) {
  6370.           popover.classList.remove('show');
  6371.           setTimeout(() => popover.remove(), 300);
  6372.           document.removeEventListener('click', closeOnClick);
  6373.         }
  6374.       };
  6375.       setTimeout(() => document.addEventListener('click', closeOnClick), 100);
  6376.     }
  6377.     // 🎤 Fonction pour initialiser l'état du bouton audio
  6378.     function initAudioButtonState() {
  6379.       const audioBtn = document.querySelector('.mtb-btn[data-filter=\"audio\"]');
  6380.       if (!audioBtn) return;
  6381.       
  6382.       const audioCount = audioBtn.querySelector('.mtb-count[data-bind=\"audio\"]');
  6383.       if (!audioCount) return;
  6384.       
  6385.       const count = parseInt(audioCount.textContent.trim()) || 0;
  6386.       
  6387.       if (count === 0) {
  6388.         // Masquer le compteur \"0\"
  6389.         audioCount.style.display = 'none';
  6390.         
  6391.         // Griser l'icône
  6392.         audioBtn.classList.add('disabled-audio');
  6393.         audioBtn.style.opacity = '0.4';
  6394.         audioBtn.style.cursor = 'not-allowed';
  6395.         
  6396.         const icons = audioBtn.querySelectorAll('i');
  6397.         icons.forEach(icon => {
  6398.           icon.style.color = '#999 !important';
  6399.           icon.style.filter = 'grayscale(100%)';
  6400.         });
  6401.         
  6402.         console.log('🎤 Bouton audio désactivé (0 message)');
  6403.       } else {
  6404.         // Afficher le compteur
  6405.         audioCount.style.display = 'inline';
  6406.         
  6407.         // Activer l'icône
  6408.         audioBtn.classList.remove('disabled-audio');
  6409.         audioBtn.style.opacity = '1';
  6410.         audioBtn.style.cursor = 'pointer';
  6411.         
  6412.         console.log(`🎤 Bouton audio activé (\${count} message\${count > 1 ? 's' : ''})`);
  6413.       }
  6414.     }
  6415.     // 🎤 Observer les changements du compteur audio pour mettre à jour l'état
  6416.     const audioCountObserver = new MutationObserver(() => {
  6417.       initAudioButtonState();
  6418.     });
  6419.     
  6420.     // Démarrer l'observation quand le DOM est prêt
  6421.     if (document.readyState === 'loading') {
  6422.       document.addEventListener('DOMContentLoaded', () => {
  6423.         const audioCount = document.querySelector('.mtb-count[data-bind=\"audio\"]');
  6424.         if (audioCount) {
  6425.           audioCountObserver.observe(audioCount, { 
  6426.             childList: true, 
  6427.             characterData: true, 
  6428.             subtree: true 
  6429.           });
  6430.         }
  6431.       });
  6432.     } else {
  6433.       const audioCount = document.querySelector('.mtb-count[data-bind=\"audio\"]');
  6434.       if (audioCount) {
  6435.         audioCountObserver.observe(audioCount, { 
  6436.           childList: true, 
  6437.           characterData: true, 
  6438.           subtree: true 
  6439.         });
  6440.       }
  6441.     }
  6442.     
  6443.     // Mise à jour des compteurs quand les favoris changent
  6444.     window.addEventListener('favorites:updated', updateCounts);
  6445.     
  6446.     // Initialisation
  6447.     setTimeout(() => {
  6448.       updateCounts();
  6449.       setActive('all');
  6450.     }, 100);
  6451.     // Mise à jour périodique des compteurs (sauf favoris qui reste fixe)
  6452.     setInterval(updateCounts, 2000);
  6453.   })();
  6454.   function navigateToDay(index) {
  6455.      if (index >= 0 && index < collapseSections.length) {
  6456.       // Fermer tous les jours
  6457.       collapseSections.forEach(s => {
  6458.         if (s && s.classList) {
  6459.           s.classList.remove('show');
  6460.         }
  6461.       });
  6462.       dateCards.forEach(c => {
  6463.         if (c && c.classList) {
  6464.           c.classList.remove('active');
  6465.         }
  6466.       });
  6467.       // Ouvrir le bon jour
  6468.       const targetCollapse = collapseSections[index];
  6469.       const targetCard = dateCards[index];
  6470.       if (targetCollapse && targetCard) {
  6471.         if (targetCollapse.classList) {
  6472.           targetCollapse.classList.add('show');
  6473.         }
  6474.         if (targetCard.classList) {
  6475.           targetCard.classList.add('active');
  6476.         }
  6477.       }
  6478.     }
  6479.   }
  6480.   prevButtons.forEach(button => {
  6481.     button.addEventListener('click', function () {
  6482.       const targetIndex = parseInt(this.dataset.target, 10);
  6483.       navigateToDay(targetIndex);
  6484.     });
  6485.   });
  6486.   nextButtons.forEach(button => {
  6487.     button.addEventListener('click', function () {
  6488.       const targetIndex = parseInt(this.dataset.target, 10);
  6489.       navigateToDay(targetIndex);
  6490.     });
  6491.   });
  6492. });
  6493. </script>
  6494.   <script>
  6495.     document.addEventListener('DOMContentLoaded', function() {
  6496.   const style = document.createElement('style');
  6497.   style.textContent = `
  6498.     .hidden {
  6499.       display: none !important;
  6500.     }
  6501.   `;
  6502.   document.head.appendChild(style);
  6503. });
  6504.     document.addEventListener('DOMContentLoaded', function() {
  6505.     // Get the gift button
  6506.     const giftButton = document.querySelector('.gift-button');
  6507.     if (giftButton) {
  6508.       // Keep it clickable for the gift functionality
  6509.       giftButton.style.pointerEvents = 'auto';
  6510.       
  6511.       // Add click handler for gift action
  6512.       giftButton.onclick = function(e) {
  6513.         e.preventDefault();
  6514.         e.stopPropagation();
  6515.         return false;
  6516.       };
  6517.       
  6518.       // Make sure hover still works
  6519.       favoriteButton.addEventListener('mouseover', function() {
  6520.         document.getElementById('purchase-alert').style.display = 'block';
  6521.       });
  6522.       
  6523.       // Keep any existing hover functionality
  6524.       if (typeof showSelection === 'function') {
  6525.         favoriteButton.onmouseover = showSelection;
  6526.       }
  6527.     }
  6528.     
  6529.     // Make sure the purchase alert remains interactive
  6530.     const purchaseAlert = document.getElementById('purchase-alert');
  6531.     if (purchaseAlert) {
  6532.       purchaseAlert.style.pointerEvents = 'auto';
  6533.     }
  6534.   });
  6535.     // Sélection des éléments
  6536.     const purchaseAlert = document.getElementById(\"purchase-alert\");
  6537.     const alertContent = document.getElementById(\"purchase-alert-content\");
  6538.     const likeCountLabel = document.getElementById(\"likeCount\");
  6539.     
  6540.     // Fonction pour obtenir le nombre actuel de favoris
  6541.     function getCurrentFavoriteCount() {
  6542.         const likeCountLabel = document.getElementById(\"likeCount\");
  6543.         return parseInt(likeCountLabel?.textContent.trim(), 10) || 0;
  6544.     }
  6545.     // Fonction pour mettre à jour le contenu de l'alerte
  6546.     function updatePurchaseAlert(current) {
  6547.   let remainingForAlbum = Math.max(0, 20 - current);
  6548.   let remainingForPochette = Math.max(0, 12 - current);
  6549.   let remainingForPack = Math.max(0, 12 - current);
  6550.   const progressBar = (count, total, color) => `
  6551.   <div style=\"margin: 5px 0;\">
  6552.     <div style=\"background-color: #e9ecef; border-radius: 5px; overflow: hidden; height: 8px;\">
  6553.       <div style=\"width: \${
  6554.         (count / total) * 100
  6555.       }%; background-color: \${color}; height: 100%;\"></div>
  6556.     </div>
  6557.     <small style=\"font-size: 12px;\">\${count}/\${total} photos</small>
  6558.   </div>
  6559. `;
  6560.   // Use Twig paths here:
  6561.   const products = [
  6562.       {
  6563.       name: \"Pochette photo (12 photos)\",
  6564.       required: 12,
  6565.       remaining: remainingForPochette,
  6566.       image: \"/images/produit/PochettePhoto5sur5-2.jpg\",
  6567.       color: \"#2196f3\",
  6568.       link: \"";
  6569.         // line 6179
  6570.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("AjoutPochettePhotos_Favoris", ["nbr" => 12]);
  6571.         yield "\",
  6572.     },
  6573.        {
  6574.       name: \"Pack numérique (20 photos)\",
  6575.       required: 20,
  6576.       remaining: remainingForAlbum,
  6577.       image: \"/images/produit/photoNumerique.jpg\",
  6578.       color: \"#4caf50\",
  6579.       link: \"";
  6580.         // line 6187
  6581.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("PackPhotosNumerique_Favoris", ["nbr" => 20]);
  6582.         yield "\",
  6583.     }
  6584.   
  6585.   
  6586.     
  6587.   ].sort((a, b) => a.remaining - b.remaining);
  6588.   const productList = products
  6589.     .map((product) => {
  6590.       const count = current;
  6591.       const total = product.required;
  6592.       const remaining = product.remaining;
  6593.       return `
  6594.     <li style=\"margin-bottom: 15px;\">
  6595.       <div style=\"display: flex; align-items: center; gap: 10px;\">
  6596.         <img
  6597.           src=\"\${product.image}\"
  6598.           alt=\"\${product.name}\"
  6599.           style=\"width: 65px; height: 65px; border-radius: 5px; margin-top:-19px\"
  6600.         />
  6601.         <div style=\"flex: 1;\">
  6602.           <strong style=\"font-size: 14px;\">\${product.name}</strong>
  6603.           \${progressBar(count, total, product.color)}
  6604.           \${
  6605.             remaining > 0
  6606.               ? `<small style=\"color: \${product.color}; font-size: 12px;\">
  6607.                    Encore \${remaining} photos ❤️ pour compléter \${product.name.toLowerCase()}
  6608.                  </small>`
  6609.               : `<button
  6610.                   style=\"
  6611.                     margin-top: 5px;
  6612.                     padding: 5px 8px;
  6613.                     background-color: \${product.color};
  6614.                     color: white;
  6615.                     border: none;
  6616.                     border-radius: 5px;
  6617.                     font-size: 12px;
  6618.                     cursor: pointer;
  6619.                   \"
  6620.                   onclick=\"window.location.href='\${product.link}'\"
  6621.                 >
  6622.                   Commander
  6623.                 </button>`
  6624.           }
  6625.         </div>
  6626.       </div>
  6627.     </li>
  6628.   `;
  6629.     })
  6630.     .join(\"\");
  6631.   const plusButton = `
  6632.     <li style=\"margin-bottom: 15px; text-align: center;\">
  6633.       <button
  6634.         style=\"
  6635.           padding: 5px 8px;
  6636.           background-color: #F56040;
  6637.           color: white;
  6638.           border: none;
  6639.           border-radius: 5px;
  6640.           font-size: 14px;
  6641.           line-height: 1;
  6642.           width: 150px;
  6643.           height: 40px;
  6644.           cursor: pointer;
  6645.         \"
  6646.         onclick=\"window.location.href='";
  6647.         // line 6254
  6648.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("boutique5sur5");
  6649.         yield "'\"
  6650.       >
  6651.         Aller à la boutique
  6652.       </button>
  6653.     </li>
  6654.   `;
  6655.   if (current === 0) {
  6656.     alertContent.innerHTML = `
  6657.     <p style=\"font-size: 16px; font-weight: bold; color: #333;\">
  6658.       Vous n'avez pas encore de photos favorites !
  6659.     </p>
  6660.     <p style=\"margin-bottom: 20px; color: #555;\">
  6661.       Commencez à ajouter vos moments préférés pour profiter de nos offres.
  6662.     </p>
  6663.     <ul style=\"list-style-type: none; padding: 0;\">\${productList}\${plusButton}</ul>
  6664.   `;
  6665.   } else {
  6666.     alertContent.innerHTML = `
  6667.     <p style=\"font-size: 16px; font-weight: bold; color: #333;\">
  6668.       Vous avez atteint \${current} photos favorites !
  6669.     </p>
  6670.     <p style=\"margin-bottom: 20px; color: #555;\">
  6671.       Profitez de nos offres spéciales :
  6672.     </p>
  6673.     <ul style=\"list-style-type: none; padding: 0;\">\${productList}\${plusButton}</ul>
  6674.   `;
  6675.   }
  6676.   if (purchaseAlert && purchaseAlert.classList) {
  6677.     purchaseAlert.classList.remove(\"hidden\");
  6678.   }
  6679.   clearTimeout(window.purchaseAlertTimeout);
  6680.   window.purchaseAlertTimeout = setTimeout(() => {
  6681.     if (!purchaseAlert.matches(\":hover\")) {
  6682.       closePurchaseAlert();
  6683.     }
  6684.   }, 5000);
  6685. }
  6686.     // Fonction pour fermer l'alerte
  6687.     function closePurchaseAlert() {
  6688.       if (purchaseAlert && purchaseAlert.classList) {
  6689.         purchaseAlert.classList.add(\"hidden\");
  6690.       }
  6691.     }
  6692.     // Événement pour mettre à jour le contenu et afficher la popover dynamiquement au hover
  6693.     document.querySelector(\".gift-button\").addEventListener(\"mouseover\", () => {
  6694.       const currentCount = getCurrentFavoriteCount();
  6695.       updatePurchaseAlert(currentCount);
  6696.       if (purchaseAlert && purchaseAlert.classList) {
  6697.         purchaseAlert.classList.remove(\"cachee\"); // Réaffiche la popover
  6698.       }
  6699.     });
  6700.     // Nouvelles fonctions pour le bouton cadeau
  6701.     function showGiftMessage() {
  6702.       const tooltip = document.getElementById(\"giftTooltip\");
  6703.       if (tooltip) {
  6704.         if (tooltip && tooltip.classList) {
  6705.           tooltip.classList.add(\"show\");
  6706.         }
  6707.       }
  6708.     }
  6709.     function hideGiftMessage() {
  6710.       const tooltip = document.getElementById(\"giftTooltip\");
  6711.       if (tooltip) {
  6712.         if (tooltip && tooltip.classList) {
  6713.           tooltip.classList.remove(\"show\");
  6714.         }
  6715.       }
  6716.     }
  6717.     function showSelection() {
  6718.       document.getElementById(\"purchase-alert\").style.display = \"block\";
  6719.     }
  6720.     function hideSelection() {
  6721.       document.getElementById(\"selectionPopover\").style.display = \"none\";
  6722.     }
  6723.     document.addEventListener(\"DOMContentLoaded\", function () {
  6724.       const container = document.querySelector(\".date-container\");
  6725.       // Vérifie si le conteneur existe pour éviter les erreurs
  6726.       if (container) {
  6727.         container.scrollTo({
  6728.           left: container.scrollWidth, // Scroll directement à la position maximale
  6729.           behavior: \"smooth\", // Défilement fluide
  6730.         });
  6731.       }
  6732.     });
  6733.     document.addEventListener(\"DOMContentLoaded\", function () {
  6734.       const container = document.querySelector(\".date-container\");
  6735.       const leftArrow = document.querySelector(\".scroll-btn.left\");
  6736.       const rightArrow = document.querySelector(\".scroll-btn.right\");
  6737.       // Fonction pour vérifier le débordement et activer/désactiver les flèches
  6738.       function updateArrowsVisibility() {
  6739.         const isOverflowing = container.scrollWidth > container.clientWidth; // Vérifie si débordement
  6740.         leftArrow.style.display = isOverflowing ? \"flex\" : \"none\";
  6741.         rightArrow.style.display = isOverflowing ? \"flex\" : \"none\";
  6742.       }
  6743.       // Fonction pour défiler
  6744.       function scrollContainer(direction) {
  6745.         container.scrollBy({
  6746.           left: direction === \"left\" ? -200 : 200, // Défiler à gauche ou à droite
  6747.           behavior: \"smooth\",
  6748.         });
  6749.       }
  6750.       // Ajout des événements de clic pour les flèches
  6751.       leftArrow.addEventListener(\"click\", () => scrollContainer(\"left\"));
  6752.       rightArrow.addEventListener(\"click\", () => scrollContainer(\"right\"));
  6753.       // ⚡ OPTIMISÉ: Debounce resize pour éviter surcharge
  6754.       let resizeTimeout;
  6755.       const debouncedResize = () => {
  6756.         clearTimeout(resizeTimeout);
  6757.         resizeTimeout = setTimeout(updateArrowsVisibility, 150);
  6758.       };
  6759.       
  6760.       updateArrowsVisibility();
  6761.       window.addEventListener(\"resize\", debouncedResize, { passive: true });
  6762.     });
  6763.     document.addEventListener(\"DOMContentLoaded\", function () {
  6764.       const container = document.querySelector(\".date-container\");
  6765.       const leftBtn = document.querySelector(\".scroll-btn.left\");
  6766.       const rightBtn = document.querySelector(\".scroll-btn.right\");
  6767.       leftBtn.addEventListener(\"click\", () => {
  6768.         container.scrollBy({
  6769.           left: -200, // Défile vers la gauche
  6770.           behavior: \"smooth\",
  6771.         });
  6772.       });
  6773.       rightBtn.addEventListener(\"click\", () => {
  6774.         container.scrollBy({
  6775.           left: 200, // Défile vers la droite
  6776.           behavior: \"smooth\",
  6777.         });
  6778.       });
  6779.     });
  6780.  document.addEventListener(\"DOMContentLoaded\", function () {
  6781.     // Sélectionnez tous les badges de filtre
  6782.     const filterBadges = document.querySelectorAll(\".filter-badge\");
  6783.     // Sélectionnez tous les éléments de la galerie
  6784.     const galleryItems = document.querySelectorAll(\".column\");
  6785.     // Sélectionnez tous les jours
  6786.     const days = document.querySelectorAll(\".collapse\");
  6787.     // Fonction pour réinitialiser les filtres
  6788.     function resetFilters() {
  6789.         // Réinitialisez tous les éléments de la galerie
  6790.         galleryItems.forEach((item) => {
  6791.             item.style.display = \"block\";
  6792.         });
  6793.         // Réinitialisez les états des badges
  6794.         filterBadges.forEach((badge) => {
  6795.           if (badge && badge.classList) {
  6796.             badge.classList.remove(\"active\");
  6797.           }
  6798.         });
  6799.     }
  6800.     // Ajoutez un gestionnaire d'événements pour chaque badge
  6801.     filterBadges.forEach((badge) => {
  6802.         badge.addEventListener(\"click\", function () {
  6803.             const filter = this.getAttribute(\"data-filter\");
  6804.             // Réinitialisez l'état actif pour tous les badges
  6805.             filterBadges.forEach((btn) => {
  6806.               if (btn && btn.classList) {
  6807.                 btn.classList.remove(\"active\");
  6808.               }
  6809.             });
  6810.             // Ajoutez l'état actif au badge cliqué
  6811.             if (this && this.classList) {
  6812.               this.classList.add(\"active\");
  6813.             }
  6814.             // Affichez ou masquez les éléments de la galerie
  6815.             galleryItems.forEach((item) => {
  6816.                 if (filter === \"all\") {
  6817.                     item.style.display = \"block\";
  6818.                 } else if (filter === \"photo\" && item.querySelector(\"img\")) {
  6819.                     item.style.display = \"block\";
  6820.                 } else if (filter === \"video\" && item.querySelector(\"video\")) {
  6821.                     item.style.display = \"block\";
  6822.                 } else if (filter === \"audio\" && item.classList && item.classList.contains(\"audio-message-item\")) {
  6823.                     item.style.display = \"block\";
  6824.                 } else {
  6825.                     item.style.display = \"none\";
  6826.                 }
  6827.             });
  6828.         });
  6829.     });
  6830.     // Réinitialiser les filtres lors du changement de jour
  6831.     days.forEach((day) => {
  6832.         day.addEventListener(\"show.bs.collapse\", function () {
  6833.             resetFilters();
  6834.         });
  6835.     });
  6836. });
  6837.     \$(document).ready(function () {
  6838.       let zoomCounter = 0; // Initialize zoom counter
  6839.       let currentImageSrc = \"\"; // Track current image source
  6840.       let lastClickPosition = { x: 50, y: 50 }; // Default to center of image
  6841.       \$(\".container--gallery\").magnificPopup({
  6842.         delegate: \"a\",
  6843.         type: \"image\",
  6844.         mainClass: \"mfp-with-zoom mfp-img-mobile\",
  6845.         image: {
  6846.           verticalFit: true,
  6847.         },
  6848.         gallery: {
  6849.           enabled: true,
  6850.           tPrev: \"Previous (Left arrow key)\", // Alt text on left arrow
  6851.           tNext: \"Next (Right arrow key)\", // Alt text on right arrow
  6852.           tCounter: \"%curr% of %total%\", // Markup for \"1 of 7\" counter
  6853.         },
  6854.         zoom: {
  6855.           enabled: true,
  6856.           duration: 300,
  6857.           opener: function (element) {
  6858.             return element.find(\"img\");
  6859.           },
  6860.         },
  6861.         callbacks: {
  6862.           open: function () {
  6863.             // Get current image data from the link that was clicked
  6864.             const currentLink = this.currItem.el;
  6865.             const imageId =
  6866.               currentLink
  6867.                 .closest(\".photo-zoom\")
  6868.                 .find(\".heart-icon\")
  6869.                 .data(\"id\") || \"\";
  6870.             const sejourId =
  6871.               currentLink
  6872.                 .closest(\".photo-zoom\")
  6873.                 .find(\".heart-icon\")
  6874.                 .data(\"sejour-id\") || \"\";
  6875.             const imagePath =
  6876.               currentLink
  6877.                 .closest(\".photo-zoom\")
  6878.                 .find(\".heart-icon\")
  6879.                 .data(\"path\") || \"\";
  6880.             const imageDesc =
  6881.               currentLink
  6882.                 .closest(\".photo-zoom\")
  6883.                 .find(\".heart-icon\")
  6884.                 .data(\"description\") || \"\";
  6885.             const isFavorite = currentLink
  6886.               .closest(\".photo-zoom\")
  6887.               .find(\".heart-icon i\")
  6888.               .hasClass(\"bi-heart-fill\");
  6889.             const favoriteIconClass = isFavorite ? \"bi-heart-fill\" : \"bi-heart\";
  6890.             const favoriteIconColor = isFavorite ? \"#f56040\" : \"white\";
  6891.             const favoriteTooltip = isFavorite
  6892.               ? \"Retirer des favoris\"
  6893.               : \"Ajouter aux favoris\";
  6894.             const zoomControls = `
  6895.           <div class=\"mfp-zoom-controls\">
  6896.             <button class=\"zoom-btn zoom-out\" title=\"Zoom Out\"><i class=\"fa fa-search-minus\"></i></button>
  6897.             <button class=\"zoom-btn zoom-in\" title=\"Zoom In\"><i class=\"fa fa-search-plus\"></i></button>
  6898.           </div>
  6899.           <div class=\"mfp-favorite\">
  6900.             <button class=\"favorite-btn\" 
  6901.                     data-id=\"\${imageId}\" 
  6902.                     data-sejour-id=\"\${sejourId}\" 
  6903.                     data-path=\"\${imagePath}\" 
  6904.                     data-description=\"\${imageDesc}\"
  6905.                     title=\"\${favoriteTooltip}\">
  6906.               <i class=\"bi \${favoriteIconClass}\" style=\"color: \${favoriteIconColor}; text-shadow: 0px 0px 3px rgba(0,0,0,0.5);\"></i>
  6907.             </button>
  6908.           </div>
  6909.           <div class=\"mfp-counter\"></div>
  6910.         `;
  6911.             \$(\".mfp-content\").append(zoomControls);
  6912.             initializeZoomControls();
  6913.             initializeFavoriteButton();
  6914.             const intervalId = setInterval(() => {
  6915.               const newImageSrc = \$(\".mfp-img\").attr(\"src\");
  6916.               if (newImageSrc !== currentImageSrc) {
  6917.                 currentImageSrc = newImageSrc;
  6918.                 zoomCounter = 0;
  6919.                 lastClickPosition = { x: 50, y: 50 }; // Reset to center
  6920.                 attachZoomHandler(); // Reattach zoom handler to new image
  6921.                 \$(\".mfp-img\").css({
  6922.                   \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  6923.                   transform: `scale(1)`,
  6924.                 });
  6925.                 // Update favorite button for the new image
  6926.                 updateFavoriteButton();
  6927.                 initializeZoomControls();
  6928.                 updateCounter();
  6929.               }
  6930.             }, 100);
  6931.             this.content.on(\"mfpClose\", function () {
  6932.               clearInterval(intervalId);
  6933.             });
  6934.             attachZoomHandler();
  6935.           },
  6936.           close: function () {
  6937.             \$(\".mfp-zoom-controls\").remove();
  6938.             \$(\".mfp-favorite\").remove();
  6939.             \$(\".mfp-counter\").remove();
  6940.             zoomCounter = 0;
  6941.           },
  6942.         },
  6943.       });
  6944.       function attachZoomHandler() {
  6945.         \$(\".mfp-img\")
  6946.           .off(\"click\")
  6947.           .on(\"click\", function (event) {
  6948.             event.stopPropagation(); // Prevent default navigation behavior
  6949.             // Calculate click coordinates relative to the image
  6950.             const imgOffset = \$(this).offset();
  6951.             const clickX = event.pageX - imgOffset.left;
  6952.             const clickY = event.pageY - imgOffset.top;
  6953.             const imgWidth = \$(this).width();
  6954.             const imgHeight = \$(this).height();
  6955.             // Calculate transform-origin based on click position
  6956.             lastClickPosition = {
  6957.               x: (clickX / imgWidth) * 100,
  6958.               y: (clickY / imgHeight) * 100,
  6959.             };
  6960.             // Cycle through zoom levels: 1x, 1.5x, 2x
  6961.             zoomCounter = (zoomCounter + 1) % 3;
  6962.             const zoomLevels = [1, 1.5, 2];
  6963.             const zoomLevel = zoomLevels[zoomCounter];
  6964.             \$(this).css({
  6965.               \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  6966.               transform: `scale(\${zoomLevel})`,
  6967.             });
  6968.             updateZoomButtonState();
  6969.           });
  6970.       }
  6971.       function initializeZoomControls() {
  6972.         \$(\".mfp-zoom-controls .zoom-in\")
  6973.           .off(\"click\")
  6974.           .on(\"click\", function (event) {
  6975.             event.stopPropagation();
  6976.             zoomCounter = (zoomCounter + 1) % 3;
  6977.             const zoomLevels = [1, 1.5, 2];
  6978.             const zoomLevel = zoomLevels[zoomCounter];
  6979.             \$(\".mfp-img\").css({
  6980.               \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  6981.               transform: `scale(\${zoomLevel})`,
  6982.             });
  6983.             updateZoomButtonState();
  6984.           });
  6985.         \$(\".mfp-zoom-controls .zoom-out\")
  6986.           .off(\"click\")
  6987.           .on(\"click\", function (event) {
  6988.             event.stopPropagation();
  6989.             if (zoomCounter > 0) {
  6990.               zoomCounter -= 1;
  6991.               const zoomLevels = [1, 1.5, 2];
  6992.               const zoomLevel = zoomLevels[zoomCounter];
  6993.               \$(\".mfp-img\").css({
  6994.                 \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  6995.                 transform: `scale(\${zoomLevel})`,
  6996.               });
  6997.               updateZoomButtonState();
  6998.             } else {
  6999.               \$.magnificPopup.close();
  7000.             }
  7001.           });
  7002.       }
  7003.       function initializeFavoriteButton() {
  7004.         \$(\".mfp-favorite .favorite-btn\")
  7005.           .off(\"click\")
  7006.           .on(\"click\", function (event) {
  7007.             event.stopPropagation();
  7008.             const \$this = \$(this);
  7009.             const imageId = \$this.data(\"id\");
  7010.             const sejourId = \$this.data(\"sejour-id\");
  7011.             // Toggle favorite status
  7012.             const isFavorite = \$this.find(\"i\").hasClass(\"bi-heart-fill\");
  7013.             // Update the button appearance
  7014.             if (isFavorite) {
  7015.               \$this
  7016.                 .find(\"i\")
  7017.                 .removeClass(\"bi-heart-fill\")
  7018.                 .addClass(\"bi-heart\")
  7019.                 .css(\"color\", \"white\");
  7020.               \$this.attr(\"title\", \"Ajouter aux favoris\");
  7021.             } else {
  7022.               \$this
  7023.                 .find(\"i\")
  7024.                 .removeClass(\"bi-heart\")
  7025.                 .addClass(\"bi-heart-fill\")
  7026.                 .css(\"color\", \"#f56040\");
  7027.               \$this.attr(\"title\", \"Retirer des favoris\");
  7028.             }
  7029.             // Update the original heart icon in the gallery
  7030.             const originalHeartIcon = \$(
  7031.               `.heart-icon[data-id=\"\${imageId}\"]`
  7032.             ).find(\"i\");
  7033.             if (isFavorite) {
  7034.               originalHeartIcon
  7035.                 .removeClass(\"bi-heart-fill\")
  7036.                 .addClass(\"bi-heart\")
  7037.                 .css(\"color\", \"\");
  7038.             } else {
  7039.               originalHeartIcon
  7040.                 .removeClass(\"bi-heart\")
  7041.                 .addClass(\"bi-heart-fill\")
  7042.                 .css(\"color\", \"#f56040\");
  7043.             }
  7044.             // Make AJAX call to update favorite status in the backend using Parent routes
  7045.             \$.ajax({
  7046.               url: isFavorite ? \"/Parent/aSupprimerFav\" : \"/Parent/ajouterFav\",
  7047.               type: \"POST\",
  7048.               data: {
  7049.                 id: imageId,
  7050.                 idSejour: sejourId,
  7051.               },
  7052.               success: function (response) {
  7053.                 // Optional: Show a success message or handle response
  7054.                 console.log(\"Favorite status updated\", response);
  7055.               },
  7056.               error: function (error) {
  7057.                 console.error(\"Error updating favorite status\", error);
  7058.                 // Revert the icon change on error
  7059.                 if (isFavorite) {
  7060.                   \$this
  7061.                     .find(\"i\")
  7062.                     .removeClass(\"bi-heart\")
  7063.                     .addClass(\"bi-heart-fill\")
  7064.                     .css(\"color\", \"#f56040\");
  7065.                   originalHeartIcon
  7066.                     .removeClass(\"bi-heart\")
  7067.                     .addClass(\"bi-heart-fill\")
  7068.                     .css(\"color\", \"#f56040\");
  7069.                 } else {
  7070.                   \$this
  7071.                     .find(\"i\")
  7072.                     .removeClass(\"bi-heart-fill\")
  7073.                     .addClass(\"bi-heart\")
  7074.                     .css(\"color\", \"white\");
  7075.                   originalHeartIcon
  7076.                     .removeClass(\"bi-heart-fill\")
  7077.                     .addClass(\"bi-heart\")
  7078.                     .css(\"color\", \"\");
  7079.                 }
  7080.               },
  7081.             });
  7082.           });
  7083.       }
  7084.       function updateFavoriteButton() {
  7085.         // Get current image data from the current slide
  7086.         const currentSlide = \$.magnificPopup.instance.currItem.el;
  7087.         const photoZoom = currentSlide.closest(\".photo-zoom\");
  7088.         if (photoZoom.length) {
  7089.           const heartIcon = photoZoom.find(\".heart-icon\");
  7090.           const imageId = heartIcon.data(\"id\") || \"\";
  7091.           const sejourId = heartIcon.data(\"sejour-id\") || \"\";
  7092.           const imagePath = heartIcon.data(\"path\") || \"\";
  7093.           const imageDesc = heartIcon.data(\"description\") || \"\";
  7094.           const isFavorite = heartIcon.find(\"i\").hasClass(\"bi-heart-fill\");
  7095.           const favoriteIconClass = isFavorite ? \"bi-heart-fill\" : \"bi-heart\";
  7096.           const favoriteIconColor = isFavorite ? \"#f56040\" : \"white\";
  7097.           const favoriteTooltip = isFavorite
  7098.             ? \"Retirer des favoris\"
  7099.             : \"Ajouter aux favoris\";
  7100.           // Update the favorite button
  7101.           const \$favoriteBtn = \$(\".mfp-favorite .favorite-btn\");
  7102.           \$favoriteBtn.data(\"id\", imageId);
  7103.           \$favoriteBtn.data(\"sejour-id\", sejourId);
  7104.           \$favoriteBtn.data(\"path\", imagePath);
  7105.           \$favoriteBtn.data(\"description\", imageDesc);
  7106.           \$favoriteBtn.attr(\"title\", favoriteTooltip);
  7107.           \$favoriteBtn
  7108.             .find(\"i\")
  7109.             .removeClass(\"bi-heart bi-heart-fill\")
  7110.             .addClass(favoriteIconClass)
  7111.             .css(\"color\", favoriteIconColor);
  7112.         }
  7113.       }
  7114.       function updateZoomButtonState() {
  7115.         const zoomLevels = [1, 1.5, 2];
  7116.         const currentZoom = zoomLevels[zoomCounter];
  7117.         \$(\".zoom-in\").prop(\"disabled\", currentZoom === 2);
  7118.         \$(\".zoom-out\").prop(\"disabled\", currentZoom === 1);
  7119.       }
  7120.       function updateCounter() {
  7121.         const counterText = \$(\".mfp-counter\")
  7122.           .closest(\".mfp-content\")
  7123.           .find(\".mfp-counter\")
  7124.           .text();
  7125.         const matches = counterText.match(/(\\d+) of (\\d+)/);
  7126.         if (matches) {
  7127.           const currentIndex = matches[1];
  7128.           const totalImages = matches[2];
  7129.           \$(\".mfp-counter\").text(`\${currentIndex} of \${totalImages}`);
  7130.         }
  7131.       }
  7132.       // Add CSS for the favorite button and rounded image corners
  7133.       \$(\"<style>\")
  7134.         .prop(\"type\", \"text/css\")
  7135.         .html(
  7136.           `
  7137.       .mfp-favorite {
  7138.         position: absolute;
  7139.         top: 15px;
  7140.         left: 15px;
  7141.         z-index: 1046;
  7142.       }
  7143.       .favorite-btn {
  7144.         background: transparent;
  7145.         border: none;
  7146.         font-size: 24px;
  7147.         padding: 5px;
  7148.         cursor: pointer;
  7149.         outline: none;
  7150.       }
  7151.       .favorite-btn i {
  7152.         transition: all 0.3s ease;
  7153.       }
  7154.       .favorite-btn:hover i {
  7155.         transform: scale(1.2);
  7156.       }
  7157.       /* Rounded corners for zoomed images */
  7158.       .mfp-img {
  7159.         border-radius: 8px;
  7160.       }
  7161.       /* Make sure the container doesn't clip the rounded corners */
  7162.       .mfp-figure:after {
  7163.         border-radius: 8px;
  7164.       }
  7165.     `
  7166.         )
  7167.         .appendTo(\"head\");
  7168.     });
  7169.   </script>
  7170. <script>
  7171. document.addEventListener('DOMContentLoaded', function () {
  7172.   const openBtn = document.getElementById('openFavoritesBtn');
  7173.   const closeBtn = document.getElementById('closeSidebarBtn');
  7174.   const sidebar = document.getElementById('favoritesSidebar');
  7175.   const tbody = document.querySelector('#favoritesTable tbody');
  7176.   openBtn.addEventListener('click', async () => {
  7177.     try {
  7178.       const response = await fetch('/Parent/mes-favoris', {
  7179.         headers: {
  7180.           'Accept': 'application/json'
  7181.         }
  7182.       });
  7183.       const result = await response.json();
  7184.       if (!result.success || !Array.isArray(result.data)) {
  7185.         alert('Erreur lors du chargement des favoris.');
  7186.         return;
  7187.       }
  7188.       tbody.innerHTML = '';
  7189.       result.data.forEach((fav, index) => {
  7190.         const row = document.createElement('tr');
  7191.         row.innerHTML = `
  7192.           <td>\${index + 1}</td>
  7193.           <td><img src=\"\${fav.path}\" alt=\"favori\"></td>
  7194.           <td>\${fav.descreption || '—'}</td>
  7195.           <td>\${fav.created_at}</td>
  7196.         `;
  7197.         tbody.appendChild(row);
  7198.       });
  7199.       sidebar.classList.add('active');
  7200.     } catch (e) {
  7201.       console.error('Erreur réseau:', e);
  7202.       alert('Impossible de charger les favoris.');
  7203.     }
  7204.   });
  7205.   closeBtn.addEventListener('click', () => {
  7206.     sidebar.classList.remove('active');
  7207.   });
  7208. });
  7209. </script>
  7210.   <script>
  7211.         // Fonction pour vérifier et afficher l'alerte
  7212.         function checkFavoritesAlert() {
  7213.             const currentCount = window.favoriteCount || 0;
  7214.             if (currentCount >= 10) {
  7215.                 const purchaseAlert = document.getElementById('purchase-alert');
  7216.                 if (purchaseAlert) {
  7217.                     purchaseAlert.style.display = 'block'; // Affiche l'alerte
  7218.                 }
  7219.             } else {
  7220.                 purchaseAlert.style.display = 'none'; // Cache l'alerte si le nombre est réduit
  7221.             }
  7222.         }
  7223.     
  7224.         
  7225.         document.addEventListener('DOMContentLoaded', () => {
  7226.     const favoriteCount = ";
  7227.         // line 6899
  7228.         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.'6899$this->source); })()), "html"nulltrue);
  7229.         yield ";
  7230.     updateCardContent(favoriteCount);
  7231. });
  7232. function updateCardContent(favoriteCount) {
  7233.     const card = document.getElementById('dynamic-card');
  7234.     const cardContent = document.getElementById('dynamic-card-content');
  7235.     let produits = [];
  7236.     if (favoriteCount >= 20) {
  7237.         produits.push({
  7238.             titre: \"Album débloqué !\",
  7239.             bouton: \"Commander\",
  7240.             image: \"/images/produit/Album5sur5-3.jpg\",
  7241.             lien: \"";
  7242.         // line 6914
  7243.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("EditionAlbum");
  7244.         yield "\"
  7245.         });
  7246.     }
  7247.     if (favoriteCount >= 12) {
  7248.         produits.push({
  7249.             titre: \"Pochette débloquée !\",
  7250.             bouton: \"Commander\",
  7251.             image: \"/images/produit/PochettePhoto5sur5-2.jpg\",
  7252.             lien: \"";
  7253.         // line 6922
  7254.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("AjoutPochettePhotos_Favoris", ["nbr" => 12]);
  7255.         yield "\"
  7256.         });
  7257.     }
  7258.     if (favoriteCount >= 5) {
  7259.         produits.push({
  7260.             titre: \"Pack numérique débloqué !\",
  7261.             bouton: \"Commander\",
  7262.             image: \"/images/produit/photoNumerique.jpg\",
  7263.             lien: \"";
  7264.         // line 6930
  7265.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("PackPhotosNumerique_Favoris", ["nbr" => 15]);
  7266.         yield "\"
  7267.         });
  7268.     }
  7269. if (produits.length === 0) {
  7270.   cardContent.innerHTML = `
  7271.     <div style=\"position: relative; width: 100%; height: 140px; border-radius: 15px; overflow: hidden; box-shadow: 0 4px 10px rgba(0,0,0,0.1);\">
  7272.       <div style=\"background-image: url('/images/produit/CoffretCadeau5sur5-2.jpg'); background-size: cover; background-position: center; width: 100%; height: 100%;\">
  7273.         <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;\">
  7274.           <div style=\"
  7275.     margin-top: 35px;
  7276.     color: white;
  7277.     font-size: 15px;
  7278.     font-weight: bold;
  7279.     text-align: center;
  7280.     line-height: 1;
  7281.     text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);\">
  7282.             Ajoutez des favoris ❤️<br><span style=\"font-size: 16px; font-weight: normal;\">pour débloquer un souvenir à offrir 🎁</span>
  7283.           </div>
  7284.         </div>
  7285.       </div>
  7286.     </div>
  7287.   `;
  7288.         return;
  7289.     }
  7290.     cardContent.innerHTML = `
  7291.     <div class=\"splide\" id=\"dynamicSplide\">
  7292.       <div class=\"splide__track\">
  7293.         <ul class=\"splide__list\">
  7294.           \${produits.map(produit => `
  7295.             <li class=\"splide__slide\" style=\"position: relative;\">
  7296.               <img src=\"\${produit.image}\" alt=\"\${produit.titre}\" style=\"width: 100%; height: 150px; object-fit: cover; border-radius: 8px;\">
  7297.               <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;\">
  7298.                 <div style=\"font-weight: bold; font-size: 14px;\">\${produit.titre}</div>
  7299.                 <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}'\">
  7300.                   \${produit.bouton}
  7301.                 </button>
  7302.               </div>
  7303.             </li>
  7304.           `).join('')}
  7305.         </ul>
  7306.       </div>
  7307.     </div>
  7308.     `;
  7309.     // Monte le carrousel
  7310.     new Splide('#dynamicSplide', {
  7311.         type: 'loop',
  7312.         arrows: true,
  7313.         pagination: false,
  7314.         autoplay: true,
  7315.         interval: 4000,
  7316.         speed: 800,
  7317.     }).mount();
  7318. }
  7319.         // Fonction helper pour lire le compteur de favoris (gère les badges premium)
  7320.         function getFavorisCount() {
  7321.             const mesFavCount = document.getElementById('mesFavCount');
  7322.             if (!mesFavCount) return 0;
  7323.             
  7324.             const badge = mesFavCount.querySelector('.premium-5sur5-badge');
  7325.             if (badge) {
  7326.                 return parseInt(badge.textContent.trim() || '0');
  7327.             }
  7328.             
  7329.             const countText = mesFavCount.textContent.trim();
  7330.             if (countText === 'Pas de favoris' || countText.includes('Pas de favoris')) {
  7331.                 return 0;
  7332.             }
  7333.             
  7334.             return parseInt(countText || '0');
  7335.         }
  7336.         // Fonction helper pour mettre à jour l'affichage du compteur de favoris
  7337.         function updateFavorisDisplay(count) {
  7338.             const mesFavCount = document.getElementById('mesFavCount');
  7339.             const favorisBtn = document.querySelector('.mtb-btn[data-filter=\"favoris\"]');
  7340.             const favorisIcon = favorisBtn?.querySelector('i.bi-heart-fill');
  7341.             
  7342.             if (!mesFavCount || !favorisBtn) return;
  7343.             
  7344.             if (count === 0) {
  7345.                 // Afficher \"Pas de favoris\" au lieu de \"0\" avec style premium
  7346.                 mesFavCount.innerHTML = '<span class=\"favoris-empty-text\" style=\"color: #94a3b8; font-style: italic; font-size: 11px;\">Pas de favoris</span>';
  7347.                 favorisBtn.classList.add('favoris-empty');
  7348.                 favorisBtn.disabled = true;
  7349.                 favorisBtn.title = \"Pas de favoris pour l'instant\";
  7350.                 if (favorisIcon) {
  7351.                     favorisIcon.style.color = '#cbd5e1';
  7352.                 }
  7353.             } else {
  7354.                 // Afficher le badge premium avec le nombre
  7355.                 mesFavCount.innerHTML = `<span class=\"premium-5sur5-badge\" style=\"background: rgba(245, 96, 64, 0.1); color: #F56040; font-size: 10px; padding: 2px 6px;\">\${count}</span>`;
  7356.                 favorisBtn.classList.remove('favoris-empty');
  7357.                 favorisBtn.disabled = false;
  7358.                 favorisBtn.title = \"Mes favoris\";
  7359.                 if (favorisIcon) {
  7360.                     favorisIcon.style.color = '#f56040';
  7361.                 }
  7362.             }
  7363.         }
  7364.         function supprimerFavoris(\$id, \$idSejour) {
  7365.             // 🚨 LOG CRITIQUE : Tracer TOUS les appels à supprimerFavoris
  7366.             console.error('🚨🚨🚨 supprimerFavoris() APPELÉ ! 🚨🚨🚨', {
  7367.                 id: \$id,
  7368.                 idSejour: \$idSejour,
  7369.                 stack: new Error().stack,
  7370.                 mesFavCountAvant: document.getElementById('mesFavCount')?.textContent
  7371.             });
  7372.             
  7373.             // Vider l'élément coeur pour ce favori
  7374.             const coeurElement = \$('#coeur' + \$id);
  7375.             coeurElement.empty();
  7376.             // Ajout d'une animation sur le bouton cadeau
  7377.             const giftButton = document.querySelector('.gift-button');
  7378.             if (giftButton) {
  7379.                 giftButton.classList.add('active');
  7380.                 // Retirer l'animation après qu'elle soit jouée
  7381.                 setTimeout(() => {
  7382.                     giftButton.classList.remove('active');
  7383.                 }, 600); // La durée doit correspondre à celle de l'animation
  7384.             }
  7385.             // Mise à jour de l'icône coeur
  7386.             const clas = \$('.IconImag6').hasClass('active') ? \"IconDelete IconDeletesix\" : \"IconDelete\";
  7387.             coeurElement.html(
  7388.                 `<i class=\"bi bi-heart \${clas}\" ></i>`
  7389.             );
  7390.             // METTRE À JOUR UNIQUEMENT #mesFavCount (source unique de vérité)
  7391.             // L'observer se chargera de synchroniser giftCount automatiquement
  7392.             const mesFavCount = document.getElementById('mesFavCount');
  7393.             if (mesFavCount) {
  7394.                 let currentCount = getFavorisCount();
  7395.                 currentCount = Math.max(0, currentCount - 1); // Empêche d'aller en dessous de 0
  7396.                 updateFavorisDisplay(currentCount);
  7397.                 console.log('[supprimerFavoris] ✅ mesFavCount décrémenté:', currentCount);
  7398.                 
  7399.                 // L'observer MutationObserver va automatiquement :
  7400.                 // - Synchroniser giftCount
  7401.                 // - Mettre à jour le sidebar
  7402.                 // - Mettre à jour product-suggestions
  7403.             }
  7404.             // Préparation des données pour l'Ajax
  7405.             const \$_data = { 'id': \$id, 'idSejour': \$idSejour };
  7406.             // Appel Ajax pour supprimer le favori
  7407.             \$.ajax({
  7408.                 type: \"POST\",
  7409.                 url: \"";
  7410.         // line 7085
  7411.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("Supprimer_fav");
  7412.         yield "\",
  7413.                 data: \$_data,
  7414.                 success: function () {
  7415.                     // Réactiver les icônes après succès
  7416.                     \$('.IconDelete').each(function () {
  7417.                         \$(this).css('pointer-events', '');
  7418.                     });
  7419.                     
  7420.                     // Mettre à jour l'alerte avec le nouveau nombre
  7421.                     const finalCount = getCurrentFavoriteCount();
  7422.                     if (typeof updatePurchaseAlert === 'function') {
  7423.                         updatePurchaseAlert(finalCount);
  7424.                     }
  7425.                 },
  7426.                 error: function (xhr, status, error) {
  7427.                     console.error('Erreur lors de la suppression du favori :', error);
  7428.                 }
  7429.             });
  7430.         }
  7431.         function AddFavoris(\$id, \$idSejour, \$urlimg, \$description) {
  7432.             // 🟢 LOG : Tracer les ajouts de favoris
  7433.             console.log('🟢 AddFavoris() APPELÉ', {
  7434.                 id: \$id,
  7435.                 idSejour: \$idSejour,
  7436.                 mesFavCountAvant: document.getElementById('mesFavCount')?.textContent
  7437.             });
  7438.             
  7439.             // Update heart icon
  7440.             \$('#coeur' + \$id).empty();
  7441.             var clas = \$('.IconImag6').hasClass('active') ? \"IconDelete IconDeletesix\" : \"IconDelete\";
  7442.             \$('#coeur' + \$id).html(\"<i class=\\\"bi bi-heart-fill favSelect \" + clas + \"\\\" )\\\"></i>\");
  7443.             
  7444.             // METTRE À JOUR UNIQUEMENT #mesFavCount (source unique de vérité)
  7445.             // L'observer se chargera de synchroniser giftCount automatiquement
  7446.             const mesFavCount = document.getElementById('mesFavCount');
  7447.             if (mesFavCount) {
  7448.                 let currentCount = getFavorisCount();
  7449.                 currentCount++;
  7450.                 updateFavorisDisplay(currentCount);
  7451.                 console.log('[AddFavoris] ✅ mesFavCount incrémenté:', currentCount);
  7452.                 
  7453.                 // L'observer MutationObserver va automatiquement :
  7454.                 // - Synchroniser giftCount
  7455.                 // - Mettre à jour le sidebar
  7456.                 // - Mettre à jour product-suggestions
  7457.             }
  7458.             
  7459.             // Update other counters
  7460.             var \$total = parseInt(\$(\"#totalLike\").html()) + 1;
  7461.             \$(\"#totalLike\").html(\$total);
  7462.             \$(\"#totalLikeTitle\").html(\$total);
  7463.             \$(\"#totalLikeMobile\").html(\$total);
  7464.             
  7465.             // Add gift button animation
  7466.             const giftButton = document.querySelector('.gift-button');
  7467.             if (giftButton) {
  7468.                 giftButton.classList.add('active');
  7469.                 setTimeout(() => {
  7470.                     giftButton.classList.remove('active');
  7471.                 }, 600);
  7472.             }
  7473.             var \$data = { 'id': \$id, 'idSejour': \$idSejour };
  7474.             \$.ajax({
  7475.                 type: \"POST\",
  7476.                 url: \"";
  7477.         // line 7152
  7478.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("Ajouter_fav");
  7479.         yield "\",
  7480.                 data: \$data,
  7481.                 success: function () {
  7482.                     \$('.IconDelete').each(function () {
  7483.                         \$(this).css('pointer-events', '');
  7484.                     });
  7485.                     if (\$description === undefined) {
  7486.                         \$description = ''; // Set it to an empty string
  7487.                     }
  7488.                     \$('.rowMaselection').append(
  7489.                         '<div class=\"column\" id=\"column-' + \$id + '\">'+
  7490.                         '<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>'+
  7491.                         '<a class=\"photo-zoom\">'+
  7492.                         '<img data-idAtach=\"'+\$id+'\" id=\"'+\$idSejour+'\" src=\"'+\$urlimg+'\"></a>'+
  7493.                         (\$description ? '<h4 id=\"commint\" class=\"titleHeadPhoto\">'+\$description+'</h4>' : '')+ // Only add the <h4> if \$description is not empty
  7494.                         '</div>'
  7495.                     );
  7496.                     // Directly update nbLikes count in the header
  7497.                     var currentNbLikes = parseInt(\$('#favoris-link-Accueilpayment .nbrpanier').text());
  7498.                     var newNbLikes = currentNbLikes + 1;
  7499.                     \$('#favoris-link-Accueilpayment .nbrpanier').text(newNbLikes);
  7500.                     
  7501.                     // Mettre à jour l'alerte avec le nouveau nombre
  7502.                     const finalCount = getCurrentFavoriteCount();
  7503.                     if (typeof updatePurchaseAlert === 'function') {
  7504.                         updatePurchaseAlert(finalCount);
  7505.                     }
  7506.                 },
  7507.                 error: function (xhr, status, error) {
  7508.                     console.error('Error:', error);
  7509.                 }
  7510.             });
  7511.         }
  7512.         \$(document).on('click', '.bi-heart, .bi-heart-fill', function (e) {
  7513.         const heartIcon       = \$(this);
  7514.         
  7515.         // 🛡️ PROTECTION : Ignorer les clics sur le bouton favoris de la toolbar
  7516.         // Ce bouton sert uniquement à FILTRER, pas à ajouter/supprimer des favoris
  7517.         if (heartIcon.closest('.mtb-btn').length > 0) {
  7518.             console.log('💗 Clic sur bouton toolbar favoris ignoré (gestion séparée)');
  7519.             return; // Ne rien faire, c'est géré par le listener de la toolbar
  7520.         }
  7521.         
  7522.         const heartContainer  = heartIcon.closest('.heart-icon');
  7523.         // Extract data attributes
  7524.         const attachmentId    = heartContainer.data('id');
  7525.         const sejourId        = heartContainer.data('sejour-id');
  7526.         const path            = heartContainer.data('path');
  7527.         const description     = heartContainer.data('description');
  7528.         const isFavorite      = heartIcon.hasClass('bi-heart-fill');
  7529.         if (isFavorite) {
  7530.             // Remove from favorites
  7531.             supprimerFavoris(attachmentId, sejourId);
  7532.         } else {
  7533.             // Add to favorites
  7534.             AddFavoris(attachmentId, sejourId, path, description);
  7535.         }
  7536.         // Update UI components after the action (sans double comptage)
  7537.         setTimeout(function() {
  7538.             const likeCountLabel = document.getElementById('likeCount');
  7539.             
  7540.             if (likeCountLabel) {
  7541.                 const currentCount = parseInt(likeCountLabel.textContent, 10) || 0;
  7542.                 
  7543.                 // Update UI components seulement
  7544.                 updateCardContent(currentCount);
  7545.                 updateFavoritesSidebar();
  7546.                 \$(\"#close-favorites-btn\").click();
  7547.                 
  7548.                 // 🎯 Product suggestions sont mis à jour automatiquement par le MutationObserver
  7549.                 // dans parent-toasts.js qui observe #mesFavCount
  7550.                 // updateProductSuggestionsLive(currentCount); // ← SUPPRIMÉ (doublon)
  7551.             }
  7552.         }, 50);
  7553.     });
  7554.         // Ajoutez les événements sur les icônes de cœur
  7555.         document.querySelectorAll('.IconDelete').forEach((icon) => {
  7556.             icon.addEventListener('click', (event) => {
  7557.                 const isFavorite = icon && icon.classList && icon.classList.contains('bi-heart-fill');
  7558.                 if (isFavorite) {
  7559.                     removeFavorite();
  7560.                     if (icon.classList) {
  7561.                       icon.classList.remove('bi-heart-fill');
  7562.                       icon.classList.add('bi-heart');
  7563.                     }
  7564.                 } else {
  7565.                     addFavorite();
  7566.                     if (icon.classList) {
  7567.                       icon.classList.remove('bi-heart');
  7568.                       icon.classList.add('bi-heart-fill');
  7569.                     }
  7570.                 }
  7571.             });
  7572.         });
  7573.         // Vérifie l'état initial
  7574.         checkFavoritesAlert();
  7575.         
  7576.         
  7577.         // ⚡ OPTIMISÉ: Réduction du délai d'initialisation
  7578.       
  7579.   </script>
  7580.   <!-- Initialisation -->
  7581.   <script>
  7582.     // ⚡ OPTIMISATION: Différer l'initialisation d'AOS pour ne pas bloquer le chargement
  7583.     setTimeout(function() {
  7584.       AOS.init({
  7585.         duration: 800,
  7586.         easing: \"ease-in-out\"
  7587.       });
  7588.     }, 100);
  7589.     // 🎯 DAY FILTER DROPDOWN LOGIC (Senior UX)
  7590.     document.addEventListener('DOMContentLoaded', function() {
  7591.       initializeDayFilters();
  7592.       
  7593.       // Initialiser le compteur audio avec la valeur correcte
  7594.       setTimeout(function() {
  7595.         updateAudioButtonState('days');
  7596.       }, 500);
  7597.     });
  7598.     function initializeDayFilters() {
  7599.       const dropdowns = document.querySelectorAll('.day-filter-dropdown');
  7600.       
  7601.       dropdowns.forEach(dropdown => {
  7602.         const toggle = dropdown.querySelector('.filter-toggle');
  7603.         const menu = dropdown.querySelector('.filter-dropdown-menu');
  7604.         const options = dropdown.querySelectorAll('.filter-option');
  7605.         const dayIndex = dropdown.dataset.dayIndex;
  7606.         const dayContainer = document.getElementById(`demP\${dayIndex}`);
  7607.         
  7608.         if (!toggle || !menu || !dayContainer) return;
  7609.         
  7610.         // Calculer et mettre à jour les compteurs initiaux
  7611.         updateDayFilterCounts(dropdown, dayContainer);
  7612.         
  7613.         // Toggle dropdown
  7614.         toggle.addEventListener('click', (e) => {
  7615.           e.stopPropagation();
  7616.           const isOpen = dropdown.classList.contains('open');
  7617.           
  7618.           // Fermer tous les autres dropdowns
  7619.           document.querySelectorAll('.day-filter-dropdown.open').forEach(d => {
  7620.             if (d !== dropdown) d.classList.remove('open');
  7621.           });
  7622.           
  7623.           // Toggle le dropdown actuel
  7624.           dropdown.classList.toggle('open', !isOpen);
  7625.         });
  7626.         
  7627.         // Gérer les clics sur les options
  7628.         options.forEach(option => {
  7629.           option.addEventListener('click', (e) => {
  7630.             e.stopPropagation();
  7631.             const filter = option.dataset.filter;
  7632.             
  7633.             // Mettre à jour l'état actif
  7634.             options.forEach(opt => opt.classList.remove('active'));
  7635.             option.classList.add('active');
  7636.             
  7637.             // Appliquer le filtre
  7638.             applyDayFilter(dayContainer, filter);
  7639.             
  7640.             // Fermer le dropdown
  7641.             dropdown.classList.remove('open');
  7642.           });
  7643.         });
  7644.       });
  7645.       
  7646.       // Fermer les dropdowns en cliquant ailleurs
  7647.       document.addEventListener('click', () => {
  7648.         document.querySelectorAll('.day-filter-dropdown.open').forEach(dropdown => {
  7649.           dropdown.classList.remove('open');
  7650.         });
  7651.       });
  7652.     }
  7653.     function updateDayFilterCounts(dropdown, dayContainer) {
  7654.       const photoItems = dayContainer.querySelectorAll('[data-type=\"photo\"]');
  7655.       const videoItems = dayContainer.querySelectorAll('[data-type=\"video\"]');
  7656.       // Compter les messages audio individuels plutôt que les conteneurs
  7657.       const audioMessageItems = dayContainer.querySelectorAll('.audio-message-item[data-type=\"audio\"]');
  7658.       const audioContainers = dayContainer.querySelectorAll('.audio-messages-container[data-type=\"audio\"]');
  7659.       const audioRestricted = dayContainer.querySelectorAll('.audio-messages-restricted[data-type=\"audio\"]');
  7660.       
  7661.       const allItems = dayContainer.querySelectorAll('[data-type]');
  7662.       
  7663.       const countAll = dropdown.querySelector('[data-count-all]');
  7664.       const countPhoto = dropdown.querySelector('[data-count-photo]');
  7665.       const countVideo = dropdown.querySelector('[data-count-video]');
  7666.       const countAudio = dropdown.querySelector('[data-count-audio]');
  7667.       
  7668.       // Compter les messages audio individuels + conteneurs + sections restreintes
  7669.       const totalAudio = audioMessageItems.length + audioContainers.length + audioRestricted.length;
  7670.       
  7671.       if (countAll) countAll.textContent = allItems.length;
  7672.       if (countPhoto) countPhoto.textContent = photoItems.length;
  7673.       if (countVideo) countVideo.textContent = videoItems.length;
  7674.       if (countAudio) countAudio.textContent = totalAudio;
  7675.       
  7676.       // Masquer les options sans contenu
  7677.       const photoOption = dropdown.querySelector('[data-filter=\"photo\"]');
  7678.       const videoOption = dropdown.querySelector('[data-filter=\"video\"]');
  7679.       const audioOption = dropdown.querySelector('[data-filter=\"audio\"]');
  7680.       
  7681.       if (photoOption) photoOption.style.display = photoItems.length > 0 ? 'flex' : 'none';
  7682.       if (videoOption) videoOption.style.display = videoItems.length > 0 ? 'flex' : 'none';
  7683.       if (audioOption) audioOption.style.display = totalAudio > 0 ? 'flex' : 'none';
  7684.     }
  7685.     function applyDayFilter(dayContainer, filter) {
  7686.       const items = dayContainer.querySelectorAll('[data-type]');
  7687.       
  7688.       items.forEach(item => {
  7689.         if (filter === 'all' || item.dataset.type === filter) {
  7690.           item.style.display = '';
  7691.           item.classList.remove('filtered-out');
  7692.         } else {
  7693.           item.style.display = 'none';
  7694.           item.classList.add('filtered-out');
  7695.         }
  7696.       });
  7697.       
  7698.       // Animation fluide pour les éléments visibles
  7699.       requestAnimationFrame(() => {
  7700.         const visibleItems = dayContainer.querySelectorAll('[data-type]:not(.filtered-out)');
  7701.         visibleItems.forEach((item, index) => {
  7702.           item.style.animation = `fadeInUp 0.3s ease forwards \${index * 0.05}s`;
  7703.         });
  7704.       });
  7705.     }
  7706.     // Animation CSS pour fadeInUp
  7707.     if (!document.querySelector('#dayFilterAnimations')) {
  7708.       const style = document.createElement('style');
  7709.       style.id = 'dayFilterAnimations';
  7710.       style.textContent = `
  7711.         @keyframes fadeInUp {
  7712.           from {
  7713.             opacity: 0;
  7714.             transform: translateY(20px);
  7715.           }
  7716.           to {
  7717.             opacity: 1;
  7718.             transform: translateY(0);
  7719.           }
  7720.         }
  7721.       `;
  7722.       document.head.appendChild(style);
  7723.     }
  7724.     document.addEventListener(\"DOMContentLoaded\", function () {
  7725.       const dateCards = document.querySelectorAll(\".date-card\");
  7726.       const sections = document.querySelectorAll(\".collapse\");
  7727.       dateCards.forEach((card) => {
  7728.         card.addEventListener(\"click\", function () {
  7729.           // Supprimer les classes actives des autres cartes et sections
  7730.           dateCards.forEach((c) => c.classList.remove(\"active\"));
  7731.           sections.forEach((s) => s.classList.remove(\"show\"));
  7732.           // Ajouter la classe active à la carte cliquée
  7733.           this.classList.add(\"active\");
  7734.           // Récupérer la cible et afficher la bonne section
  7735.           const targetId = this.getAttribute(\"data-bs-target\");
  7736.           const targetSection = document.querySelector(targetId);
  7737.           if (targetSection) {
  7738.             targetSection.classList.add(\"show\");
  7739.           }
  7740.         });
  7741.       });
  7742.     });
  7743.     document.addEventListener(\"DOMContentLoaded\", function () {
  7744.       // Initialisation du carrousel Splide
  7745.       var splide = new Splide(\"#imageSlider\", {
  7746.         type: \"loop\",
  7747.         perPage: 1,
  7748.         autoplay: true,
  7749.         interval: 6000,
  7750.         pauseOnHover: false,
  7751.         pauseOnFocus: false,
  7752.         pagination: false,
  7753.         arrows: false,
  7754.       });
  7755.       splide.mount();
  7756.       // ⚠️ Scroll automatique désactivé pour meilleure UX
  7757.       // Les utilisateurs peuvent défiler manuellement quand ils le souhaitent
  7758.     });
  7759.   </script>
  7760.   <script>
  7761.    
  7762.     const giftButton = document.querySelector('.gift-button');
  7763.     if (giftButton) {
  7764.         giftButton.addEventListener('click', () => {
  7765.         // Ajouter la classe 'active' pour déclencher l'éclat
  7766.             giftButton.classList.add('active');
  7767.         // Retirer l'animation après qu'elle soit jouée
  7768.         setTimeout(() => {
  7769.                 giftButton.classList.remove('active');
  7770.         }, 600); // La durée doit correspondre à celle de l'animation
  7771.             
  7772.             // Optionnel : rediriger vers la page de commande
  7773.             // window.location.href = '/commande';
  7774.     });
  7775.     }
  7776.     
  7777.     //const HeartAddButton = document.querySelector('.IconDelete');
  7778.     \$(\".IconDelete\").on('click', () => {
  7779.         // Ajouter la classe 'active' pour déclencher l'éclat
  7780.         favoriteButton.classList.add('active');
  7781.         // Retirer l'animation après qu'elle soit jouée
  7782.         setTimeout(() => {
  7783.             favoriteButton.classList.remove('active');
  7784.         }, 600); // La durée doit correspondre à celle de l'animation
  7785.     });
  7786.     \$(document).ready(function() {
  7787.         // Attach click event to collapse triggers
  7788.         const lastCard = \$('.date-card.modern-card.active');
  7789.         const lastTargetId = lastCard.attr('data-bs-target');
  7790.         if (lastTargetId) {
  7791.             \$(lastTargetId).collapse('show'); // Expand the last collapse section
  7792.             LoadImagesCloud(\$(lastTargetId)); // Load images for the last day
  7793.         }
  7794.         \$('[data-bs-toggle=\"collapse\"]').on('click', function() {
  7795.             var targetId = \$(this).attr('data-bs-target'); // Get the target ID
  7796.             \$('.date-card.modern-card').removeClass('active'); // Remove 'active' class from all cards
  7797.             \$(this).addClass('active'); // Add 'active' class to the clicked card
  7798.             LoadImagesCloud(\$(targetId)); // Ensure this function works as expected
  7799.                // Hide all other collapses except the one clicked
  7800.                \$('[data-bs-target]').each(function() {
  7801.                 var currentTargetId = \$(this).attr('data-bs-target');
  7802.                 // If the current collapse is not the one clicked, hide it
  7803.                 if (currentTargetId !== targetId) {
  7804.                     \$(currentTargetId).collapse('hide');
  7805.                     //\$('[data-bs-toggle=\"collapse\"]').removeClass('active'); // Remove active class from all cards
  7806.                     //Modifier leurs style en non active aussi
  7807.                 }
  7808.             });
  7809.         });
  7810.     });
  7811.   
  7812.             \$(document).ready(function () {
  7813.               
  7814.                 ";
  7815.         // line 7533
  7816.         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.'7533$this->source); })()), "session", [], "any"falsefalsefalse7533), "get", ["paymentmoniteco"], "method"falsefalsefalse7533)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  7817.             // line 7534
  7818.             yield "                ";
  7819.             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.'7534$this->source); })()), "session", [], "any"falsefalsefalse7534), "get", ["paymentmoniteco"], "method"falsefalsefalse7534) == "succses")) {
  7820.                 // line 7535
  7821.                 yield "
  7822.                 Swal.fire({
  7823.                     icon: 'success',
  7824.                     title: ' succès ',
  7825.                     text: 'votre commande est validée'
  7826.                 });
  7827.                 ";
  7828.             }
  7829.             // line 7545
  7830.             yield "                ";
  7831.         }
  7832.         // line 7546
  7833.         yield "
  7834.                 if (\$total1 > 0) {
  7835.                     \$('.iconeFleche').first().click();
  7836.                     //  \$([document.documentElement, document.body]).animate({
  7837.                     //  scrollTop: \$('.iconeFleche').last().offset().top
  7838.                     //  }, );
  7839.                 }
  7840.                 else {
  7841.                     \$(window).scrollTop(0);
  7842.                 }
  7843.                 var slider = \$('.responsive').slick({
  7844.                     infinite: true,
  7845.                     slidesToShow: 1,
  7846.                     slidesToScroll: 1,
  7847.                     autoplay: true,
  7848.                     autoplaySpeed: 4000,
  7849.                     pauseOnFocus: false,
  7850.                     pauseOnHover: false,
  7851.                     draggable: false,
  7852.                     fade: true
  7853.                 });
  7854.                 \$('.responsive').css('display', 'block');
  7855.                 \$('.namePRD').css('display', 'block');
  7856.                 var currSlide = 0;
  7857.                 var nextSlide = 0;
  7858.                 slider.on('afterChange', function (event, slick, currentSlide) {
  7859.                     console.log(typeof (\$('.slick-active .slick-current').find('.imgproduit2')) != \"undefined\");
  7860.                     if (typeof (\$('.slick-active .slick-current').find('.imgproduit2')) != \"undefined\") {
  7861.                         setTimeout(function () {
  7862.                             \$('.slick-active .imgproduit1').removeClass('animated fadeIn');
  7863.                             \$('.slick-active .imgproduit1').addClass('animated fadeOut');
  7864.                             \$('.slick-active .imgproduit1').css('display', 'none');
  7865.                             \$('.slick-active .imgproduit2').css('display', 'block');
  7866.                             \$('.slick-active .imgproduit2').removeClass('animated fadeOut');
  7867.                             \$('.slick-active .imgproduit2').addClass('animated fadeIn');
  7868.                         }, 2000);
  7869.                     }
  7870.                 });
  7871.                 slider.on('beforeChange', function (event, slick, currentSlide, nextSlide) {
  7872.                     currSlide = currentSlide;
  7873.                     \$('.imgproduit2').each(function () {
  7874.                         \$(this).removeClass('animated fadeIn');
  7875.                         \$(this).addClass('animated fadeOut');
  7876.                         \$(this).css('display', 'none');
  7877.                     });
  7878.                     \$('.imgproduit1').each(function () {
  7879.                         \$(this).css('display', 'block');
  7880.                         \$(this).removeClass('animated fadeOut');
  7881.                         \$(this).addClass('animated fadeIn');
  7882.                     });
  7883.                 });
  7884.                 \$('.columnPub').each(function () {
  7885.                     \$(this).slick({
  7886.                         infinite: true,
  7887.                         speed: 50,
  7888.                         fade: true,
  7889.                         slidesToShow: 1,
  7890.                         slidesToScroll: 1,
  7891.                         autoplay: true,
  7892.                         pauseOnFocus: false,
  7893.                         pauseOnHover: false,
  7894.                         draggable: false
  7895.                     });
  7896.                     \$(this).css('display', 'block');
  7897.                 });
  7898.                 \$(\"#offrePack\").click();
  7899.                 ";
  7900.         // line 7620
  7901.         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.'7620$this->source); })()), "user", [], "any"falsefalsefalse7620), "showpubprod", [], "any"falsefalsefalse7620) != "false")) {
  7902.             // line 7621
  7903.             yield "                \$('#btnPubProd').click();
  7904.                 \$('.modal-backdrop').css('background-color', 'rgba(0, 0, 0, 0.2)');
  7905.                 ";
  7906.         }
  7907.         // line 7624
  7908.         yield "            });
  7909.             \$(\"#closeImage\").click(function () {
  7910.                 \$('#myModalImage').css('display', \"none\");
  7911.             });
  7912.             \$.ajax({
  7913.                 type: \"POST\",
  7914.                 url: \"";
  7915.         // line 7630
  7916.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("delateSession_parent");
  7917.         yield "\",
  7918.                 success: function () { }
  7919.             });
  7920.             function afficheDiv(elem) {
  7921.                 \$('.nav-link').each(function () {
  7922.                     \$(this).removeClass('active');
  7923.                 });
  7924.                 elem.addClass('active');
  7925.                 if (elem.attr('id') === \"esphoto\" || elem.attr('id') === \"esphotoMobile\") {
  7926.                     \$(\"#espacphoto\").show();
  7927.                     \$(\"#espacemessage\").hide();
  7928.                     \$(\"#espaceMa_selection\").hide();
  7929.                     pageMenu = 'MonSejour'
  7930.                     \$(this).addClass('active');
  7931.                    \$('#imageActifphoto').css('display', 'block');
  7932.                      \$('#imagenoActifphoto').css('display', 'none');
  7933.                    \$('#VocalActivee').css('display', 'none');
  7934.                      \$('#noActifVocal').css('display', 'block');
  7935.                 }
  7936.                 if (elem.attr('id') === \"esmessage\" || elem.attr('id') === \"esmessageMobile\") {
  7937.                     \$(\"#espacphoto\").hide();
  7938.                     \$(\"#espaceMa_selection\").hide();
  7939.                     \$(\"#espacemessage\").show();
  7940.                     pageMenu = 'BoiteVocale'
  7941.                     \$(\"#espaceMa_selection\").hide();
  7942.                     \$(this).addClass('active');
  7943.                   \$('#imageActifphoto').css('display', 'none');
  7944.                      \$('#imagenoActifphoto').css('display', 'block');
  7945.                    \$('#VocalActivee').css('display', 'block');
  7946.                      \$('#noActifVocal').css('display', 'none');
  7947.                 }
  7948.                 if (elem.attr('id') === \"esselection\" || elem.attr('id') === \"esselectionMobile\") {
  7949.                     \$(\"#espacphoto\").hide();
  7950.                     \$(\"#espacemessage\").hide();
  7951.                     \$(\"#espaceMa_selection\").show();
  7952.                     \$(homeNavmob).removeClass('bi bi-house-door-fill');
  7953.                     \$(homeNavmob).addClass('bi bi-house-door');
  7954.                     \$(micromob).removeClass('bi bi-mic-fill');
  7955.                     \$(micromob).addClass('bi bi-mic');
  7956.                     \$(selecNavmob).removeClass('bi bi-heart');
  7957.                     \$(selecNavmob).addClass('bi bi-heart-fill');
  7958.                 }
  7959.             }
  7960.             function LoadImagesCloud(\$element) {
  7961.                 \$element.find('.photo-zoom img').each(function (\$this) {
  7962.                     if (\$(this).attr('data-src') != \$(this).attr('src')) {
  7963.                         \$(this).attr('src', \$(this).attr('data-src'));
  7964.                     }
  7965.                 });
  7966.             }
  7967.   </script>
  7968.   <script>
  7969.     // ⚡ OPTIMISATION: Regroupement des initialisations jQuery
  7970.     \$(document).ready(function () {
  7971.       // Modal PubProd
  7972.       \$(\"#PubProd\").on(\"hidden.bs.modal\", function () {
  7973.         \$(document).trigger(\"modalClosed\");
  7974.       });
  7975.       
  7976.       // NoShow checkbox
  7977.       \$(\"#noShow\").on(\"change\", function () {
  7978.         if (\$(this).is(\":checked\")) {
  7979.           \$.ajax({
  7980.             url: \"/Parent/showpub\",
  7981.             type: \"POST\",
  7982.             dataType: \"json\",
  7983.             success: function (response) {
  7984.               if (response.status === \"success\") {
  7985.                 console.log(\"User showpubprod updated successfully.\");
  7986.               } else {
  7987.                 console.log(\"Error:\", response.message);
  7988.               }
  7989.             },
  7990.             error: function (xhr, status, error) {
  7991.               console.log(\"AJAX Error:\", error);
  7992.             },
  7993.           });
  7994.         }
  7995.       });
  7996.     });
  7997.   </script>
  7998. </div>
  7999. <!-- Script pour la sidebar des favoris -->
  8000. <script>
  8001.   // ⚡ OPTIMISATION: Utiliser requestIdleCallback pour ne pas bloquer le thread principal
  8002.  
  8003.   
  8004.     
  8005.     // Charger les favoris
  8006.     function loadFavorites() {
  8007.       \$.ajax({
  8008.         url: \"/Parent/mes-favoris\",
  8009.         type: \"GET\",
  8010.         dataType: \"json\",
  8011.         beforeSend: function() {
  8012.           \$(\"#favorites-grid\").html(\"<div style='text-align:center'>Chargement...</div>\");
  8013.         },
  8014.         success: function(data) {
  8015.           \$(\"#favorites-grid\").empty();
  8016.           
  8017.           if (data.data && data.data.length > 0) {
  8018.             \$(\"#favorites-empty-state\").hide();
  8019.             
  8020.             \$.each(data.data, function(i, fav) {
  8021.               var item = \$(\"<div class='favorite-item'></div>\");
  8022.               var img = \$(\"<img>\").attr(\"src\", fav.path).attr(\"alt\", fav.descreption || \"Photo favorite\");
  8023.               var overlay = \$(\"<div class='favorite-overlay'></div>\");
  8024.         
  8025.               
  8026.               btn.click(function(e) {
  8027.                 e.preventDefault();
  8028.                 e.stopPropagation();
  8029.                 removeFavorite(fav.id);
  8030.               });
  8031.               
  8032.               overlay.append(btn);
  8033.               item.append(img).append(overlay);
  8034.               \$(\"#favorites-grid\").append(item);
  8035.             });
  8036.             
  8037.             \$(\"#favorites-counter\").text(data.data.length);
  8038.             var percentage = (data.data.length / 10) * 100;
  8039.             \$(\"#favorites-progress\").css(\"width\", percentage + \"%\");
  8040.             
  8041.           } else {
  8042.             \$(\"#favorites-empty-state\").show();
  8043.             \$(\"#favorites-counter\").text(\"0\");
  8044.             \$(\"#favorites-progress\").css(\"width\", \"0%\");
  8045.           }
  8046.         },
  8047.         error: function() {
  8048.           \$(\"#favorites-grid\").html(\"<div style='color:red;text-align:center'>Erreur de chargement</div>\");
  8049.         }
  8050.       });
  8051.     }
  8052.     
  8053.     // Supprimer un favori
  8054.     function removeFavorite(id) {
  8055.       \$.ajax({
  8056.         url: \"/Parent/remove-favorite/\" + id,
  8057.         type: \"POST\",
  8058.         success: function() {
  8059.           loadFavorites();
  8060.           
  8061.           // Mettre à jour tous les compteurs de favoris
  8062.           updateAllFavoriteCounters();
  8063.         },
  8064.         error: function() {
  8065.           alert(\"Erreur lors de la suppression du favori\");
  8066.         }
  8067.       });
  8068.     }
  8069.   });
  8070. </script>
  8071. <!-- === E-COMMERCE SIDEBAR JAVASCRIPT === -->
  8072. <script>
  8073. // Configuration UX_VARIANT pour A/B testing
  8074. let UX_VARIANT = 'EMOTION'; // ou 'URGENCY'
  8075. // Variables globales e-commerce
  8076. let sejourEndDate = null; // À définir avec la vraie date de fin du séjour
  8077. // Fonction utilitaire robuste pour gérer les compteurs de favoris
  8078. window.getFavoriteCount = function getFavoriteCount() {
  8079.   const likeCountInput = document.getElementById('likeCount');
  8080.   if (likeCountInput) {
  8081.     // Priorité à la valeur de l'input
  8082.     const value = likeCountInput.value || likeCountInput.textContent || 0;
  8083.     return parseInt(value, 10) || 0;
  8084.   }
  8085.   
  8086.   // Fallback sur giftCount
  8087.   const giftCount = document.getElementById('giftCount');
  8088.   if (giftCount && giftCount.textContent) {
  8089.     return parseInt(giftCount.textContent.trim(), 10) || 0;
  8090.   }
  8091.   
  8092.   return 0;
  8093. };
  8094. window.setFavoriteCount = function setFavoriteCount(count) {
  8095.   const likeCountInput = document.getElementById('likeCount');
  8096.   if (likeCountInput) {
  8097.     // Mettre à jour les deux propriétés pour être sûr
  8098.     likeCountInput.value = count;
  8099.     likeCountInput.textContent = count;
  8100.   }
  8101.   
  8102.   // Mettre à jour les autres compteurs
  8103.   const giftCount = document.getElementById('giftCount');
  8104.   if (giftCount) {
  8105.     giftCount.textContent = count;
  8106.   }
  8107.   
  8108.   const mesFavCount = document.getElementById('mesFavCount');
  8109.   if (mesFavCount) {
  8110.     mesFavCount.textContent = count;
  8111.   }
  8112.   
  8113.   // Mettre à jour l'input hidden
  8114.   const nbFavCurrentInput = document.getElementById('nbFavCurrent');
  8115.   if (nbFavCurrentInput) {
  8116.     nbFavCurrentInput.value = count;
  8117.   }
  8118. };
  8119. // Fonction pour définir la date de fin du séjour
  8120. window.setSejourEndDate = function setSejourEndDate(dateString) {
  8121.   sejourEndDate = dateString;
  8122.   console.log('🎯 Sejour end date set to:', sejourEndDate);
  8123.   
  8124.   // Mettre à jour le countdown si le sidebar est ouvert
  8125.   updateCountdownTimer();
  8126. };
  8127. // Fonctions d'ouverture/fermeture du sidebar
  8128. window.openEcommerceSidebar = function openEcommerceSidebar() {
  8129.   const sidebar = document.getElementById('ecommerce-sidebar');
  8130.   if (!sidebar) {
  8131.     console.error('❌ E-commerce sidebar element not found!');
  8132.     return false;
  8133.   }
  8134.   
  8135.   console.log('🎁 [OPEN SIDEBAR] Ouverture du sidebar e-commerce...');
  8136.   const favCount = window.getFavoriteCount ? window.getFavoriteCount() : 0;
  8137.   console.log('🎁 [OPEN SIDEBAR] Favoris actuels:', favCount);
  8138.   
  8139.   // D'abord ouvrir le sidebar pour que les éléments soient dans le DOM
  8140.   sidebar.classList.add('active');
  8141.   console.log('🎁 [OPEN SIDEBAR] Sidebar classe \"active\" ajoutée');
  8142.   
  8143.   // Puis mettre à jour le contenu (petit délai pour que le DOM soit prêt)
  8144.   setTimeout(() => {
  8145.     console.log('🎁 [OPEN SIDEBAR] Mise à jour du contenu...');
  8146.     
  8147.     // Appeler la fonction de parent-toasts.js
  8148.     if (typeof window.parentConversion !== 'undefined' && typeof window.parentConversion.updateSidebar === 'function') {
  8149.       console.log('✅ [OPEN SIDEBAR] Appel de parentConversion.updateSidebar()');
  8150.       window.parentConversion.updateSidebar();
  8151.     } else {
  8152.       console.warn('⚠️ [OPEN SIDEBAR] parent-toasts.js non disponible, fallback sur fonction locale');
  8153.       // Fallback sur la fonction locale
  8154.       if (typeof window.updateEcommerceSidebarContent === 'function') {
  8155.         window.updateEcommerceSidebarContent(favCount);
  8156.       }
  8157.     }
  8158.   }, 100); // 100ms de délai pour que le sidebar soit visible
  8159.   
  8160.   return true;
  8161. };
  8162. window.closeEcommerceSidebar = function closeEcommerceSidebar() {
  8163.   const sidebar = document.getElementById('ecommerce-sidebar');
  8164.   if (sidebar) {
  8165.     sidebar.classList.remove('active');
  8166.     console.log('🎯 E-commerce sidebar closed');
  8167.   } else {
  8168.     console.error('❌ E-commerce sidebar element not found!');
  8169.   }
  8170. };
  8171. // 🚫 FONCTION LEGACY SUPPRIMÉE - Utiliser parent-toasts.js à la place
  8172. // Cette fonction était en conflit avec updateEcommerceSidebar() de parent-toasts.js
  8173. // qui gère TOUT : titre, sous-titre, compteurs, visibilité des produits, CTA, etc.
  8174. window.updateEcommerceSidebarContent = function updateEcommerceSidebarContent(favoriteCount) {
  8175.   console.warn('[LEGACY] updateEcommerceSidebarContent appelé - Redirection vers parent-toasts.js');
  8176.   
  8177.   // Rediriger vers la vraie fonction
  8178.   if (typeof window.parentConversion !== 'undefined' && typeof window.parentConversion.updateSidebar === 'function') {
  8179.     window.parentConversion.updateSidebar();
  8180.   } else {
  8181.     console.error('[LEGACY] parent-toasts.js non disponible !');
  8182.   }
  8183. }
  8184. // 🚫 FONCTION SUPPRIMÉE - Géré par parent-toasts.js
  8185. // Tout est maintenant géré dans updateEcommerceSidebar() de parent-toasts.js
  8186. // Fonction pour gérer le countdown
  8187. window.updateCountdownTimer = function updateCountdownTimer() {
  8188.   const countdownTimer = document.getElementById('countdown-timer');
  8189.   const daysLeftSpan = document.getElementById('days-left');
  8190.   
  8191.   if (!countdownTimer || !daysLeftSpan) return;
  8192.   
  8193.   // Si pas de date définie, utiliser une date par défaut (6 semaines à partir d'aujourd'hui)
  8194.   let expirationDate;
  8195.   if (sejourEndDate) {
  8196.     const endDate = new Date(sejourEndDate);
  8197.     expirationDate = new Date(endDate.getTime() + (6 * 7 * 24 * 60 * 60 * 1000)); // +6 semaines
  8198.   } else {
  8199.     // Date par défaut : 6 semaines à partir d'aujourd'hui
  8200.     expirationDate = new Date();
  8201.     expirationDate.setDate(expirationDate.getDate() + (6 * 7));
  8202.   }
  8203.   
  8204.   const now = new Date();
  8205.   const daysLeft = Math.ceil((expirationDate - now) / (24 * 60 * 60 * 1000));
  8206.   
  8207.   if (daysLeft <= 10 && daysLeft > 0) {
  8208.     countdownTimer.style.display = 'block';
  8209.     daysLeftSpan.textContent = daysLeft;
  8210.     
  8211.     // Mettre à jour les titres avec le countdown si variante URGENCY
  8212.     if (UX_VARIANT === 'URGENCY') {
  8213.       const title = document.getElementById('ecommerce-title');
  8214.       if (title) {
  8215.         const favoriteCount = parseInt(document.getElementById('giftCount')?.textContent || '0');
  8216.         if (favoriteCount > 0) {
  8217.           if (favoriteCount < 5) {
  8218.             title.innerHTML = `⏳ \${favoriteCount} souvenirs - Plus que \${daysLeft} jours !`;
  8219.           } else if (favoriteCount < 12) {
  8220.             title.innerHTML = `⏳ \${favoriteCount} magnifiques souvenirs - Plus que \${daysLeft} jours !`;
  8221.           } else {
  8222.             title.innerHTML = `⏳ Superbe collection de \${favoriteCount} photos - Plus que \${daysLeft} jours !`;
  8223.           }
  8224.         }
  8225.       }
  8226.     }
  8227.   } else {
  8228.     countdownTimer.style.display = 'none';
  8229.   }
  8230. }
  8231. // Fonction pour commander un produit
  8232. window.orderProduct = function orderProduct(productType) {
  8233.   let favoriteCount = 0;
  8234.   
  8235.   // Méthode 1: Fonction getCurrentFavoriteCount
  8236.   try {
  8237.     if (typeof getCurrentFavoriteCount === 'function') {
  8238.       favoriteCount = getCurrentFavoriteCount();
  8239.     }
  8240.   } catch (e) {
  8241.     console.log('⚠️ getCurrentFavoriteCount non disponible:', e);
  8242.   }
  8243.   
  8244.   // Méthode 2: Element giftCount
  8245.   if (favoriteCount === 0) {
  8246.     const giftCount = document.getElementById('giftCount');
  8247.     if (giftCount && giftCount.textContent) {
  8248.       favoriteCount = parseInt(giftCount.textContent.trim()) || 0;
  8249.     }
  8250.   }
  8251.   
  8252.   // Méthode 3: Récupérer depuis les éléments qui affichent le nombre de favoris
  8253.   if (favoriteCount === 0) {
  8254.     const albumFavCount = document.getElementById('album-fav-count');
  8255.     const digitalFavCount = document.getElementById('digital-fav-count');
  8256.     
  8257.     if (albumFavCount && albumFavCount.textContent) {
  8258.       favoriteCount = parseInt(albumFavCount.textContent.trim()) || 0;
  8259.     } else if (digitalFavCount && digitalFavCount.textContent) {
  8260.       favoriteCount = parseInt(digitalFavCount.textContent.trim()) || 0;
  8261.     }
  8262.   }
  8263.   
  8264.   // Méthode 4: Variable globale likes
  8265.   if (favoriteCount === 0 && typeof likes !== 'undefined' && likes) {
  8266.     favoriteCount = likes.length || 0;
  8267.   }
  8268.   
  8269.   // Méthode 5: Compter les éléments liked dans le DOM
  8270.   if (favoriteCount === 0) {
  8271.     const likedElements = document.querySelectorAll('.liked, .photo.liked, [data-liked=\"true\"]');
  8272.     favoriteCount = likedElements.length;
  8273.   }
  8274.   
  8275.   // Debug pour voir la valeur récupérée
  8276.   console.log('🔍 Nombre de favoris détecté:', favoriteCount);
  8277.   
  8278.   if (favoriteCount === 0) {
  8279.     // Afficher une notification plus élégante
  8280.     const notification = document.createElement('div');
  8281.     notification.className = 'favorite-notification';
  8282.     notification.innerHTML = `
  8283.       <div class=\"notification-content\">
  8284.         <i class=\"bi bi-heart\" style=\"color: #e91e63; font-size: 1.5rem; margin-right: 10px;\"></i>
  8285.         <span>Veuillez d'abord sélectionner des photos favorites !</span>
  8286.         <button onclick=\"this.parentElement.parentElement.remove()\" style=\"background: none; border: none; color: #666; font-size: 1.2rem; margin-left: 10px;\">&times;</button>
  8287.       </div>
  8288.     `;
  8289.     
  8290.     // Styles pour la notification
  8291.     notification.style.cssText = `
  8292.       position: fixed;
  8293.       top: 20px;
  8294.       right: 20px;
  8295.       background: #fff;
  8296.       border: 2px solid #e91e63;
  8297.       border-radius: 8px;
  8298.       padding: 15px;
  8299.       box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  8300.       z-index: 10000;
  8301.       animation: slideInRight 0.3s ease;
  8302.     `;
  8303.     
  8304.     // Ajouter l'animation CSS si elle n'existe pas
  8305.     if (!document.getElementById('notification-styles')) {
  8306.       const style = document.createElement('style');
  8307.       style.id = 'notification-styles';
  8308.       style.textContent = `
  8309.         @keyframes slideInRight {
  8310.           from { transform: translateX(100%); opacity: 0; }
  8311.           to { transform: translateX(0); opacity: 1; }
  8312.         }
  8313.         .notification-content {
  8314.           display: flex;
  8315.           align-items: center;
  8316.         }
  8317.       `;
  8318.       document.head.appendChild(style);
  8319.     }
  8320.     
  8321.     document.body.appendChild(notification);
  8322.     
  8323.     // Supprimer automatiquement après 5 secondes
  8324.     setTimeout(() => {
  8325.       if (notification.parentElement) {
  8326.         notification.remove();
  8327.       }
  8328.     }, 5000);
  8329.     
  8330.     return;
  8331.   }
  8332.   
  8333.   // Construire l'URL avec les favoris pré-sélectionnés
  8334.   let orderUrl = '';
  8335.   
  8336.   switch (productType) {
  8337.     case 'album':
  8338.       orderUrl = `";
  8339.         // line 8079
  8340.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("EditionAlbum");
  8341.         yield "?favorites=\${favoriteCount}`;
  8342.       break;
  8343.     case 'digital':
  8344.       orderUrl = `";
  8345.         // line 8082
  8346.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("PackPhotosNumerique_Favoris", ["nbr" => 15]);
  8347.         yield "?favorites=\${favoriteCount}`;
  8348.       break;
  8349.     case 'prints':
  8350.       orderUrl = `";
  8351.         // line 8085
  8352.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("AjoutPochettePhotos_Favoris", ["nbr" => 12]);
  8353.         yield "?favorites=\${favoriteCount}`;
  8354.       break;
  8355.     default:
  8356.       console.error('Type de produit non reconnu:', productType);
  8357.       alert('Erreur: Type de produit non reconnu');
  8358.       return;
  8359.   }
  8360.   
  8361.   // Analytics/tracking
  8362.   console.log('Product ordered', { productType, favoriteCount, url: orderUrl });
  8363.   
  8364.   // Redirection vers la commande
  8365.   if (orderUrl) {
  8366.     // Vérifier que l'URL est valide
  8367.     try {
  8368.       new URL(orderUrl, window.location.origin);
  8369.     window.location.href = orderUrl;
  8370.     } catch (error) {
  8371.       console.error('URL invalide générée:', orderUrl, error);
  8372.       alert('Erreur: Impossible de générer le lien de commande');
  8373.     }
  8374.   } else {
  8375.     console.error('Aucune URL générée pour le produit:', productType);
  8376.     alert('Erreur: Impossible de générer le lien de commande');
  8377.   }
  8378. }
  8379. // Fonction pour tester tous les liens de produits
  8380. window.testProductLinks = function() {
  8381.   const products = ['album', 'digital', 'prints'];
  8382.   const favoriteCount = window.getFavoriteCount() || 0;
  8383.   
  8384.   console.log('🧪 Test des liens de produits avec', favoriteCount, 'favoris');
  8385.   
  8386.   products.forEach(productType => {
  8387.     try {
  8388.       let testUrl = '';
  8389.       switch (productType) {
  8390.         case 'album':
  8391.           testUrl = `";
  8392.         // line 8124
  8393.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("EditionAlbum");
  8394.         yield "?favorites=\${favoriteCount}`;
  8395.           break;
  8396.         case 'digital':
  8397.           testUrl = `";
  8398.         // line 8127
  8399.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("PackPhotosNumerique_Favoris", ["nbr" => 15]);
  8400.         yield "?favorites=\${favoriteCount}`;
  8401.           break;
  8402.         case 'prints':
  8403.           testUrl = `";
  8404.         // line 8130
  8405.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("AjoutPochettePhotos_Favoris", ["nbr" => 12]);
  8406.         yield "?favorites=\${favoriteCount}`;
  8407.           break;
  8408.       }
  8409.       
  8410.       // Vérifier que l'URL est valide
  8411.       const url = new URL(testUrl, window.location.origin);
  8412.       console.log(`✅ \${productType}: \${url.href}`);
  8413.     } catch (error) {
  8414.       console.error(`❌ \${productType}: Erreur URL`, error);
  8415.     }
  8416.   });
  8417. };
  8418. // Fonction pour valider les liens au chargement de la page
  8419. window.validateProductLinks = function() {
  8420.   // Vérifier que tous les boutons de produits existent
  8421.   const albumBtn = document.querySelector('button[onclick*=\"orderProduct(\\'album\\')\"]');
  8422.   const digitalBtn = document.querySelector('button[onclick*=\"orderProduct(\\'digital\\')\"]');
  8423.   const printsBtn = document.querySelector('button[onclick*=\"orderProduct(\\'prints\\')\"]');
  8424.   
  8425.   if (!albumBtn) console.warn('⚠️ Bouton album non trouvé');
  8426.   if (!digitalBtn) console.warn('⚠️ Bouton digital non trouvé');
  8427.   if (!printsBtn) console.warn('⚠️ Bouton prints non trouvé');
  8428.   
  8429.   // Tester les liens
  8430.   window.testProductLinks();
  8431. };
  8432. // Fonction centrale de mise à jour de TOUS les compteurs de favoris
  8433. window.updateAllFavoriteCounters = function() {
  8434.   // Récupérer le compte depuis #mesFavCount (source unique de vérité)
  8435.   const mesFavCount = document.getElementById('mesFavCount');
  8436.   let favoriteCount = 0;
  8437.   
  8438.   if (mesFavCount) {
  8439.     favoriteCount = parseInt(mesFavCount.textContent || '0');
  8440.   }
  8441.   
  8442.   console.log('[updateAllFavoriteCounters] 💗 Synchronisation:', favoriteCount, 'favoris');
  8443.   
  8444.   // Synchroniser giftCount (bouton cadeau) avec animation
  8445.   const giftCount = document.getElementById('giftCount');
  8446.   if (giftCount) {
  8447.     giftCount.textContent = favoriteCount;
  8448.     giftCount.classList.remove('gift-count-bounce');
  8449.     setTimeout(() => giftCount.classList.add('gift-count-bounce'), 10);
  8450.   }
  8451.   
  8452.   // Mettre à jour les compteurs dans le sidebar même s'il n'est pas ouvert
  8453.   const albumCount = document.getElementById('album-count');
  8454.   const digitalCount = document.getElementById('digital-count');
  8455.   const printsCount = document.getElementById('prints-count');
  8456.   
  8457.   if (albumCount) albumCount.textContent = favoriteCount;
  8458.   if (digitalCount) digitalCount.textContent = favoriteCount;
  8459.   if (printsCount) printsCount.textContent = Math.min(favoriteCount, 12);
  8460.   
  8461.   // Mettre à jour les icônes de favoris dans les produits
  8462.   const albumFavCount = document.getElementById('album-fav-count');
  8463.   const digitalFavCount = document.getElementById('digital-fav-count');
  8464.   const printsFavCount = document.getElementById('prints-fav-count');
  8465.   
  8466.   if (albumFavCount) albumFavCount.textContent = favoriteCount;
  8467.   if (digitalFavCount) digitalFavCount.textContent = favoriteCount;
  8468.   if (printsFavCount) printsFavCount.textContent = Math.min(favoriteCount, 12);
  8469.   
  8470.   // Mettre à jour le sidebar si ouvert
  8471.   const sidebar = document.getElementById('ecommerce-sidebar');
  8472.   if (sidebar && sidebar.classList.contains('active')) {
  8473.     console.log('🔄 Sidebar is open, updating content with favoriteCount:', favoriteCount);
  8474.     window.updateEcommerceSidebarContent(favoriteCount);
  8475.   } else {
  8476.     console.log('ℹ️ Sidebar is closed, but updating content anyway for consistency');
  8477.     // Mettre à jour le contenu même si le sidebar n'est pas ouvert pour la cohérence
  8478.     window.updateEcommerceSidebarContent(favoriteCount);
  8479.   }
  8480. };
  8481. // Fonction pour retirer un favori de la grille et exécuter supprimerFavoris
  8482. window.removeFavorite = function removeFavorite(itemId) {
  8483.   // Animation simple de disparition puis suppression
  8484.   const favoriteItem = document.querySelector(`.favorite-item[data-id=\"\${itemId}\"]`);
  8485.  
  8486.   if (favoriteItem) {
  8487.     favoriteItem.classList.add('fade-out');
  8488.     setTimeout(() => {
  8489.       favoriteItem.remove();
  8490.       // Appeler la fonction métier si présente
  8491.       if (typeof window.supprimerFavoris === 'function') {
  8492.         const heartIcon = document.querySelector(`#coeur\${itemId}`);
  8493.         const sejourId = heartIcon && heartIcon.dataset.sejourId ? heartIcon.dataset.sejourId : '';
  8494.         window.supprimerFavoris(itemId, sejourId);
  8495.       }
  8496.       // Mettre à jour les compteurs
  8497.       updateAllFavoriteCounters();
  8498.     }, 200);
  8499.   }
  8500. };
  8501. // Vérifier que la fonction est bien définie
  8502. console.log('🔍 removeFavorite function defined:', typeof window.removeFavorite);
  8503. // (Nettoyé) Pas de délégation globale ici; les boutons utilisent des onclick simples
  8504. // Fonction pour voir un favori en grand
  8505. window.viewFavorite = function viewFavorite(itemId) {
  8506.   console.log('👁️ Viewing favorite:', itemId);
  8507.   
  8508.   // Essayer d'utiliser la fonction viewImage existante
  8509.   if (typeof window.viewImage === 'function') {
  8510.     window.viewImage(itemId, null);
  8511.   } else {
  8512.     console.log('ℹ️ viewImage function not available, opening in new tab');
  8513.     // Fallback: ouvrir dans un nouvel onglet
  8514.     const favoriteItem = document.querySelector(`.favorite-item[data-id=\"\${itemId}\"] img`);
  8515.     if (favoriteItem && favoriteItem.src) {
  8516.       window.open(favoriteItem.src, '_blank');
  8517.     }
  8518.   }
  8519. };
  8520. // Fonction de debug pour tester les compteurs
  8521. window.debugFavoriteCounters = function() {
  8522.   console.log('🔍 Debug Favorite Counters:');
  8523.   console.log('- getFavoriteCount():', window.getFavoriteCount());
  8524.   console.log('- likeCount input value:', document.getElementById('likeCount')?.value);
  8525.   console.log('- likeCount textContent:', document.getElementById('likeCount')?.textContent);
  8526.   console.log('- giftCount textContent:', document.getElementById('giftCount')?.textContent);
  8527.   console.log('- album-count textContent:', document.getElementById('album-count')?.textContent);
  8528.   console.log('- digital-count textContent:', document.getElementById('digital-count')?.textContent);
  8529.   console.log('- prints-count textContent:', document.getElementById('prints-count')?.textContent);
  8530.   console.log('- Sidebar active:', document.getElementById('ecommerce-sidebar')?.classList.contains('active'));
  8531. };
  8532. // Fonction de test pour les boutons de favoris
  8533. window.testFavoriteButtons = function() {
  8534.   console.log('🧪 Testing favorite buttons:');
  8535.   const removeButtons = document.querySelectorAll('.btn-remove-favorite');
  8536.   const viewButtons = document.querySelectorAll('.btn-view-favorite');
  8537.   
  8538.   console.log('- Remove buttons found:', removeButtons.length);
  8539.   console.log('- View buttons found:', viewButtons.length);
  8540.   
  8541.   removeButtons.forEach((btn, index) => {
  8542.     console.log(`- Remove button \${index}:`, {
  8543.       itemId: btn.dataset.itemId,
  8544.       hasClickListener: btn.onclick !== null
  8545.     });
  8546.   });
  8547.   
  8548.   viewButtons.forEach((btn, index) => {
  8549.     console.log(`- View button \${index}:`, {
  8550.       itemId: btn.dataset.itemId,
  8551.       hasClickListener: btn.onclick !== null
  8552.     });
  8553.   });
  8554. };
  8555. // Fermer le sidebar en cliquant en dehors
  8556. document.addEventListener('click', function(e) {
  8557.   const sidebar = document.getElementById('ecommerce-sidebar');
  8558.   const giftButton = document.querySelector('.gift-button');
  8559.   
  8560.   if (sidebar && sidebar.classList.contains('active') && 
  8561.       !sidebar.contains(e.target) && 
  8562.       !giftButton.contains(e.target)) {
  8563.     window.closeEcommerceSidebar();
  8564.   }
  8565. });
  8566. // Fermer avec Escape
  8567. document.addEventListener('keydown', function(e) {
  8568.   if (e.key === 'Escape') {
  8569.     window.closeEcommerceSidebar();
  8570.   }
  8571. });
  8572. // Initialisation au chargement
  8573. document.addEventListener('DOMContentLoaded', function() {
  8574.   // Vérifier que les éléments existent
  8575.   const sidebar = document.getElementById('ecommerce-sidebar');
  8576.   const giftButton = document.getElementById('gift-button-trigger');
  8577.   
  8578.   // Event listener propre pour le bouton cadeau
  8579.   if (giftButton) {
  8580.     giftButton.addEventListener('click', function(e) {
  8581.       e.preventDefault();
  8582.       e.stopPropagation();
  8583.       window.openEcommerceSidebar();
  8584.     });
  8585.   }
  8586.   
  8587.   // Définir la date de fin du séjour si disponible
  8588.   ";
  8589.         // line 8323
  8590.         if (((isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'8323$this->source); })()) && CoreExtension::getAttribute($this->env$this->source, ($context["sejour"] ?? null), "dateFinSejour", [], "any"truetruefalse8323))) {
  8591.             // line 8324
  8592.             yield "    window.setSejourEndDate('";
  8593.             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.'8324$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse8324), "Y-m-d"), "html"nulltrue);
  8594.             yield "');
  8595.   ";
  8596.         }
  8597.         // line 8326
  8598.         yield "  
  8599.   // Mise à jour initiale du contenu
  8600.   let favoriteCount = 0;
  8601.   try {
  8602.     if (typeof getCurrentFavoriteCount === 'function') {
  8603.       favoriteCount = getCurrentFavoriteCount();
  8604.     } else {
  8605.       // Essayer d'abord l'input likeCount
  8606.       const likeCountInput = document.getElementById('likeCount');
  8607.       if (likeCountInput && likeCountInput.value) {
  8608.         favoriteCount = parseInt(likeCountInput.value, 10) || 0;
  8609.       } else {
  8610.         // Fallback sur giftCount
  8611.         const giftCount = document.getElementById('giftCount');
  8612.         if (giftCount && giftCount.textContent) {
  8613.           favoriteCount = parseInt(giftCount.textContent.trim()) || 0;
  8614.         }
  8615.       }
  8616.     }
  8617.   } catch (e) {
  8618.     console.log('⚠️ Fallback pour favoriteCount initial:', e);
  8619.     // Fallback sur likeCount input
  8620.     const likeCountInput = document.getElementById('likeCount');
  8621.     if (likeCountInput && likeCountInput.value) {
  8622.       favoriteCount = parseInt(likeCountInput.value, 10) || 0;
  8623.     } else {
  8624.       const giftCount = document.getElementById('giftCount');
  8625.       if (giftCount && giftCount.textContent) {
  8626.         favoriteCount = parseInt(giftCount.textContent.trim()) || 0;
  8627.       }
  8628.     }
  8629.   }
  8630.   
  8631.   window.updateEcommerceSidebarContent(favoriteCount);
  8632.   
  8633. });
  8634. </script>
  8635. <!-- 🎯 DAY FILTER POPOVER (instancié une seule fois) -->
  8636. <div id=\"dayFilterPopover\" class=\"day-popover\" role=\"dialog\" aria-modal=\"true\" aria-hidden=\"true\">
  8637.   <div class=\"dp-arrow\" aria-hidden=\"true\"></div>
  8638.   <div class=\"dp-content\" role=\"group\" aria-label=\"Filtres du jour\">
  8639.     <button class=\"dp-btn\" data-filter=\"all\" title=\"Tout\" aria-pressed=\"true\">
  8640.       <i class=\"bi bi-grid-3x3-gap-fill\"></i><span class=\"dp-count dp-label\">Tout</span>
  8641.     </button>
  8642.     <button class=\"dp-btn\" data-filter=\"photos\" title=\"Photos\" aria-pressed=\"false\">
  8643.       <i class=\"bi bi-images\"></i><span class=\"dp-count\" data-bind=\"photo\">0</span>
  8644.     </button>
  8645.     <button class=\"dp-btn\" data-filter=\"audio\" title=\"Audios\" aria-pressed=\"false\">
  8646.       <i class=\"bi bi-mic-fill\"></i><span class=\"dp-count\" data-bind=\"audio\">0</span>
  8647.     </button>
  8648.     <button class=\"dp-btn\" data-filter=\"videos\" title=\"Vidéos\" aria-pressed=\"false\">
  8649.       <i class=\"bi bi-camera-video-fill\"></i><span class=\"dp-count\" data-bind=\"video\">0</span>
  8650.     </button>
  8651.     <button class=\"dp-btn\" data-filter=\"favoris\" title=\"Favoris\" aria-pressed=\"false\">
  8652.       <i class=\"bi bi-heart-fill\" style=\"color:#f56040\"></i><span class=\"dp-count\" data-bind=\"fav\">0</span>
  8653.     </button>
  8654.     <button class=\"dp-btn dp-close\" title=\"Fermer\" aria-label=\"Fermer\">
  8655.       <i class=\"bi bi-x-lg\"></i>
  8656.     </button>
  8657.   </div>
  8658. </div>
  8659. ";
  8660.         // line 8391
  8661.         yield "<aside class=\"col-lg-3 d-none d-lg-block\" style=\"position:sticky;top:100px;\">
  8662.   <div id=\"parentSuggestions\" class=\"pcb-sticky\">
  8663.     ";
  8664.         // line 8394
  8665.         yield "  </div>
  8666. </aside>
  8667. ";
  8668.         // line 8398
  8669.         yield "<div class=\"col-12 d-lg-none mt-3\">
  8670.   <div id=\"parentSuggestionsMobile\">
  8671.     ";
  8672.         // line 8401
  8673.         yield "  </div>
  8674. </div>
  8675. ";
  8676.         // line 8405
  8677.         yield "<script src=\"";
  8678.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("js/sidebar-ecommerce-pro.js"), "html"nulltrue);
  8679.         yield "\"></script>
  8680. ";
  8681.         
  8682.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  8683.         
  8684.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  8685.         yield from [];
  8686.     }
  8687.     /**
  8688.      * @codeCoverageIgnore
  8689.      */
  8690.     public function getTemplateName(): string
  8691.     {
  8692.         return "Parent/DetailsSejour.html.twig";
  8693.     }
  8694.     /**
  8695.      * @codeCoverageIgnore
  8696.      */
  8697.     public function isTraitable(): bool
  8698.     {
  8699.         return false;
  8700.     }
  8701.     /**
  8702.      * @codeCoverageIgnore
  8703.      */
  8704.     public function getDebugInfo(): array
  8705.     {
  8706.         return array (  9324 => 8405,  9319 => 8401,  9315 => 8398,  9310 => 8394,  9306 => 8391,  9241 => 8326,  9235 => 8324,  9233 => 8323,  9037 => 8130,  9031 => 8127,  9025 => 8124,  8983 => 8085,  8977 => 8082,  8971 => 8079,  8519 => 7630,  8511 => 7624,  8506 => 7621,  8504 => 7620,  8428 => 7546,  8425 => 7545,  8413 => 7535,  8410 => 7534,  8408 => 7533,  8024 => 7152,  7954 => 7085,  7796 => 6930,  7785 => 6922,  7774 => 6914,  7756 => 6899,  7108 => 6254,  7038 => 6187,  7027 => 6179,  6578 => 5733,  6553 => 5711,  6497 => 5658,  6361 => 5525,  6300 => 5467,  6288 => 5458,  6036 => 5210,  6023 => 5209,  6009 => 5206,  5996 => 5196,  5987 => 5190,  5976 => 5182,  5969 => 5177,  5967 => 5176,  3625 => 2837,  3513 => 2727,  3497 => 2714,  3395 => 2614,  3392 => 2613,  3378 => 2612,  3372 => 2608,  3368 => 2606,  3364 => 2604,  3358 => 2603,  3354 => 2601,  3347 => 2597,  3343 => 2595,  3341 => 2594,  3334 => 2590,  3328 => 2586,  3325 => 2585,  3321 => 2584,  3314 => 2579,  3312 => 2578,  3310 => 2577,  3306 => 2575,  3300 => 2574,  3296 => 2572,  3289 => 2568,  3285 => 2566,  3283 => 2565,  3276 => 2561,  3270 => 2557,  3267 => 2556,  3263 => 2555,  3260 => 2554,  3258 => 2553,  3256 => 2552,  3252 => 2550,  3246 => 2549,  3242 => 2547,  3235 => 2543,  3231 => 2541,  3229 => 2540,  3222 => 2536,  3216 => 2532,  3213 => 2531,  3209 => 2530,  3206 => 2529,  3204 => 2528,  3202 => 2527,  3196 => 2524,  3190 => 2520,  3188 => 2519,  3183 => 2516,  3175 => 2513,  3171 => 2512,  3165 => 2510,  3163 => 2509,  3155 => 2504,  3147 => 2499,  3144 => 2498,  3142 => 2497,  3137 => 2494,  3130 => 2490,  3124 => 2488,  3122 => 2487,  3106 => 2473,  3103 => 2472,  3099 => 2471,  3091 => 2465,  3087 => 2464,  3082 => 2462,  3078 => 2461,  3074 => 2460,  3070 => 2459,  3066 => 2458,  3056 => 2451,  3048 => 2448,  3041 => 2444,  3038 => 2443,  3035 => 2442,  3031 => 2441,  3016 => 2428,  3008 => 2426,  3002 => 2424,  2998 => 2422,  2996 => 2421,  2993 => 2420,  2989 => 2419,  2982 => 2415,  2974 => 2410,  2966 => 2405,  2950 => 2392,  2930 => 2374,  2924 => 2371,  2921 => 2370,  2919 => 2369,  2916 => 2368,  2910 => 2365,  2907 => 2364,  2905 => 2363,  2902 => 2362,  2896 => 2359,  2893 => 2358,  2891 => 2357,  2880 => 2348,  2878 => 2340,  2843 => 2310,  2839 => 2309,  2836 => 2308,  2833 => 2307,  2830 => 2306,  2827 => 2305,  2824 => 2304,  2821 => 2303,  2803 => 2302,  2800 => 2301,  2798 => 2300,  2795 => 2299,  2778 => 2283,  2764 => 2282,  2758 => 2278,  2752 => 2276,  2749 => 2275,  2743 => 2273,  2740 => 2272,  2734 => 2270,  2732 => 2269,  2727 => 2266,  2725 => 2261,  2720 => 2258,  2718 => 2254,  2713 => 2251,  2707 => 2247,  2705 => 2246,  2700 => 2243,  2697 => 2242,  2694 => 2240,  2688 => 2237,  2683 => 2235,  2679 => 2234,  2676 => 2233,  2671 => 2230,  2669 => 2229,  2665 => 2228,  2661 => 2227,  2657 => 2225,  2654 => 2224,  2651 => 2223,  2648 => 2222,  2645 => 2221,  2642 => 2220,  2639 => 2219,  2636 => 2218,  2633 => 2217,  2630 => 2216,  2627 => 2215,  2624 => 2214,  2621 => 2212,  2618 => 2211,  2615 => 2210,  2612 => 2209,  2609 => 2208,  2606 => 2207,  2604 => 2206,  2602 => 2205,  2599 => 2204,  2596 => 2203,  2593 => 2202,  2590 => 2201,  2587 => 2200,  2570 => 2199,  2548 => 2179,  2542 => 2177,  2538 => 2175,  2536 => 2174,  2526 => 2171,  2523 => 2170,  2519 => 2169,  2511 => 2168,  2504 => 2166,  2496 => 2161,  2488 => 2158,  2478 => 2151,  2474 => 2150,  2470 => 2149,  2464 => 2146,  2449 => 2133,  2447 => 2132,  2443 => 2130,  2428 => 2118,  2416 => 2109,  2408 => 2103,  2406 => 2102,  2398 => 2097,  2395 => 2096,  2390 => 2093,  2383 => 2091,  2380 => 2090,  2378 => 2089,  2372 => 2085,  2369 => 2084,  2365 => 2081,  2362 => 2080,  2359 => 2079,  2356 => 2078,  2353 => 2076,  2350 => 2075,  2196 => 1923,  2192 => 1922,  2188 => 1921,  2160 => 1896,  2136 => 1875,  2129 => 1871,  2105 => 1850,  2098 => 1846,  2057 => 1808,  2029 => 1783,  2018 => 1775,  2014 => 1774,  2009 => 1771,  2007 => 1770,  1999 => 1764,  1986 => 1762,  1839 => 1627,  1835 => 1626,  1831 => 1625,  1827 => 1624,  1823 => 1623,  1819 => 1622,  1815 => 1621,  1811 => 1620,  1802 => 1614,  1797 => 1612,  1791 => 1609,  1787 => 1608,  1783 => 1607,  1779 => 1606,  1773 => 1603,  1769 => 1602,  1765 => 1601,  1761 => 1600,  1757 => 1599,  1753 => 1598,  1749 => 1597,  1743 => 1594,  1739 => 1593,  1735 => 1592,  1731 => 1591,  1727 => 1590,  1721 => 1587,  1716 => 1584,  1713 => 1583,  1710 => 1582,  1707 => 1581,  1704 => 1580,  1701 => 1579,  1698 => 1578,  1695 => 1577,  1692 => 1576,  1689 => 1575,  137 => 24,  135 => 23,  133 => 22,  131 => 21,  129 => 20,  127 => 19,  125 => 18,  123 => 17,  121 => 16,  119 => 15,  116 => 13,  114 => 12,  110 => 11,  106 => 10,  102 => 9,  98 => 8,  94 => 7,  90 => 6,  86 => 5,  80 => 2,  57 => 1,  55 => 1762,  42 => 1,);
  8707.     }
  8708.     public function getSourceContext(): Source
  8709.     {
  8710.         return new Source("{% extends \"Parent/LayoutParent.html.twig\" %} {% block LinksCss %}
  8711. {{ parent() }}
  8712. <script src=\"https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.js\" defer></script>
  8713. <link rel=\"stylesheet\" href=\"{{ '/css/Parent/css/premiercnx.css' }}\" />
  8714. <link href=\"{{ asset('css/Parent/css/detailsejour.css') }}\" type=\"text/css\" rel=\"stylesheet\" />
  8715. <link rel=\"stylesheet\" href=\"{{ '/css/Accompagnateur/imgzoom.css' }}\" />
  8716. <link rel=\"stylesheet\" href=\"{{ asset('Plugins/css/dropzone.css') }}\" />
  8717. <link rel=\"stylesheet\" href=\"{{ asset('css/splide.min.css') }}\" />
  8718. <link rel=\"stylesheet\" href=\"{{ asset('css/favorites-sidebar.css') }}\" />
  8719. <link rel=\"stylesheet\" href=\"{{ asset('css/sidebar-ecommerce-pro.css') }}\">
  8720. {% set destination = \"detailsejour\" %}
  8721. {# ==================== Configuration B2C Conversion ==================== #}
  8722. {% set nowTs = 'now'|date('U') %}
  8723. {% set debutTs = sejour.dateDebutSejour|date('U') %}
  8724. {% set finTs = sejour.dateFinSejour|date('U') %}
  8725. {% set closeTs = sejour.dateFinCode ? sejour.dateFinCode|date('U') : finTs %}
  8726. {% set secondsPerDay = 86400 %}
  8727. {% set daysSinceStart = ((nowTs - debutTs) / secondsPerDay)|round(0, 'floor') %}
  8728. {% set daysUntilEnd = ((finTs - nowTs) / secondsPerDay)|round(0, 'ceil') %}
  8729. {% set daysAfterEnd = ((nowTs - finTs) / secondsPerDay)|round(0, 'floor') %}
  8730. {% set daysUntilClose = ((closeTs - nowTs) / secondsPerDay)|round(0, 'ceil') %}
  8731. <style>
  8732. /* ============================================
  8733.    PREMIUM DAY CARDS - Style Accompagnateur
  8734.    ============================================ */
  8735. /* Base card styles */
  8736. /* ============================================
  8737.    PREMIUM DAY CARDS - Timeline ultra-premium
  8738.    Identique à l'espace accompagnateur
  8739.    ============================================ */
  8740. .date-card {
  8741.   flex: 0 0 auto;
  8742.   width: 110px;
  8743.   background: #fff;
  8744.   border-radius: 14px;
  8745.   padding: 8px 6px;
  8746.   text-align: center;
  8747.   transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  8748.   overflow: visible;
  8749.   scroll-snap-align: center;
  8750.   position: relative;
  8751.   min-height: 56px;
  8752.   max-height: 68px;
  8753.   border: 1px solid transparent;
  8754.   cursor: pointer;
  8755. }
  8756. .date-card .day {
  8757.   font-weight: 600;
  8758.   font-size: 0.70rem;
  8759.   color: #2c3e50;
  8760.   margin-bottom: 1px;
  8761.   letter-spacing: -0.01em;
  8762.   line-height: 1.15;
  8763. }
  8764. .date-card .full-date {
  8765.   font-size: 0.60rem;
  8766.   color: #6b7280;
  8767.   font-weight: 500;
  8768.   line-height: 1.1;
  8769.   margin-top: 0px;
  8770.   padding-bottom: 5px;
  8771. }
  8772. .date-card ul {
  8773.   margin: 4px 0 0 0;
  8774.   padding: 0;
  8775.   list-style: none;
  8776.   display: flex;
  8777.   gap: 4px;
  8778.   justify-content: center;
  8779.   flex-wrap: wrap;
  8780.   align-items: center;
  8781. }
  8782. .date-card ul li {
  8783.   font-size: 0.60rem;
  8784.   color: #6b7280;
  8785.   display: flex;
  8786.   align-items: center;
  8787.   gap: 2px;
  8788.   line-height: 1;
  8789.   font-weight: 500;
  8790. }
  8791. .date-card ul li i {
  8792.   font-size: 0.65rem;
  8793. }
  8794. .premium-day-card {
  8795.   flex: 0 0 auto;
  8796.   width: 130px;
  8797.   background: #fff;
  8798.   border-radius: 14px;
  8799.   padding: 8px 6px;
  8800.   text-align: center;
  8801.   transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  8802.   overflow: visible;
  8803.   scroll-snap-align: center;
  8804.   position: relative;
  8805.   min-height: 56px;
  8806.   max-height: 68px;
  8807.   border: 1px solid transparent;
  8808.   cursor: pointer;
  8809.   will-change: transform;
  8810.   contain: layout style;
  8811. }
  8812. .premium-day-card .day {
  8813.   font-weight: 600;
  8814.   font-size: 0.9rem;
  8815.   color: #2c3e50;
  8816.   margin-bottom: 1px;
  8817.   letter-spacing: -0.01em;
  8818.   line-height: 1.15;
  8819. }
  8820. .premium-day-card .full-date {
  8821.   font-size: 0.75rem;
  8822.   color: #6b7280;
  8823.   font-weight: 500;
  8824.   line-height: 1.1;
  8825.   margin-top: 0;
  8826. }
  8827. /* Compteurs de médias - Points colorés minimalistes */
  8828. .premium-day-card ul,
  8829. .date-card ul,
  8830. .media-list-horizontal {
  8831.   margin: 4px 0 0 0;
  8832.   padding: 0;
  8833.   list-style: none;
  8834.   display: flex;
  8835.   gap: 4px;
  8836.   justify-content: center;
  8837.   flex-wrap: wrap;
  8838.   align-items: center;
  8839. }
  8840. .premium-day-card ul li,
  8841. .date-card ul li {
  8842.   font-size: 0.60rem;
  8843.   color: #6b7280;
  8844.   display: flex;
  8845.   align-items: center;
  8846.   gap: 2px;
  8847.   line-height: 1;
  8848.   font-weight: 500;
  8849. }
  8850. .premium-day-card ul li i,
  8851. .date-card ul li i {
  8852.   font-size: 0.65rem;
  8853. }
  8854. /* ============================================
  8855.    COULEURS PAR TYPE DE MÉDIA - Uniforme pour toutes les cartes
  8856.    Photo = Orange, Vocal = Bleu, Vidéo = Orange clair
  8857.    ============================================ */
  8858. /* Photo = Orange 🟠 */
  8859. .premium-day-card ul li i.bi-camera,
  8860. .premium-day-card ul li i.bi-camera-fill,
  8861. .premium-day-card ul li i.bi-image,
  8862. .premium-day-card ul li i.bi-images,
  8863. .premium-day-past ul li i.bi-camera,
  8864. .premium-day-past ul li i.bi-camera-fill,
  8865. .premium-day-past ul li i.bi-image,
  8866. .premium-day-past ul li i.bi-images,
  8867. .premium-day-current ul li i.bi-camera,
  8868. .premium-day-current ul li i.bi-camera-fill,
  8869. .premium-day-current ul li i.bi-image,
  8870. .premium-day-current ul li i.bi-images,
  8871. .premium-day-future ul li i.bi-camera,
  8872. .premium-day-future ul li i.bi-camera-fill,
  8873. .premium-day-future ul li i.bi-image,
  8874. .premium-day-future ul li i.bi-images,
  8875. .date-card ul li i.bi-camera,
  8876. .date-card ul li i.bi-camera-fill,
  8877. .date-card ul li i.bi-image,
  8878. .date-card ul li i.bi-images {
  8879.   color: #F56040 !important;
  8880.   opacity: 1 !important;
  8881. }
  8882. /* Vocal/Audio = Bleu Mint 🔵 */
  8883. .premium-day-card ul li i.bi-mic-fill,
  8884. .premium-day-card ul li i.bi-mic,
  8885. .premium-day-past ul li i.bi-mic-fill,
  8886. .premium-day-past ul li i.bi-mic,
  8887. .premium-day-current ul li i.bi-mic-fill,
  8888. .premium-day-current ul li i.bi-mic,
  8889. .premium-day-future ul li i.bi-mic-fill,
  8890. .premium-day-future ul li i.bi-mic,
  8891. .date-card ul li i.bi-mic-fill,
  8892. .date-card ul li i.bi-mic {
  8893.   color: #41A2AA !important;
  8894.   opacity: 1 !important;
  8895. }
  8896. /* Vidéo = Orange clair 🟠 */
  8897. .premium-day-card ul li i.bi-camera-video,
  8898. .premium-day-card ul li i.bi-camera-video-fill,
  8899. .premium-day-card ul li i.bi-film,
  8900. .premium-day-past ul li i.bi-camera-video,
  8901. .premium-day-past ul li i.bi-camera-video-fill,
  8902. .premium-day-past ul li i.bi-film,
  8903. .premium-day-current ul li i.bi-camera-video,
  8904. .premium-day-current ul li i.bi-camera-video-fill,
  8905. .premium-day-current ul li i.bi-film,
  8906. .premium-day-future ul li i.bi-camera-video,
  8907. .premium-day-future ul li i.bi-camera-video-fill,
  8908. .premium-day-future ul li i.bi-film,
  8909. .date-card ul li i.bi-camera-video,
  8910. .date-card ul li i.bi-camera-video-fill,
  8911. .date-card ul li i.bi-film {
  8912.   color: #FF9F7A !important;
  8913.   opacity: 1 !important;
  8914. }
  8915. /* État PASSÉ - Cohérent avec charte 5sur5 */
  8916. .premium-day-past {
  8917.   opacity: 0.85;
  8918.   background: rgba(65, 162, 170, 0.05);
  8919.   border: 1px solid rgba(65, 162, 170, 0.25);
  8920.   cursor: pointer;
  8921.   pointer-events: auto;
  8922. }
  8923. .premium-day-past:hover {
  8924.   transform: translateY(-2px);
  8925.   box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
  8926.   opacity: 1;
  8927. }
  8928. /* État AUJOURD'HUI - Premium mis en avant clairement */
  8929. .premium-day-current {
  8930.   width: 110px !important;
  8931.   border: 2px solid #41A2AA !important;
  8932.   background: #fff !important;
  8933.   box-shadow: 0 6px 16px rgba(65, 162, 170, 0.12) !important;
  8934.   transform: scale(1.04);
  8935.   z-index: 10;
  8936.   cursor: pointer;
  8937.   opacity: 1 !important;
  8938.   position: relative;
  8939. }
  8940. /* Point animé \"Aujourd'hui\" - style calendrier moderne */
  8941. .premium-day-current::after {
  8942.   content: '';
  8943.   position: absolute;
  8944.   top: 8px;
  8945.   right: 8px;
  8946.   width: 8px;
  8947.   height: 8px;
  8948.   background: #41A2AA;
  8949.   border-radius: 50%;
  8950.   box-shadow: 0 0 0 0 rgba(65, 162, 170, 0.7);
  8951.   animation: todayPulse 2s ease-in-out infinite;
  8952.   z-index: 5;
  8953. }
  8954. @keyframes todayPulse {
  8955.   0% {
  8956.     box-shadow: 0 0 0 0 rgba(65, 162, 170, 0.7);
  8957.   }
  8958.   50% {
  8959.     box-shadow: 0 0 0 6px rgba(65, 162, 170, 0);
  8960.   }
  8961.   100% {
  8962.     box-shadow: 0 0 0 0 rgba(65, 162, 170, 0);
  8963.   }
  8964. }
  8965. .premium-day-current:hover {
  8966.   transform: scale(1.04);
  8967.   box-shadow: 0 6px 16px rgba(65, 162, 170, 0.12) !important;
  8968. }
  8969. .premium-day-current:focus-visible {
  8970.   outline: 3px solid rgba(65, 162, 170, 0.3);
  8971.   outline-offset: 2px;
  8972. }
  8973. .premium-day-current .day,
  8974. .premium-day-current .full-date {
  8975.   color: #137F86 !important;
  8976.   font-weight: 600 !important;
  8977. }
  8978. .premium-day-current .full-date {
  8979.   padding-bottom: 5px !important;
  8980. }
  8981. .premium-day-current ul li {
  8982.   color: #137F86 !important;
  8983. }
  8984. /* État ACTIF - Carte sélectionnée */
  8985. .date-card.active,
  8986. .premium-day-card.active {
  8987.   width: 140px !important;
  8988.   border: 2px solid #41A2AA !important;
  8989.   background: #EAF7F7 !important;
  8990.   box-shadow: 0 2px 8px rgba(65, 162, 170, 0.15) !important;
  8991.   transform: scale(1.02);
  8992.   z-index: 10;
  8993. }
  8994. .date-card.active .day,
  8995. .premium-day-card.active .day,
  8996. .date-card.active .day-number,
  8997. .premium-day-card.active .day-number {
  8998.   color: #137F86 !important;
  8999.   font-weight: 700;
  9000. }
  9001. .date-card.active .full-date,
  9002. .premium-day-card.active .full-date,
  9003. .date-card.active .day-name,
  9004. .premium-day-card.active .day-name {
  9005.   color: #137F86 !important;
  9006.   font-weight: 700;
  9007. }
  9008. .date-card.active ul li,
  9009. .premium-day-card.active ul li {
  9010.   color: #137F86 !important;
  9011. }
  9012. .date-card.active ul li i,
  9013. .premium-day-card.active ul li i {
  9014.   color: #41A2AA !important;
  9015. }
  9016. .date-card:hover,
  9017. .premium-day-card:hover {
  9018.   background-color: #f9f9f9;
  9019.   box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  9020. }
  9021. /* État FUTUR - Semi-caché, réduit, verrouillé */
  9022. .premium-day-future {
  9023.   opacity: 0.45 !important;
  9024.   transform: scale(0.92);
  9025.   cursor: not-allowed !important;
  9026.   pointer-events: none !important;
  9027.   border: 1px solid rgba(188, 196, 206, 0.2) !important;
  9028.   background: #fff !important;
  9029.   box-shadow: none !important;
  9030. }
  9031. .premium-day-future:hover {
  9032.   transform: scale(0.92) !important;
  9033.   box-shadow: none !important;
  9034. }
  9035. .premium-day-future .day,
  9036. .premium-day-future .full-date {
  9037.   color: #BCC4CE !important;
  9038. }
  9039. .premium-day-future ul {
  9040.   display: none !important;
  9041. }
  9042. /* Icône cadenas sur jours futurs */
  9043. .premium-day-future::before {
  9044.   content: '\\F4C0';
  9045.   font-family: 'bootstrap-icons';
  9046.   position: absolute;
  9047.   top: 4px;
  9048.   right: 4px;
  9049.   font-size: 9px;
  9050.   color: #BCC4CE;
  9051.   opacity: 0.25;
  9052. }
  9053. /* Tooltip pour jours futurs */
  9054. .premium-day-future::after {
  9055.   content: attr(data-tooltip);
  9056.   position: absolute;
  9057.   bottom: -35px;
  9058.   left: 50%;
  9059.   transform: translateX(-50%);
  9060.   background: rgba(0, 0, 0, 0.85);
  9061.   color: white;
  9062.   padding: 6px 10px;
  9063.   border-radius: 6px;
  9064.   font-size: 11px;
  9065.   white-space: nowrap;
  9066.   opacity: 0;
  9067.   pointer-events: none;
  9068.   transition: opacity 0.2s ease;
  9069.   z-index: 1000;
  9070. }
  9071. /* Date container scroll */
  9072. .date-container {
  9073.   display: flex;
  9074.   gap: 12px;
  9075.   overflow-x: auto;
  9076.   scrollbar-width: none;
  9077.   -ms-overflow-style: none;
  9078.   padding: 8px 4px;
  9079. }
  9080. .date-container::-webkit-scrollbar {
  9081.   display: none;
  9082. }
  9083. /* Section days wrapper */
  9084. .section-days {
  9085.   background: #f8fafb;
  9086.   border-radius: 12px;
  9087.   padding: 10px 12px;
  9088.   margin-bottom: 16px;
  9089.   border: 1px solid rgba(65, 162, 170, 0.1);
  9090.   box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  9091. }
  9092. /* Bouton favoris désactivé (0 favoris) */
  9093. .mtb-btn.favoris-empty,
  9094. .mtb-btn[data-filter=\"favoris\"]:disabled {
  9095.   opacity: 0.6;
  9096.   cursor: not-allowed;
  9097.   pointer-events: none;
  9098.   background: rgba(0, 0, 0, 0.02) !important;
  9099.   border-color: rgba(0, 0, 0, 0.08) !important;
  9100. }
  9101. .mtb-btn.favoris-empty:hover,
  9102. .mtb-btn[data-filter=\"favoris\"]:disabled:hover {
  9103.   transform: none;
  9104.   box-shadow: none;
  9105. }
  9106. .favoris-empty-text {
  9107.   font-size: 11px;
  9108.   font-family: inherit;
  9109.   color: #94a3b8;
  9110.   font-style: italic;
  9111.   font-weight: 500;
  9112.   line-height: 1.2;
  9113. }
  9114. /* Styles premium pour les filtres */
  9115. .premium-5sur5-actions-group {
  9116.   display: flex;
  9117.   gap: 8px;
  9118.   align-items: center;
  9119.   flex-wrap: wrap;
  9120. }
  9121. .premium-5sur5-action-btn {
  9122.   display: inline-flex;
  9123.   align-items: center;
  9124.   gap: 6px;
  9125.   padding: 7px 12px;
  9126.   background: #F7FBFC;
  9127.   border: 1px solid rgba(65, 162, 170, 0.12);
  9128.   border-radius: 14px;
  9129.   color: #41A2AA;
  9130.   font-size: 13px;
  9131.   font-weight: 600;
  9132.   font-family: inherit;
  9133.   cursor: pointer;
  9134.   transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  9135.   white-space: nowrap;
  9136.   position: relative;
  9137.   line-height: 1.4;
  9138. }
  9139. .premium-5sur5-action-btn:hover:not(:disabled) {
  9140.   background: rgba(65, 162, 170, 0.08);
  9141.   border-color: rgba(65, 162, 170, 0.25);
  9142.   transform: translateY(-1px);
  9143. }
  9144. .premium-5sur5-action-btn:active:not(:disabled) {
  9145.   transform: translateY(0);
  9146. }
  9147. .premium-5sur5-action-btn i {
  9148.   font-size: 14px;
  9149.   opacity: 0.85;
  9150.   line-height: 1;
  9151. }
  9152. .premium-5sur5-action-btn span:not(.premium-5sur5-badge):not(.favoris-empty-text) {
  9153.   font-size: 13px;
  9154.   font-weight: 600;
  9155.   letter-spacing: 0.2px;
  9156.   line-height: 1.4;
  9157.   font-family: inherit;
  9158. }
  9159. .premium-5sur5-badge {
  9160.   display: inline-block;
  9161.   font-size: 11px;
  9162.   font-weight: 600;
  9163.   font-family: inherit;
  9164.   padding: 2px 6px;
  9165.   border-radius: 6px;
  9166.   letter-spacing: 0.2px;
  9167.   margin-left: 2px;
  9168.   line-height: 1.2;
  9169. }
  9170. /* État actif pour les boutons premium */
  9171. .premium-5sur5-action-btn.mtb-btn.active,
  9172. .premium-5sur5-action-btn.mtb-btn.is-active {
  9173.   background: rgba(65, 162, 170, 0.15) !important;
  9174.   border-color: #41A2AA !important;
  9175.   color: #137F86 !important;
  9176.   box-shadow: 0 2px 8px rgba(65, 162, 170, 0.2);
  9177. }
  9178. .premium-5sur5-action-btn.mtb-btn[data-filter=\"favoris\"].active {
  9179.   background: rgba(245, 96, 64, 0.15) !important;
  9180.   border-color: #f56040 !important;
  9181.   color: #d43e1f !important;
  9182. }
  9183. .premium-5sur5-action-btn.mtb-btn[data-filter=\"audio\"].active {
  9184.   background: rgba(255, 215, 0, 0.15) !important;
  9185.   border-color: #ffd700 !important;
  9186.   color: #b8860b !important;
  9187. }
  9188. /* Bouton favoris désactivé */
  9189. .premium-5sur5-action-btn.favoris-empty,
  9190. .premium-5sur5-action-btn[data-filter=\"favoris\"]:disabled {
  9191.   opacity: 0.6;
  9192.   cursor: not-allowed;
  9193.   pointer-events: none;
  9194.   background: rgba(0, 0, 0, 0.02) !important;
  9195.   border-color: rgba(0, 0, 0, 0.08) !important;
  9196. }
  9197. .premium-5sur5-action-btn.favoris-empty:hover,
  9198. .premium-5sur5-action-btn[data-filter=\"favoris\"]:disabled:hover {
  9199.   transform: none;
  9200.   box-shadow: none;
  9201. }
  9202. /* Styles pour la section favoris */
  9203. .favorites-ecommerce-view {
  9204.   width: 100%;
  9205.   max-width: 100%;
  9206.   padding: 24px;
  9207.   box-sizing: border-box;
  9208. }
  9209. .favorites-header {
  9210.   display: flex;
  9211.   justify-content: space-between;
  9212.   align-items: center;
  9213.   margin-bottom: 24px;
  9214.   padding: 20px;
  9215.   background: #f8fafb;
  9216.   border-radius: 12px;
  9217.   border: 1px solid rgba(65, 162, 170, 0.1);
  9218. }
  9219. .favorites-title {
  9220.   display: flex;
  9221.   align-items: center;
  9222.   gap: 12px;
  9223.   flex-wrap: wrap;
  9224. }
  9225. .favorites-title h3 {
  9226.   font-size: 20px;
  9227.   font-weight: 700;
  9228.   color: #1a1a1a;
  9229.   margin: 0;
  9230.   display: flex;
  9231.   align-items: center;
  9232.   gap: 8px;
  9233. }
  9234. .favorites-title h3 i {
  9235.   color: #f56040;
  9236.   font-size: 20px;
  9237. }
  9238. .favorites-count {
  9239.   display: inline-flex;
  9240.   align-items: center;
  9241.   padding: 6px 12px;
  9242.   background: rgba(245, 96, 64, 0.1);
  9243.   color: #f56040;
  9244.   border-radius: 20px;
  9245.   font-size: 14px;
  9246.   font-weight: 600;
  9247. }
  9248. .btn-back-to-days {
  9249.   display: flex;
  9250.   align-items: center;
  9251.   gap: 8px;
  9252.   padding: 10px 20px;
  9253.   background: #ffffff;
  9254.   border: 1px solid rgba(65, 162, 170, 0.2);
  9255.   border-radius: 10px;
  9256.   color: #6b7280;
  9257.   font-size: 14px;
  9258.   font-weight: 600;
  9259.   cursor: pointer;
  9260.   transition: all 0.2s ease;
  9261. }
  9262. .btn-back-to-days:hover {
  9263.   background: rgba(65, 162, 170, 0.05);
  9264.   border-color: #41A2AA;
  9265.   color: #41A2AA;
  9266. }
  9267. .favorites-content {
  9268.   width: 100%;
  9269. }
  9270. .favorites-grid {
  9271.   display: grid;
  9272.   grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  9273.   gap: 16px;
  9274.   width: 100%;
  9275.   padding: 0;
  9276. }
  9277. .favorites-grid .favorite-item,
  9278. .favorites-grid .photo-item {
  9279.   position: relative;
  9280.   width: 100%;
  9281.   aspect-ratio: 1;
  9282.   border-radius: 12px;
  9283.   overflow: hidden;
  9284.   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  9285.   transition: all 0.3s ease;
  9286.   cursor: pointer;
  9287. }
  9288. .favorites-grid .favorite-item:hover,
  9289. .favorites-grid .photo-item:hover {
  9290.   transform: translateY(-4px);
  9291.   box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  9292. }
  9293. .favorites-grid .favorite-item:hover .favorite-actions,
  9294. .favorites-grid .photo-item:hover .favorite-actions {
  9295.   opacity: 1;
  9296. }
  9297. .favorites-grid img {
  9298.   width: 100%;
  9299.   height: 100%;
  9300.   object-fit: cover;
  9301.   display: block;
  9302. }
  9303. .favorites-grid .favorite-item {
  9304.   position: relative;
  9305. }
  9306. .favorites-grid .favorite-actions {
  9307.   position: absolute;
  9308.   top: 8px;
  9309.   right: 8px;
  9310.   display: flex;
  9311.   gap: 6px;
  9312.   opacity: 0;
  9313.   transition: opacity 0.3s ease;
  9314.   z-index: 10;
  9315. }
  9316. /* CTA discret et premium */
  9317. .premium-cta-subtle {
  9318.   margin: 20px 0;
  9319.   padding: 16px 20px;
  9320.   background: rgba(65, 162, 170, 0.04);
  9321.   border: 1px solid rgba(65, 162, 170, 0.15);
  9322.   border-radius: 12px;
  9323.   cursor: pointer;
  9324.   transition: all 0.3s ease;
  9325.   display: flex;
  9326.   align-items: center;
  9327.   justify-content: space-between;
  9328.   gap: 12px;
  9329.   text-decoration: none;
  9330.   color: inherit;
  9331. }
  9332. .premium-cta-subtle:hover {
  9333.   background: rgba(65, 162, 170, 0.08);
  9334.   border-color: rgba(65, 162, 170, 0.25);
  9335.   transform: translateX(2px);
  9336.   text-decoration: none;
  9337.   color: inherit;
  9338. }
  9339. .premium-cta-subtle > div:first-child {
  9340.   display: flex;
  9341.   align-items: center;
  9342.   gap: 12px;
  9343.   flex: 1;
  9344. }
  9345. .premium-cta-subtle > div:first-child > div:first-child {
  9346.   width: 40px;
  9347.   height: 40px;
  9348.   background: rgba(65, 162, 170, 0.1);
  9349.   border-radius: 10px;
  9350.   display: flex;
  9351.   align-items: center;
  9352.   justify-content: center;
  9353.   flex-shrink: 0;
  9354. }
  9355. .premium-cta-subtle > div:first-child > div:first-child i {
  9356.   font-size: 18px;
  9357.   color: #41A2AA;
  9358. }
  9359. .premium-cta-subtle > div:first-child > div:last-child {
  9360.   flex: 1;
  9361.   min-width: 0;
  9362. }
  9363. .premium-cta-subtle > div:first-child > div:last-child p:first-child {
  9364.   margin: 0;
  9365.   font-size: 14px;
  9366.   font-weight: 600;
  9367.   color: #1a1a1a;
  9368.   line-height: 1.4;
  9369. }
  9370. .premium-cta-subtle > div:first-child > div:last-child p:last-child {
  9371.   margin: 4px 0 0 0;
  9372.   font-size: 12px;
  9373.   color: #6b7280;
  9374.   line-height: 1.4;
  9375. }
  9376. .premium-cta-subtle > i:last-child {
  9377.   font-size: 18px;
  9378.   color: #41A2AA;
  9379.   flex-shrink: 0;
  9380. }
  9381. .premium-5sur5-day-title {
  9382.   font-size: 1.35rem;
  9383.   font-weight: 700;
  9384.   color: #2c3e50;
  9385.   margin: 0 0 4px 0;
  9386.   letter-spacing: -0.02em;
  9387.   line-height: 1.3;
  9388. }
  9389. .premium-5sur5-day-subtitle {
  9390.   font-size: 0.9rem;
  9391.   color: #6b7280;
  9392.   margin: 0;
  9393.   font-weight: 500;
  9394.   line-height: 1.5;
  9395. }
  9396. @media (max-width: 768px) {
  9397.   .premium-5sur5-day-header {
  9398.     padding: 12px 16px;
  9399.     margin-bottom: 16px;
  9400.   }
  9401.   .premium-5sur5-day-title {
  9402.     font-size: 1.15rem;
  9403.   }
  9404.   .premium-5sur5-day-subtitle {
  9405.     font-size: 0.8rem;
  9406.   }
  9407.   /* Menu sticky en bas - Override des styles précédents */
  9408.   .premium-5sur5-actions-group {
  9409.     position: fixed !important;
  9410.     bottom: 0 !important;
  9411.     left: 0 !important;
  9412.     right: 0 !important;
  9413.     width: 100% !important;
  9414.     background: #ffffff !important;
  9415.     border-top: 1px solid rgba(65, 162, 170, 0.15) !important;
  9416.     padding: 12px 16px !important;
  9417.     z-index: 1050 !important;
  9418.     box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.08) !important;
  9419.     justify-content: space-around !important;
  9420.     gap: 0 !important;
  9421.     margin: 0 !important;
  9422.     margin-top: 0 !important;
  9423.     /* Safe area pour iPhone avec encoche */
  9424.     padding-bottom: max(12px, env(safe-area-inset-bottom)) !important;
  9425.   }
  9426.   .premium-5sur5-action-btn {
  9427.     flex: 1 !important;
  9428.     justify-content: center !important;
  9429.     min-width: 0 !important;
  9430.     padding: 10px 8px !important;
  9431.     border-radius: 12px !important;
  9432.     font-size: 12px !important;
  9433.   }
  9434.   .premium-5sur5-action-btn i {
  9435.     font-size: 16px !important;
  9436.   }
  9437.   
  9438.   .premium-5sur5-action-btn span:not(.premium-5sur5-badge):not(.favoris-empty-text) {
  9439.     font-size: 12px !important;
  9440.   }
  9441.   
  9442.   .premium-5sur5-badge {
  9443.     font-size: 10px !important;
  9444.     padding: 2px 5px !important;
  9445.   }
  9446.   /* Ajouter un padding-bottom au contenu pour éviter que le menu sticky ne cache le contenu */
  9447.   #scrollTarget {
  9448.     padding-bottom: 80px !important;
  9449.   }
  9450.   /* Section favoris responsive */
  9451.   .favorites-ecommerce-view {
  9452.     padding: 16px !important;
  9453.   }
  9454.   .favorites-header {
  9455.     flex-direction: column !important;
  9456.     gap: 12px !important;
  9457.     align-items: flex-start !important;
  9458.     padding: 16px !important;
  9459.     margin-bottom: 16px !important;
  9460.   }
  9461.   .favorites-title {
  9462.     width: 100% !important;
  9463.   }
  9464.   .favorites-title h3 {
  9465.     font-size: 18px !important;
  9466.     margin-bottom: 8px !important;
  9467.   }
  9468.   .favorites-count {
  9469.     font-size: 13px !important;
  9470.     padding: 4px 10px !important;
  9471.   }
  9472.   .btn-back-to-days {
  9473.     width: 100% !important;
  9474.     justify-content: center !important;
  9475.     padding: 10px 16px !important;
  9476.     font-size: 14px !important;
  9477.   }
  9478.   .favorites-content {
  9479.     padding: 0 !important;
  9480.   }
  9481.   .favorites-grid {
  9482.     display: grid !important;
  9483.     grid-template-columns: repeat(2, 1fr) !important;
  9484.     gap: 12px !important;
  9485.     padding: 0 !important;
  9486.   }
  9487.   .favorites-grid .favorite-item,
  9488.   .favorites-grid .photo-item {
  9489.     width: 100% !important;
  9490.     height: auto !important;
  9491.     min-height: 150px !important;
  9492.     aspect-ratio: 1 !important;
  9493.     position: relative !important;
  9494.     display: block !important;
  9495.     border-radius: 12px !important;
  9496.     overflow: hidden !important;
  9497.     background: #f0f0f0 !important;
  9498.   }
  9499.   .favorites-grid .favorite-item img,
  9500.   .favorites-grid .photo-item img {
  9501.     width: 100% !important;
  9502.     height: 100% !important;
  9503.     min-height: 150px !important;
  9504.     object-fit: cover !important;
  9505.     display: block !important;
  9506.     position: absolute !important;
  9507.     top: 0 !important;
  9508.     left: 0 !important;
  9509.     border-radius: 12px !important;
  9510.   }
  9511.   .favorites-grid video {
  9512.     width: 100% !important;
  9513.     height: 100% !important;
  9514.     min-height: 150px !important;
  9515.     object-fit: cover !important;
  9516.     display: block !important;
  9517.     position: absolute !important;
  9518.     top: 0 !important;
  9519.     left: 0 !important;
  9520.     border-radius: 12px !important;
  9521.   }
  9522.   /* CTA discret responsive */
  9523.   .premium-cta-subtle {
  9524.     padding: 12px 16px !important;
  9525.     margin: 16px 0 !important;
  9526.   }
  9527.   .premium-cta-subtle > div:first-child > div:first-child {
  9528.     width: 36px !important;
  9529.     height: 36px !important;
  9530.   }
  9531.   .premium-cta-subtle > div:first-child > div:first-child i {
  9532.     font-size: 16px !important;
  9533.   }
  9534.   .premium-cta-subtle > div:first-child > div:last-child p:first-child {
  9535.     font-size: 13px !important;
  9536.   }
  9537.   .premium-cta-subtle > div:first-child > div:last-child p:last-child {
  9538.     font-size: 11px !important;
  9539.   }
  9540.   .premium-cta-subtle:hover {
  9541.     background: rgba(65, 162, 170, 0.08) !important;
  9542.     border-color: rgba(65, 162, 170, 0.25) !important;
  9543.     transform: translateX(2px) !important;
  9544.   }
  9545. }
  9546. .date-navigation {
  9547.   width: 100%;
  9548. }
  9549. /* Legacy compatibility */
  9550. .date-card .card-content {
  9551.   display: block;
  9552.   text-align: center;
  9553. }
  9554. .date-card .media-list-horizontal {
  9555.   margin: 0 !important;
  9556.   padding: 0 !important;
  9557.   display: flex;
  9558.   gap: 6px;
  9559.   justify-content: center;
  9560. }
  9561. .date-card .media-list-horizontal li {
  9562.   font-size: 0.65rem !important;
  9563. }
  9564. /* Dots minimalistes pour les indicateurs de jour */
  9565. .dot {
  9566.   display: inline-block;
  9567.   width: 6px;
  9568.   height: 6px;
  9569.   border-radius: 50%;
  9570.   margin-left: 4px;
  9571. }
  9572. .dot.blue {
  9573.   background: #41a2aa;
  9574. }
  9575. .dot.green {
  9576.   background: #8ed081;
  9577. }
  9578. .dot.orange {
  9579.   background: #ff9c57;
  9580. }
  9581. /* Dot multi-couleur pour aujourd'hui + premier/dernier jour */
  9582. .status-dot.multi {
  9583.   position: absolute;
  9584.   top: 6px;
  9585.   right: 6px;
  9586.   width: 10px;
  9587.   height: 10px;
  9588.   border-radius: 50%;
  9589.   background: linear-gradient(90deg, #41a2aa 50%, #ff9c57 50%);
  9590.   z-index: 5;
  9591. }
  9592. /* Variante pour premier jour + aujourd'hui */
  9593. .status-dot.multi.green-orange {
  9594.   background: linear-gradient(90deg, #8ed081 50%, #ff9c57 50%);
  9595. }
  9596. /* ==================== TOASTS & ANIMATIONS ==================== */
  9597. @keyframes slideUpFromGift {
  9598.   0% {
  9599.     opacity: 0;
  9600.     transform: translateY(60px) scale(0.9);
  9601.   }
  9602.   100% {
  9603.     opacity: 1;
  9604.     transform: translateY(0) scale(1);
  9605.   }
  9606. }
  9607. @keyframes fadeOut {
  9608.   to {
  9609.     opacity: 0;
  9610.     transform: translateY(-20px);
  9611.   }
  9612. }
  9613. /* ========== BANDEAU PROMO SÉJOUR TERMINÉ ========== */
  9614. .promo-banner-termine {
  9615.   background: linear-gradient(90deg, #d32f2f 0%, #e65100 50%, #ff5722 100%);
  9616.   color: white;
  9617.   padding: 0;
  9618.   height: 38px;
  9619.   width: 100%;
  9620.   position: relative;
  9621.   z-index: 100;
  9622.   box-shadow: 0 2px 6px rgba(211, 47, 47, 0.2);
  9623. }
  9624. .promo-banner-content {
  9625.   display: flex;
  9626.   align-items: center;
  9627.   justify-content: center;
  9628.   gap: 10px;
  9629.   max-width: 1200px;
  9630.   margin: 0 auto;
  9631.   padding: 0 12px;
  9632.   height: 100%;
  9633. }
  9634. .promo-banner-icon {
  9635.   font-size: 16px;
  9636.   flex-shrink: 0;
  9637. }
  9638. .promo-banner-text {
  9639.   font-size: 12px;
  9640.   line-height: 1.2;
  9641. }
  9642. .promo-banner-text strong {
  9643.   font-weight: 700;
  9644.   display: inline;
  9645. }
  9646. .promo-days {
  9647.   color: #fff;
  9648.   font-weight: 700;
  9649.   background: rgba(255,255,255,0.2);
  9650.   padding: 1px 5px;
  9651.   border-radius: 3px;
  9652.   font-size: 11px;
  9653. }
  9654. .promo-banner-cta {
  9655.   background: #fff;
  9656.   color: #d32f2f;
  9657.   font-weight: 600;
  9658.   font-size: 11px;
  9659.   padding: 4px 12px;
  9660.   border-radius: 12px;
  9661.   text-decoration: none;
  9662.   white-space: nowrap;
  9663.   transition: all 0.2s;
  9664. }
  9665. .promo-banner-cta:hover {
  9666.   background: rgba(255,255,255,0.9);
  9667.   transform: scale(1.02);
  9668.   color: #d32f2f;
  9669. }
  9670. .promo-banner-close {
  9671.   background: none;
  9672.   border: none;
  9673.   color: white;
  9674.   font-size: 18px;
  9675.   cursor: pointer;
  9676.   opacity: 0.7;
  9677.   padding: 0 2px;
  9678.   margin-left: 2px;
  9679.   line-height: 1;
  9680. }
  9681. .promo-banner-close:hover {
  9682.   opacity: 1;
  9683. }
  9684. @media (max-width: 600px) {
  9685.   .promo-banner-termine {
  9686.     height: 34px;
  9687.   }
  9688.   .promo-banner-content {
  9689.     gap: 6px;
  9690.     padding: 0 8px;
  9691.   }
  9692.   .promo-banner-text {
  9693.     font-size: 11px;
  9694.   }
  9695.   .promo-banner-icon {
  9696.     font-size: 14px;
  9697.   }
  9698. }
  9699. /* ========== SLIDER COMPACT PREMIUM ========== */
  9700. #heroPromo {
  9701.   margin: 0;
  9702.   padding: 0;
  9703.   width: 100%;
  9704.   overflow: hidden;
  9705.   background: #fff;
  9706. }
  9707. #heroPromo .divSliderModern {
  9708.   width: 100% !important;
  9709.   margin: 0 !important;
  9710.   padding: 0 !important;
  9711. }
  9712. #imageSlider {
  9713.   max-height: 70px !important;
  9714.   height: 70px !important;
  9715.   overflow: hidden !important;
  9716.   width: 100% !important;
  9717.   margin: 0 !important;
  9718.   padding: 0 !important;
  9719. }
  9720. #imageSlider .splide__track {
  9721.   height: 70px !important;
  9722.   width: 100% !important;
  9723.   margin: 0 !important;
  9724.   padding: 0 !important;
  9725. }
  9726. #imageSlider .splide__list {
  9727.   width: 100% !important;
  9728.   margin: 0 !important;
  9729.   padding: 0 !important;
  9730. }
  9731. #imageSlider .splide__slide {
  9732.   height: 70px !important;
  9733.   width: 100% !important;
  9734.   margin: 0 !important;
  9735.   padding: 0 !important;
  9736. }
  9737. #imageSlider .splide__slide img {
  9738.   object-fit: contain !important;
  9739.   height: auto !important;
  9740.   width: auto !important;
  9741. }
  9742. .slider-content-compact {
  9743.   display: flex;
  9744.   align-items: center;
  9745.   justify-content: flex-start;
  9746.   gap: 0;
  9747.   background: linear-gradient(135deg, #f7fcfc 0%, #ffffff 30%, #fef8f5 100%);
  9748.   height: 70px !important;
  9749.   padding: 0;
  9750.   width: 100%;
  9751.   box-sizing: border-box;
  9752.   overflow: hidden;
  9753.   position: relative;
  9754. }
  9755. .imgslider-compact {
  9756.   height: 100% !important;
  9757.   width: 70% !important;
  9758.   object-fit: cover;
  9759.   flex-shrink: 0;
  9760.   display: block;
  9761. }
  9762. .slider-text-compact {
  9763.   display: flex;
  9764.   flex-direction: column;
  9765.   gap: 4px;
  9766.   align-items: flex-start;
  9767.   justify-content: center;
  9768.   flex: 1;
  9769.   min-width: 0;
  9770.   overflow: hidden;
  9771.   padding: 12px 24px;
  9772.   height: 100%;
  9773. }
  9774. .slider-title-compact {
  9775.   font-size: 14px;
  9776.   font-weight: 700;
  9777.   line-height: 1.3;
  9778.   color: inherit;
  9779.   white-space: normal;
  9780.   word-wrap: break-word;
  9781.   max-width: 100%;
  9782. }
  9783. .slider-subtitle-compact {
  9784.   font-size: 12px;
  9785.   font-weight: 500;
  9786.   line-height: 1.3;
  9787.   color: inherit;
  9788.   white-space: normal;
  9789.   word-wrap: break-word;
  9790.   max-width: 100%;
  9791. }
  9792. @media (max-width: 768px) {
  9793.   #imageSlider, #imageSlider .splide__track, #imageSlider .splide__slide, .slider-content-compact {
  9794.     height: 65px !important;
  9795.   }
  9796.   .slider-content-compact {
  9797.     gap: 0;
  9798.   }
  9799.   .imgslider-compact {
  9800.     height: 100% !important;
  9801.     width: 70% !important;
  9802.   }
  9803.   .slider-text-compact {
  9804.     padding: 10px 16px;
  9805.   }
  9806.   .slider-title-compact {
  9807.     font-size: 13px;
  9808.     line-height: 1.2;
  9809.   }
  9810.   .slider-subtitle-compact {
  9811.     font-size: 11px;
  9812.     line-height: 1.2;
  9813.   }
  9814. }
  9815. @media (max-width: 480px) {
  9816.   #imageSlider, #imageSlider .splide__track, #imageSlider .splide__slide, .slider-content-compact {
  9817.     height: 60px !important;
  9818.   }
  9819.   .slider-content-compact {
  9820.     gap: 0;
  9821.   }
  9822.   .imgslider-compact {
  9823.     height: 100% !important;
  9824.     width: 70% !important;
  9825.   }
  9826.   .slider-text-compact {
  9827.     padding: 8px 12px;
  9828.   }
  9829.   .slider-title-compact {
  9830.     font-size: 12px;
  9831.     line-height: 1.2;
  9832.   }
  9833.   .slider-subtitle-compact {
  9834.     font-size: 10px;
  9835.     line-height: 1.2;
  9836.   }
  9837. }
  9838. /* ========== EMPTY STATE ========== */
  9839. .stay-empty-wrapper {
  9840.   padding: 50px 20px 60px;
  9841.   display: flex;
  9842.   justify-content: center;
  9843. }
  9844. .stay-empty-card {
  9845.   max-width: 720px;
  9846.   width: 100%;
  9847.   background: #ffffff;
  9848.   border-radius: 24px;
  9849.   padding: 44px 40px 40px;
  9850.   box-shadow: 0 16px 50px rgba(5, 45, 60, 0.06);
  9851.   margin: 0 auto;
  9852. }
  9853. .stay-empty-title {
  9854.   font-size: 1.5rem;
  9855.   font-weight: 700;
  9856.   color: #1A1A2E;
  9857.   margin-bottom: 20px;
  9858.   text-align: center;
  9859. }
  9860. .stay-empty-intro {
  9861.   font-size: 0.98rem;
  9862.   line-height: 1.7;
  9863.   color: #5A6178;
  9864.   max-width: 580px;
  9865.   margin: 0 auto 32px;
  9866.   text-align: center;
  9867. }
  9868. /* Section \"Ce qui va arriver\" */
  9869. .stay-empty-expect {
  9870.   display: flex;
  9871.   gap: 36px;
  9872.   align-items: flex-start;
  9873.   margin-bottom: 28px;
  9874. }
  9875. .stay-empty-expect-content {
  9876.   flex: 1;
  9877. }
  9878. .stay-empty-expect-label {
  9879.   font-size: 0.92rem;
  9880.   font-weight: 600;
  9881.   color: #1A1A2E;
  9882.   margin-bottom: 16px;
  9883. }
  9884. .stay-empty-list {
  9885.   list-style: none;
  9886.   padding: 0;
  9887.   margin: 0;
  9888. }
  9889. .stay-empty-list li {
  9890.   display: flex;
  9891.   align-items: flex-start;
  9892.   gap: 12px;
  9893.   padding: 10px 0;
  9894.   font-size: 0.92rem;
  9895.   color: #4B5563;
  9896.   line-height: 1.5;
  9897. }
  9898. .stay-empty-list-icon {
  9899.   width: 28px;
  9900.   height: 28px;
  9901.   border-radius: 8px;
  9902.   display: flex;
  9903.   align-items: center;
  9904.   justify-content: center;
  9905.   flex-shrink: 0;
  9906.   margin-top: 1px;
  9907. }
  9908. .stay-empty-list-icon svg {
  9909.   width: 14px;
  9910.   height: 14px;
  9911. }
  9912. .stay-empty-list-icon--check {
  9913.   background: rgba(65, 162, 170, 0.12);
  9914.   color: #41A2AA;
  9915. }
  9916. .stay-empty-list-icon--photos {
  9917.   background: rgba(240, 158, 122, 0.12);
  9918.   color: #E8865E;
  9919. }
  9920. .stay-empty-list-icon--vocal {
  9921.   background: rgba(155, 139, 244, 0.12);
  9922.   color: #7B6BE0;
  9923. }
  9924. /* Illustration compacte */
  9925. .stay-empty-illustration {
  9926.   position: relative;
  9927.   width: 180px;
  9928.   height: 200px;
  9929.   flex-shrink: 0;
  9930. }
  9931. .stay-empty-phone {
  9932.   position: absolute;
  9933.   left: 50%;
  9934.   top: 50%;
  9935.   transform: translate(-50%, -50%);
  9936.   width: 90px;
  9937.   filter: drop-shadow(0 8px 20px rgba(0,0,0,0.1));
  9938.   animation: phoneFloat 4s ease-in-out infinite;
  9939. }
  9940. @keyframes phoneFloat {
  9941.   0%, 100% { transform: translate(-50%, -50%) translateY(0); }
  9942.   50% { transform: translate(-50%, -50%) translateY(-5px); }
  9943. }
  9944. .stay-empty-bubble {
  9945.   position: absolute;
  9946.   display: flex;
  9947.   align-items: center;
  9948.   gap: 6px;
  9949.   padding: 6px 10px;
  9950.   background: #ffffff;
  9951.   border-radius: 10px;
  9952.   box-shadow: 0 4px 14px rgba(0,0,0,0.08);
  9953.   font-size: 0.72rem;
  9954.   font-weight: 600;
  9955.   color: #1A1A2E;
  9956.   white-space: nowrap;
  9957.   opacity: 0;
  9958.   animation: bubbleFadeIn 0.5s ease forwards;
  9959. }
  9960. .stay-empty-bubble-icon {
  9961.   width: 18px;
  9962.   height: 18px;
  9963.   border-radius: 5px;
  9964.   display: flex;
  9965.   align-items: center;
  9966.   justify-content: center;
  9967.   flex-shrink: 0;
  9968. }
  9969. .stay-empty-bubble-icon svg {
  9970.   width: 10px;
  9971.   height: 10px;
  9972. }
  9973. .stay-empty-bubble--arrived {
  9974.   top: 20px;
  9975.   left: -10px;
  9976.   animation-delay: 0.4s;
  9977. }
  9978. .stay-empty-bubble--arrived .stay-empty-bubble-icon {
  9979.   background: linear-gradient(135deg, #41A2AA, #359BA3);
  9980.   color: white;
  9981. }
  9982. .stay-empty-bubble--photos {
  9983.   top: 70px;
  9984.   right: -5px;
  9985.   animation-delay: 0.9s;
  9986. }
  9987. .stay-empty-bubble--photos .stay-empty-bubble-icon {
  9988.   background: linear-gradient(135deg, #F09E7A, #E8865E);
  9989.   color: white;
  9990. }
  9991. @keyframes bubbleFadeIn {
  9992.   0% { opacity: 0; transform: translateY(6px) scale(0.95); }
  9993.   100% { opacity: 1; transform: translateY(0) scale(1); }
  9994. }
  9995. .stay-empty-illustration-label {
  9996.   position: absolute;
  9997.   bottom: 0;
  9998.   left: 50%;
  9999.   transform: translateX(-50%);
  10000.   font-size: 0.7rem;
  10001.   color: #8E95A9;
  10002.   white-space: nowrap;
  10003.   text-align: center;
  10004. }
  10005. /* Note rassurante */
  10006. .stay-empty-reassurance {
  10007.   background: #F8FAFB;
  10008.   border-radius: 12px;
  10009.   padding: 14px 20px;
  10010.   margin-bottom: 24px;
  10011.   display: flex;
  10012.   align-items: flex-start;
  10013.   gap: 12px;
  10014. }
  10015. .stay-empty-reassurance-icon {
  10016.   width: 20px;
  10017.   height: 20px;
  10018.   color: #41A2AA;
  10019.   flex-shrink: 0;
  10020.   margin-top: 2px;
  10021. }
  10022. .stay-empty-reassurance p {
  10023.   margin: 0;
  10024.   font-size: 0.85rem;
  10025.   color: #5A6178;
  10026.   line-height: 1.6;
  10027. }
  10028. /* CTA */
  10029. .stay-empty-cta {
  10030.   display: inline-flex;
  10031.   align-items: center;
  10032.   gap: 8px;
  10033.   padding: 11px 22px;
  10034.   font-size: 0.88rem;
  10035.   font-weight: 600;
  10036.   color: #41A2AA;
  10037.   background: transparent;
  10038.   border: 1.5px solid #E5E9F0;
  10039.   border-radius: 10px;
  10040.   text-decoration: none;
  10041.   transition: all 0.2s ease;
  10042. }
  10043. .stay-empty-cta:hover {
  10044.   background: #F0F9FA;
  10045.   border-color: #41A2AA;
  10046.   color: #359BA3;
  10047.   text-decoration: none;
  10048. }
  10049. .stay-empty-cta svg {
  10050.   width: 16px;
  10051.   height: 16px;
  10052. }
  10053. .stay-empty-footer {
  10054.   text-align: center;
  10055. }
  10056. /* Responsive */
  10057. @media (max-width: 700px) {
  10058.   .stay-empty-card {
  10059.     padding: 32px 24px 32px;
  10060.   }
  10061.   .stay-empty-title {
  10062.     font-size: 1.3rem;
  10063.   }
  10064.   .stay-empty-expect {
  10065.     flex-direction: column;
  10066.     gap: 24px;
  10067.   }
  10068.   .stay-empty-illustration {
  10069.     width: 100%;
  10070.     height: 160px;
  10071.     order: -1;
  10072.   }
  10073.   .stay-empty-phone {
  10074.     width: 80px;
  10075.   }
  10076.   .stay-empty-bubble {
  10077.     font-size: 0.68rem;
  10078.     padding: 5px 8px;
  10079.   }
  10080.   .stay-empty-bubble--arrived {
  10081.     left: calc(50% - 85px);
  10082.   }
  10083.   .stay-empty-bubble--photos {
  10084.     right: calc(50% - 85px);
  10085.   }
  10086.   .stay-empty-reassurance {
  10087.     flex-direction: column;
  10088.     gap: 8px;
  10089.     text-align: center;
  10090.   }
  10091.   .stay-empty-reassurance-icon {
  10092.     margin: 0 auto;
  10093.   }
  10094. }
  10095. </style>
  10096. <script>
  10097.   window.__FEATURE_PARENT_CONVERSION__ = true;
  10098.   // Configuration runtime pour le système B2C
  10099.   {# Calcul des dates pour le JS - on calcule tout en Twig #}
  10100.   {% set nowTimestamp = 'now'|date('U') %}
  10101.   {% set debutTimestamp = sejour.dateDebutSejour|date('U') %}
  10102.   {% set finTimestamp = sejour.dateFinSejour|date('U') %}
  10103.   {% set finCodeDateJS = sejour.dateFinCode is defined and sejour.dateFinCode is not null ? sejour.dateFinCode : sejour.dateFinSejour|date_modify('+42 days') %}
  10104.   {% set closeTimestamp = finCodeDateJS|date('U') %}
  10105.   {% set daysSinceStartCalc = ((nowTimestamp - debutTimestamp) / 86400)|round(0, 'floor') %}
  10106.   {% set daysUntilEndCalc = ((finTimestamp - nowTimestamp) / 86400)|round(0, 'ceil') %}
  10107.   {% set daysAfterEndCalc = ((nowTimestamp - finTimestamp) / 86400)|round(0, 'floor') %}
  10108.   {% set daysUntilCloseCalc = ((closeTimestamp - nowTimestamp) / 86400)|round(0, 'ceil') %}
  10109.   
  10110.   window.PARENT_CONVERSION_CONFIG = {
  10111.     user: {
  10112.       prenom: \"{{ app.user.prenom|default('Parent')|e('js') }}\"
  10113.     },
  10114.     sejour: {
  10115.       id: {{ sejour.id }},
  10116.       dateDebut: \"{{ sejour.dateDebutSejour|date('Y-m-d') }}\",
  10117.       dateFin: \"{{ sejour.dateFinSejour|date('Y-m-d') }}\",
  10118.       dateFinCode: \"{{ sejour.dateFinCode ? sejour.dateFinCode|date('Y-m-d') : '' }}\",
  10119.       isTermine: {{ (sejour.dateFinSejour < date()) ? 'true' : 'false' }}
  10120.     },
  10121.     dates: {
  10122.       aujourdhui: \"{{ 'now'|date('Y-m-d') }}\",
  10123.       isFirstDay: {{ (sejour.dateDebutSejour|date('Y-m-d') == 'now'|date('Y-m-d')) ? 'true' : 'false' }},
  10124.       isWithin: {{ (sejour.dateDebutSejour <= date() and sejour.dateFinSejour >= date()) ? 'true' : 'false' }},
  10125.       daysSinceStart: {{ daysSinceStartCalc|default(0) }},
  10126.       daysUntilEnd: {{ daysUntilEndCalc|default(0) }},
  10127.       daysAfterEnd: {{ daysAfterEndCalc|default(0) }},
  10128.       daysUntilClose: {{ daysUntilCloseCalc|default(0) }}
  10129.     },
  10130.     stats: {
  10131.       totalDays: {{ sejour.dateFinSejour.diff(sejour.dateDebutSejour).days }},
  10132.       totalPhotos: {{ attachementsCount|default(0) }},
  10133.       totalMessages: {{ nbmessages|default(0) }},
  10134.       todayPhotos: {{ photosDuJour|default(0) }}
  10135.     },
  10136.     parent: {
  10137.       favorites: {{ nblikes|default(0) }},
  10138.       cartCount: 0,
  10139.       lastVisitAt: \"{{ 'now'|date('Y-m-d H:i:s') }}\"
  10140.     }
  10141.   };
  10142.   // Catalogue produits (routes réelles 5sur5)
  10143.   window.PARENT_PRODUCT_CATALOG = {
  10144.     digi10: { title:\"Pack numérique 10 photos\", badge:\"Petit budget\", url:\"{{ path('boutique5sur5') }}\" },
  10145.     digi25: { title:\"Pack numérique 25 photos\", badge:\"Immédiat\", url:\"{{ path('boutique5sur5') }}\" },
  10146.     retro12: { title:\"Pochette rétro 12 tirages\", badge:\"Cadeau\", url:\"{{ path('boutique5sur5') }}\" },
  10147.     prints20: { title:\"Pochette 20 tirages\", badge:\"Best seller\", url:\"{{ path('boutique5sur5') }}\" },
  10148.     album24: { title:\"Mini-album 24 pages\", badge:\"Parfait début\", url:\"{{ path('Album_du_Sejour') }}\" },
  10149.     album48: { title:\"Album Premium 48 pages\", badge:\"Meilleure vente\", url:\"{{ path('Album_du_Sejour') }}\" },
  10150.     mix10Poster: { title:\"Pack mixte 10 tirages + poster\", badge:\"Combo\", url:\"{{ path('boutique5sur5') }}\" },
  10151.     bundleAlbumPrints: { title:\"Album + tirages (-15%)\", badge:\"Éco\", url:\"{{ path('boutique5sur5') }}\" }
  10152.   };
  10153. </script>
  10154. <style>
  10155. .btn-close {
  10156.   font-size: 1.2rem;
  10157.   border: none;
  10158.   background: transparent;
  10159. }
  10160. .slide img {
  10161.   max-width: 100%;
  10162.   max-height: 100%;
  10163.   object-fit: contain;
  10164.   border-radius: 8px;
  10165.   box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
  10166.   transition: transform 0.3s ease;
  10167.   cursor: pointer;
  10168. }
  10169. .slide img.zoomed {
  10170.   transform: scale(1.5);
  10171.   cursor: zoom-in;
  10172. }
  10173. /* === Badges discrets des cartes jours (style accompagnateur avec Bootstrap) === */
  10174. /* Les badges utilisent directement les classes Bootstrap: badge, bg-success, bg-info, position-absolute */
  10175. /* === Affichage des dates (style accompagnateur exact) === */
  10176. .container--gallery.modern {
  10177.   background: #ffffff;
  10178.   border-radius: 32px;
  10179.   padding: 10px;
  10180.   box-shadow: 0 30px 70px rgba(11, 36, 71, 0.08);
  10181.   border: 1px solid rgba(65, 162, 170, 0.08);
  10182.   min-height:1000px;
  10183. }
  10184. @media (max-width: 768px) {
  10185.   .container--gallery.modern {
  10186.     padding: 24px;
  10187.     min-height:500px;
  10188.   }
  10189. }
  10190. .pro-journal {
  10191.   background: linear-gradient(145deg, #f8fbff 0%, #ffffff 100%);
  10192.   border-radius: 24px;
  10193.   padding: 28px;
  10194.   margin-bottom: 28px;
  10195.   border: 1px solid rgba(65, 162, 170, 0.08);
  10196.   box-shadow: 0 18px 45px rgba(11, 36, 71, 0.05);
  10197. }
  10198. .pro-entry-header {
  10199.   display: flex;
  10200.   align-items: center;
  10201.   justify-content: space-between;
  10202.   flex-wrap: wrap;
  10203.   gap: 18px;
  10204.   margin-bottom: 20px;
  10205. }
  10206. .pro-entry-header .date-chip {
  10207.   display: inline-flex;
  10208.   align-items: center;
  10209.   gap: 10px;
  10210.   padding: 10px 18px;
  10211.   border-radius: 999px;
  10212.   background: rgba(65, 162, 170, 0.08);
  10213.   color: #1f2933;
  10214.   font-weight: 600;
  10215.   font-size: 0.95rem;
  10216. }
  10217. .gallery-meta-chips {
  10218.   display: flex;
  10219.   flex-wrap: wrap;
  10220.   gap: 10px;
  10221.   align-items: center;
  10222. }
  10223. .gallery-meta-chips .filter-badge {
  10224.   background: #ffffff;
  10225.   border: 1px solid rgba(15, 40, 77, 0.08);
  10226.   border-radius: 999px;
  10227.   padding: 8px 14px;
  10228.   font-size: 0.85rem;
  10229.   font-weight: 600;
  10230.   color: #405064;
  10231.   display: inline-flex;
  10232.   align-items: center;
  10233.   gap: 6px;
  10234.   transition: all 0.2s ease;
  10235. }
  10236. .gallery-meta-chips .filter-badge.active {
  10237.   background: #41a2aa;
  10238.   color: #fff;
  10239.   border-color: #41a2aa;
  10240.   box-shadow: 0 8px 20px rgba(65, 162, 170, 0.25);
  10241. }
  10242. .gallery-grid {
  10243.   width: 100%;
  10244.   display: grid !important;
  10245.   grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  10246.   gap: 18px;
  10247. }
  10248. .gallery-grid .column {
  10249.   margin: 0 !important;
  10250. }
  10251. .gallery-grid .photo-item,
  10252. .gallery-grid .video-item,
  10253. .gallery-grid .audio-message-item {
  10254.   border-radius: 18px;
  10255.   background: #fff;
  10256.   border: 1px solid rgba(15, 40, 77, 0.08);
  10257.   box-shadow: 0 12px 30px rgba(11, 36, 71, 0.08);
  10258. }
  10259. .gallery-grid .photo-item img {
  10260.   border-radius: 16px;
  10261.   height: 220px;
  10262.   object-fit: cover;
  10263. }
  10264. .gallery-grid .video-item video,
  10265. .gallery-grid .audio-message-item audio {
  10266.   border-radius: 12px;
  10267. }
  10268. </style>
  10269. {% endblock %} {% set pageMenu = app.session.get('pageMenu') %} {% block Content
  10270. %}
  10271. <div class=\"main-content\">
  10272.   <div class=\"row no-margin\">
  10273.     <!-- Bouton cadeau attractif e-commerce -->
  10274.     {% set showGiftButton = (likes|default([]))|length > 0 %}
  10275.     <div
  10276.       class=\"gift-button\"
  10277.       id=\"gift-button-trigger\"
  10278.       data-has-favorites=\"{{ showGiftButton ? '1' : '0' }}\"
  10279.       style=\"cursor: pointer; {{ showGiftButton ? '' : 'display:none;' }}\"
  10280.     >
  10281.       <i id=\"gift-icon-payment\" class=\"bi bi-gift gift-pulse\"></i>
  10282.       <label
  10283.         id=\"giftCount\"
  10284.         class=\"labelGiftCount gift-count-bounce\"
  10285.         style=\"background-color: #f56040\"
  10286.       >
  10287.         {{ (likes|default([]))|length }}
  10288.       </label>
  10289.       <!-- Message flottant attractif -->
  10290.       <div class=\"gift-tooltip\" id=\"giftTooltip\">
  10291.         <div class=\"gift-tooltip-content\">
  10292.           <div class=\"gift-tooltip-header\">
  10293.             <i class=\"bi bi-clock-history\"></i>
  10294.             <strong>Offre limitée !</strong>
  10295.           </div>
  10296.           <p>Commandez vite ! Les photos seront disponibles seulement pendant <strong>6 semaines</strong> après la fin du séjour.</p>
  10297.           <div class=\"gift-tooltip-cta\">
  10298.             <i class=\"bi bi-lightning-charge\"></i>
  10299.             Commander maintenant
  10300.           </div>
  10301.         </div>
  10302.       </div>
  10303.     </div>
  10304.     <!-- Sidebar E-commerce -->
  10305.     <div id=\"ecommerce-sidebar\">
  10306.       <div class=\"ecommerce-header\">
  10307.         <h2 class=\"ecommerce-title\" id=\"ecommerce-title\">
  10308.           🎉 Vos souvenirs favoris sont prêts !
  10309.         </h2>
  10310.         <p class=\"ecommerce-subtitle\" id=\"ecommerce-subtitle\">
  10311.           {{ (likes|default([]))|length }} photos sélectionnées avec amour ❤️
  10312.         </p>
  10313.         <button class=\"ecommerce-close\" onclick=\"closeEcommerceSidebar()\">
  10314.           <i class=\"bi bi-x\"></i>
  10315.         </button>
  10316.       </div>
  10317.       <div class=\"ecommerce-content\">
  10318.         <!-- Bannière d'urgence -->
  10319.         <div class=\"urgency-banner\" id=\"urgency-banner\">
  10320.           <div>
  10321.             <i class=\"bi bi-clock-history\"></i>
  10322.             <strong>⏳ Commandez vite !</strong>
  10323.           </div>
  10324.           <div> Les photos seront disponibles seulement <strong>6 semaines</strong> après la fin du séjour</div>
  10325.           <div class=\"countdown\" id=\"countdown-timer\" style=\"display: none;\">
  10326.             Plus que <span id=\"days-left\">0</span> jours !
  10327.           </div>
  10328.         </div>
  10329.         <!-- Produits recommandés -->
  10330.         <div id=\"products-container\">
  10331.           <!-- Album Photo -->
  10332.           <div class=\"product-card popular\" id=\"album-card\">
  10333.             <div class=\"product-header\">
  10334.               <div class=\"product-icon\">
  10335.                 <img src=\"/images/produit/Album5sur5-3.jpg\" alt=\"Album Photo Premium\" style=\"width: 100%; height: 100%; object-fit: contain; border-radius: 8px;\">
  10336.               </div>
  10337.               <div class=\"product-info\">
  10338.                 <h4>Album Photo Premium</h4>
  10339.                 <div class=\"product-pricing\">
  10340.                   <span class=\"current-price\">24,90€</span>
  10341.                   <span class=\"original-price\">28,90€</span>
  10342.                   <span class=\"savings\">-14%</span>
  10343.                 </div>
  10344.               </div>
  10345.               <div class=\"product-favorites-indicator\" title=\"Photos favorites sélectionnées\">
  10346.                 <i class=\"bi bi-heart-fill\" style=\"color: #f56040\"></i>
  10347.                 <span id=\"album-fav-count\">{{ (likes|default([]))|length }}</span>
  10348.               </div>
  10349.             </div>
  10350.             <p class=\"product-description\">
  10351.               Album photo personnalisé avec vos <strong id=\"album-count\">{{ (likes|default([]))|length }}</strong> photos favorites. Papier de qualité supérieure, reliure rigide.
  10352.             </p>
  10353.             <button class=\"product-cta\" onclick=\"orderProduct('album')\" 
  10354.                     title=\"Commander l'album photo avec vos photos favorites\">
  10355.               <i class=\"bi bi-cart-plus\"></i>
  10356.               Commander l'album
  10357.             </button>
  10358.           </div>
  10359.           <!-- Pack Numérique -->
  10360.           <div class=\"product-card\" id=\"digital-card\">
  10361.             <div class=\"product-header\">
  10362.               <div class=\"product-icon\">
  10363.                 <img src=\"/images/produit/photoNumerique.jpg\" alt=\"Pack Numérique HD\" style=\"width: 100%; height: 100%; object-fit: contain; border-radius: 8px;\">
  10364.               </div>
  10365.               <div class=\"product-info\">
  10366.                 <h4>Pack Numérique HD</h4>
  10367.                 <p class=\"price\">À partir de 3,90€</p>
  10368.               </div>
  10369.                 <div class=\"product-favorites-indicator\" title=\"Photos favorites sélectionnées\">
  10370.                   <i class=\"bi bi-heart-fill\" style=\"color: #f56040\"></i>
  10371.                   <span id=\"digital-fav-count\">{{ (likes|default([]))|length }}</span>
  10372.                 </div>
  10373.             </div>
  10374.             <p class=\"product-description\">
  10375.               Téléchargement immédiat de vos <strong id=\"digital-count\">{{ (likes|default([]))|length }}</strong> photos en haute définition. Qualité professionnelle garantie.
  10376.             </p>
  10377.             <button class=\"product-cta\" onclick=\"orderProduct('digital')\" 
  10378.                     title=\"Télécharger vos photos en haute définition\">
  10379.               <i class=\"bi bi-download\"></i>
  10380.               Télécharger HD
  10381.             </button>
  10382.           </div>
  10383.           <!-- Pochette Tirages -->
  10384.           <div class=\"product-card\" id=\"prints-card\" style=\"display: none;\">
  10385.             <div class=\"product-header\">
  10386.               <div class=\"product-icon\">
  10387.                 <i class=\"bi bi-images\"></i>
  10388.               </div>
  10389.               <div class=\"product-info\">
  10390.                 <h4>Pochette Tirages</h4>
  10391.                 <p class=\"price\">À partir de 9,90€</p>
  10392.               </div>
  10393.               <div class=\"product-favorites-indicator\" title=\"Photos favorites sélectionnées\">
  10394.                 <i class=\"bi bi-heart-fill\" style=\"color: #f56040\"></i>
  10395.                 <span>{{ (likes|default([]))|length }}</span>
  10396.               </div>
  10397.             </div>
  10398.             <p class=\"product-description\">
  10399.               <strong id=\"prints-count\">12</strong> tirages photo 10x15cm de vos favoris. Papier brillant professionnel, envoi sous 48h.
  10400.             </p>
  10401.             <button class=\"product-cta\" onclick=\"orderProduct('prints')\" 
  10402.                     title=\"Commander des tirages photo de vos favoris\">
  10403.               <i class=\"bi bi-printer\"></i>
  10404.               Commander les tirages
  10405.             </button>
  10406.           </div>
  10407.         </div>
  10408.         <!-- Réassurance -->
  10409.         <div class=\"reassurance\">
  10410.           <i class=\"bi bi-shield-check\" style=\"color: #10b981; margin-right: 8px;\"></i>
  10411.           <strong>Imprimé en France – satisfaction garantie ✅</strong>
  10412.         </div>
  10413.         
  10414.       </div>
  10415.     </div>
  10416.     <div class=\"selection-popover\" id=\"selectionPopover\">
  10417.       <h4>Votre sélection</h4>
  10418.       <p>Tirages : {{ (likes|default([]))|length }} / 12</p>
  10419.       <p>Numériques : {{ (likes|default([]))|length }} / 15</p>
  10420.       <p>Album : {{ (likes|default([]))|length }} / 20</p>
  10421.       <button class=\"finalize-button\" onclick=\"openEcommerceSidebar()\" 
  10422.               title=\"Voir les produits disponibles avec vos favoris\">
  10423.         <i class=\"bi bi-gift\"></i>
  10424.         Finaliser ma commande
  10425.       </button>
  10426.     </div>
  10427.     
  10428.     <style>
  10429.       /* Amélioration des boutons de produits */
  10430.       .product-cta {
  10431.         background: #3a8d95;
  10432.         border: none;
  10433.         border-radius: 25px;
  10434.         color: white;
  10435.         padding: 12px 24px;
  10436.         font-weight: 600;
  10437.         cursor: pointer;
  10438.         transition: all 0.3s ease;
  10439.         display: flex;
  10440.         align-items: center;
  10441.         gap: 8px;
  10442.         width: 100%;
  10443.         justify-content: center;
  10444.         margin-top: 10px;
  10445.       }
  10446.       
  10447.       .product-cta:hover {
  10448.         transform: translateY(-2px);
  10449.         box-shadow: 0 5px 15px rgba(58, 141, 149, 0.4);
  10450.         background: #2f7a82;
  10451.       }
  10452.       
  10453.       .product-cta:active {
  10454.         transform: translateY(0);
  10455.       }
  10456.       
  10457.       .product-cta:disabled {
  10458.         background: #ccc;
  10459.         cursor: not-allowed;
  10460.         transform: none;
  10461.         box-shadow: none;
  10462.       }
  10463.       
  10464.       .finalize-button {
  10465.         background: linear-gradient(135deg, #e91e63 0%, #ad1457 100%);
  10466.         border: none;
  10467.         border-radius: 25px;
  10468.         color: white;
  10469.         padding: 12px 24px;
  10470.         font-weight: 600;
  10471.         cursor: pointer;
  10472.         transition: all 0.3s ease;
  10473.         display: flex;
  10474.         align-items: center;
  10475.         gap: 8px;
  10476.         width: 100%;
  10477.         justify-content: center;
  10478.         margin-top: 15px;
  10479.       }
  10480.       
  10481.       .finalize-button:hover {
  10482.         transform: translateY(-2px);
  10483.         box-shadow: 0 5px 15px rgba(233, 30, 99, 0.4);
  10484.         background: linear-gradient(135deg, #d81b60 0%, #9c1450 100%);
  10485.       }
  10486.       
  10487.       /* Amélioration des cartes de produits */
  10488.       .product-card {
  10489.         border-radius: 12px;
  10490.         box-shadow: 0 4px 15px rgba(0,0,0,0.1);
  10491.         transition: all 0.3s ease;
  10492.         margin-bottom: 20px;
  10493.         overflow: hidden;
  10494.       }
  10495.       
  10496.       .product-card:hover {
  10497.         transform: translateY(-5px);
  10498.         box-shadow: 0 8px 25px rgba(0,0,0,0.15);
  10499.       }
  10500.       
  10501.       .product-header {
  10502.         display: flex;
  10503.         align-items: center;
  10504.         gap: 15px;
  10505.         padding: 20px;
  10506.         background: #f8f9fa;
  10507.       }
  10508.       
  10509.       .product-icon {
  10510.         width: 60px;
  10511.         height: 60px;
  10512.         border-radius: 8px;
  10513.         overflow: hidden;
  10514.         flex-shrink: 0;
  10515.       }
  10516.       
  10517.       .product-info h4 {
  10518.         margin: 0 0 5px 0;
  10519.         color: #333;
  10520.         font-weight: 600;
  10521.       }
  10522.       
  10523.       .product-pricing {
  10524.         display: flex;
  10525.         align-items: center;
  10526.         gap: 10px;
  10527.         margin: 5px 0;
  10528.       }
  10529.       
  10530.       .current-price {
  10531.         font-size: 1.2rem;
  10532.         font-weight: 700;
  10533.         color: #e91e63;
  10534.       }
  10535.       
  10536.       .original-price {
  10537.         text-decoration: line-through;
  10538.         color: #666;
  10539.         font-size: 0.9rem;
  10540.       }
  10541.       
  10542.       .savings {
  10543.         background: #4caf50;
  10544.         color: white;
  10545.         padding: 2px 8px;
  10546.         border-radius: 12px;
  10547.         font-size: 0.8rem;
  10548.         font-weight: 600;
  10549.       }
  10550.       
  10551.       .product-description {
  10552.         padding: 0 20px 20px 20px;
  10553.         color: #666;
  10554.         line-height: 1.5;
  10555.       }
  10556.       
  10557.       .product-favorites-indicator {
  10558.         display: flex;
  10559.         align-items: center;
  10560.         gap: 5px;
  10561.         background: rgba(245, 96, 64, 0.1);
  10562.         padding: 5px 10px;
  10563.         border-radius: 15px;
  10564.         font-size: 0.9rem;
  10565.         color: #f56040;
  10566.         font-weight: 600;
  10567.       }
  10568.     </style>
  10569.   </div>
  10570.   {# Zone promo - Masquée si pas de photos #}
  10571.   {% if attachementsCount|default(0) > 0 %}
  10572.   
  10573.   {# Calculer si séjour terminé #}
  10574.   {% set isSejourTermine = sejour.dateFinSejour < date() %}
  10575.   {% set finCodeDate = sejour.dateFinCode is defined and sejour.dateFinCode is not null ? sejour.dateFinCode : sejour.dateFinSejour|date_modify('+42 days') %}
  10576.   {% set daysUntilClose = ((finCodeDate|date('U') - 'now'|date('U')) / 86400)|round(0, 'ceil') %}
  10577.   
  10578.   <section id=\"heroPromo\" style=\"margin: 0; padding: 0;\">
  10579.     {# BANDEAU SÉJOUR TERMINÉ - S'affiche pour tout séjour passé #}
  10580.     {% if isSejourTermine %}
  10581.     <div class=\"promo-banner-termine\" id=\"promoBannerTermine\">
  10582.       <div class=\"promo-banner-content\">
  10583.         <span class=\"promo-banner-icon\">🎬</span>
  10584.         <div class=\"promo-banner-text\">
  10585.           {% if daysUntilClose > 0 %}
  10586.             <strong>Séjour terminé — Dernière chance !</strong>
  10587.             Plus que <span class=\"promo-days\">{{ daysUntilClose }}</span> jour{{ daysUntilClose > 1 ? 's' : '' }} pour commander vos souvenirs.
  10588.           {% else %}
  10589.             <strong>Séjour terminé</strong>
  10590.             Créez vos souvenirs : albums, tirages, photos numériques...
  10591.           {% endif %}
  10592.         </div>
  10593.         <a href=\"{{ path('boutique5sur5') }}\" class=\"promo-banner-cta\">Commander</a>
  10594.         <button class=\"promo-banner-close\" onclick=\"this.parentElement.parentElement.style.display='none'\" aria-label=\"Fermer\">×</button>
  10595.       </div>
  10596.     </div>
  10597.     {% else %}
  10598.     {# SLIDER PROMO PREMIUM - Séjour en cours #}
  10599.     <div class=\"divSliderModern\" style=\"margin: 0; padding: 0; width: 100%; overflow: hidden;\">
  10600.       <div class=\"splide no-padding no-margin\" id=\"imageSlider\" style=\"width: 100%;\">
  10601.         <div class=\"splide__track\" style=\"width: 100%;\">
  10602.           <ul class=\"splide__list\" style=\"width: 100%;\">
  10603.             <li class=\"splide__slide\" style=\"width: 100%;\">
  10604.               <div class=\"slider-content-compact\">
  10605.                 <img src=\"{{ asset('/images/imgSliderEmpty2.png') }}\" class=\"imgslider-compact\" alt=\"Produits souvenirs\" />
  10606.                 <div class=\"slider-text-compact\">
  10607.                   <span class=\"slider-title-compact\" style=\"color: #41a2aa\">Ajoutez vos favoris</span>
  10608.                   <span class=\"slider-subtitle-compact\" style=\"color: #f09e7a\">et créez vos souvenirs personnalisés !</span>
  10609.                 </div>
  10610.             </div>
  10611.           </li>
  10612.             <li class=\"splide__slide\" style=\"width: 100%;\">
  10613.               <div class=\"slider-content-compact\">
  10614.                 <img src=\"{{ asset('/images/imgSliderEmpty1.png') }}\" class=\"imgslider-compact\" alt=\"Livre du séjour\" />
  10615.                 <div class=\"slider-text-compact\">
  10616.                   <span class=\"slider-title-compact\" style=\"color: #f09e7a\">Pensez à commander le livre</span>
  10617.                   <span class=\"slider-subtitle-compact\" style=\"color: #41a2aa\">et offrez le plus beau des cadeaux !</span>
  10618.               </div>
  10619.             </div>
  10620.           </li>
  10621.         </ul>
  10622.       </div>
  10623.     </div>
  10624.   </div>
  10625.     {% endif %}
  10626.   </section>
  10627.   {% endif %}
  10628.   {# Fin heroPromo #}
  10629.   
  10630.   <!-- Section de contenu à atteindre après le scroll -->
  10631.   <div
  10632.     class=\"no-margin\"
  10633.     id=\"scrollTarget\"
  10634.     style=\"width: 100%; background: #ffffff; padding-top: 16px\"
  10635.   >
  10636.     <div class=\"no-margin\" id=\"scrollTarget\" style=\"width: 100%\">
  10637.       <!-- Header premium 5sur5 -->
  10638.       <header class=\"premium-5sur5-day-header\" style=\"padding: 5px 25px; background: #ffffff; border-bottom: 1px solid rgba(65, 162, 170, 0.1); margin-bottom: -15px;\">
  10639.         <div class=\"d-flex justify-content-between align-items-center flex-wrap gap-3\">
  10640.           <div class=\"flex-grow-1\">
  10641.             <h5 class=\"premium-5sur5-day-title\" style=\"margin: 0 0 6px 0; font-size: 1.3rem; font-weight: 700; color: #1a1a1a;\">
  10642.               {{ sejour.themSejour }}
  10643.             </h5>
  10644.             <p class=\"premium-5sur5-day-subtitle\" style=\"margin: 0; font-size: 0.9rem; color: #6b7280; font-weight: 500;\">
  10645.                    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.\"}) }}
  10646.           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.\"}) }}
  10647.               · Code : <span style=\"color: #41a2aa; font-weight: 600;\">{{sejour.codeSejour}}</span>
  10648.             </p>
  10649.         </div>
  10650.           <!-- 🎯 MEDIA TOOLBAR PREMIUM - Style 5sur5 -->
  10651.           <div class=\"premium-5sur5-actions-group\" style=\"gap: 8px;\">
  10652.             <!-- Tout -->
  10653.           <button class=\"premium-5sur5-action-btn mtb-btn {% if attachementsCount|default(0) > 0 %}active{% endif %}\" data-filter=\"all\" title=\"Tout\">
  10654.             <i class=\"bi bi-grid-3x3-gap-fill\"></i>
  10655.             <span>Tout</span>
  10656.             <span class=\"premium-5sur5-badge\" style=\"background: rgba(65, 162, 170, 0.1); color: #41A2AA;\">{{ attachementsCount|default(0) }}</span>
  10657.             </button>
  10658.           <!-- Favoris -->
  10659.           <button 
  10660.             class=\"premium-5sur5-action-btn mtb-btn {% if nblikes|default(0) == 0 %}favoris-empty{% endif %}\" 
  10661.             data-filter=\"favoris\" 
  10662.             title=\"{% if nblikes|default(0) == 0 %}Pas de favoris pour l'instant{% else %}Mes favoris{% endif %}\"
  10663.             {% if nblikes|default(0) == 0 %}disabled{% endif %}
  10664.           >
  10665.             <i class=\"bi bi-heart-fill\" style=\"color:{% if nblikes|default(0) == 0 %}#cbd5e1{% else %}#f56040{% endif %};\"></i>
  10666.             <span>Favoris</span>
  10667.             <span class=\"favoris-count\" id=\"mesFavCount\" data-bind=\"fav\" data-empty-text=\"Pas de favoris\">
  10668.               {% if nblikes|default(0) == 0 %}
  10669.                 <span class=\"favoris-empty-text\" style=\"color: #94a3b8; font-style: italic; font-size: 11px;\">Pas de favoris</span>
  10670.               {% else %}
  10671.                 <span class=\"premium-5sur5-badge\" style=\"background: rgba(245, 96, 64, 0.1); color: #F56040;\">{{ nblikes }}</span>
  10672.               {% endif %}
  10673. </span>
  10674.             </button>
  10675.           <!-- Vocal -->
  10676.           <button class=\"premium-5sur5-action-btn mtb-btn\" data-filter=\"audio\" title=\"Messages vocaux\">
  10677.             <span class=\"icon-telephone-voicemail\" style=\"display: inline-flex; align-items: center; gap: 0;\">
  10678.               <i class=\"bi bi-telephone-fill\" style=\"color:#ffd700; font-size: 14px;\"></i>
  10679.               <i class=\"bi bi-voicemail\" style=\"color:#ffd700; font-size: 14px; margin-left: -4px;\"></i>
  10680.             </span>
  10681.             <span>Vocal</span>
  10682.             <span class=\"mtb-count premium-5sur5-badge\" data-bind=\"audio\" style=\"background: rgba(255, 215, 0, 0.15); color: #ffa500;\">0</span>
  10683.             </button>
  10684.           </div>
  10685.         </div>
  10686.       </header>
  10687.         <!-- Navigation par jours - Style Premium compact -->
  10688.         <div class=\"section-days\" style=\"background: #f8fafb; border-radius: 0px; padding: 10px 12px; margin: 12px 0 16px 0; border: 1px solid rgba(65, 162, 170, 0.1);\">
  10689.           <div class=\"date-navigation d-flex align-items-center justify-content-center\" style=\"gap: 0;\">
  10690.             <div class=\"date-container d-flex\" style=\"overflow-x: auto; overflow-y: hidden; gap: 10px; padding: 4px 0; scrollbar-width: thin; scrollbar-color: #41a2aa #f0f0f0;\">
  10691.               {% for x, groupAttach in listeattach %}
  10692.                 {% set xDate = date(x) %}
  10693.                 {% set finDate = date(sejour.dateFinSejour) %}
  10694.                 {% set todayStr = 'now'|date('Y-m-d') %}
  10695.                 {% set currentDateStr = xDate|date('Y-m-d') %}
  10696.                 
  10697.                 {% if xDate <= finDate %}
  10698.                   {# États du jour : passé / courant / futur #}
  10699.                   {% set isPast = currentDateStr < todayStr %}
  10700.                   {% set isCurrent = currentDateStr == todayStr %}
  10701.                   {% set isFuture = currentDateStr > todayStr %}
  10702.                   {% set isFirstDay = groupAttach.isFirstDay == \"yes\" %}
  10703.                   {% set isLastDay = groupAttach.isLastDay == \"yes\" %}
  10704.                   
  10705.                   {# Classes premium #}
  10706.                   {% set cardClasses = ['date-card', 'premium-day-card'] %}
  10707.                   {% if isFuture %}
  10708.                     {% set cardClasses = cardClasses|merge(['premium-day-future', 'notclickable']) %}
  10709.                   {% elseif isCurrent %}
  10710.                     {% set cardClasses = cardClasses|merge(['premium-day-current', 'active']) %}
  10711.                   {% else %}
  10712.                     {% set cardClasses = cardClasses|merge(['premium-day-past']) %}
  10713.                     {% if loop.last and not isCurrent %}
  10714.                       {% set cardClasses = cardClasses|merge(['active']) %}
  10715.                     {% endif %}
  10716.                   {% endif %}
  10717.                   <div
  10718.                     class=\"{{ cardClasses|join(' ') }} position-relative\"
  10719.                     id=\"iconedemoP{{ loop.index }}\"
  10720.                     {% if isFuture %}
  10721.                       data-tooltip=\"Ce jour n'est pas encore accessible\"
  10722.                       aria-disabled=\"true\"
  10723.                     {% else %}
  10724.                     data-bs-toggle=\"collapse\"
  10725.                     data-bs-target=\"#demP{{ loop.index }}\"
  10726.                       data-day-id=\"{{ currentDateStr }}\"
  10727.                       aria-expanded=\"false\"
  10728.                       aria-controls=\"demP{{ loop.index }}\"
  10729.                     tabindex=\"0\"
  10730.                     {% endif %}
  10731.                   >
  10732.                     {# Badge pour premier/dernier jour #}
  10733.                     {% if groupAttach.isFirstDay == \"yes\" %}
  10734.                       <span class=\"badge bg-success text-white position-absolute\" style=\"top: 5px; left: 5px; font-size: 0.5rem; padding: 0.2rem 0.2rem;\">
  10735.                         <i class=\"bi bi-play-fill me-1\"></i>
  10736.                       </span>
  10737.                     {% elseif groupAttach.isLastDay == \"yes\" %}
  10738.                       <span class=\"badge bg-info text-white position-absolute\" style=\"top: 5px; left: 5px; font-size: 0.5rem; padding: 0.2rem 0.2rem;\">
  10739.                         <i class=\"bi bi-flag-fill ms-1\"></i>
  10740.                       </span>
  10741.                     {% endif %}
  10742.                     
  10743.                     <div class=\"card-content text-center\">
  10744.                       <span class=\"day\">
  10745.                        {{ xDate|date(\"D\")|replace({
  10746.                           \"Mon\": \"lun.\", \"Tue\": \"mar.\", \"Wed\": \"mer.\",
  10747.                           \"Thu\": \"jeu.\", \"Fri\": \"ven.\", \"Sat\": \"sam.\",
  10748.                           \"Sun\": \"dim.\"
  10749.                         }) }}  
  10750.                       </span>
  10751.                       <span class=\"full-date\">
  10752.                         {{ xDate|date(\"d M Y\")|replace({
  10753.                           \"Jan\": \"janv.\", \"Feb\": \"fév.\", \"Mar\": \"mars\",
  10754.                           \"Apr\": \"avr.\",  \"May\": \"mai\",   \"Jun\": \"juin\",
  10755.                           \"Jul\": \"juil.\", \"Aug\": \"août\",  \"Sep\": \"sept.\",
  10756.                           \"Oct\": \"oct.\",  \"Nov\": \"nov.\",  \"Dec\": \"déc.\"
  10757.                         }) }}
  10758.                       </span>
  10759.                       <ul class=\"media-list-horizontal\">
  10760.                         {% if groupAttach.countPhotos > 0 %}
  10761.                           <li><i class=\"bi bi-camera\"></i> {{ groupAttach.countPhotos }}</li>
  10762.                         {% endif %}
  10763.                         {% if groupAttach.countAudio > 0 %}
  10764.                           <li><i class=\"bi bi-mic-fill\"></i> {{ groupAttach.countAudio }}</li>
  10765.                         {% endif %}
  10766.                         {% if groupAttach.countVideos > 0 %}
  10767.                           <li><i class=\"bi bi-camera-video\"></i> {{ groupAttach.countVideos }}</li>
  10768.                         {% endif %}
  10769.                       </ul>
  10770.                     </div>
  10771.                   </div>
  10772.                 {% endif %}
  10773.               {% endfor %}
  10774.             </div>
  10775.           </div>
  10776.         </div>
  10777.     <!-- Carte produit flottante -->
  10778.     <div id=\"dynamic-card\" class=\"dynamic-card\" style=\"display:none\">
  10779.       <div id=\"dynamic-card-content\" class=\"dynamic-card-content\" >
  10780.         <!-- Le contenu dynamique (album, pochette, montage vidéo) sera injecté ici -->
  10781.       </div>
  10782.     </div>
  10783.     <!-- Descriptions and Attachments avec sidebar B2C -->
  10784.     <div class=\"container-xxl\" style=\"padding: 0 25px;  margin: 0 auto;\">
  10785.       <div class=\"row g-2 col-md-12\" style=\"margin: 0;\">
  10786.         <div class=\"col-lg-12 col-md-12\" style=\"padding: 0;\">
  10787.           {# Galerie principale #}
  10788.           <div class=\"container--gallery modern\" data-anchor=\"gallery\" style=\"padding: 0;\">
  10789.             {% set lastValidIndex = 0 %}
  10790.             {% set hasAttachments = false %}
  10791.       {% for x, groupAttach in listeattach %}
  10792.       {% set xDate = date(x) %}
  10793.       {% set finDate = date(sejour.dateFinSejour) %}
  10794.       {% if xDate <= finDate %}
  10795.       {% set lastValidIndex = loop.index %}
  10796.       {% set hasAttachments = true %}
  10797.       <div
  10798.         id=\"demP{{ loop.index }}\"
  10799.         class=\"collapse {% if loop.last and xDate <= finDate %}show{% endif %}\"
  10800.         style=\"padding: 12px 0;\"
  10801.       >
  10802.         <div >
  10803.         <div class=\"entry-header\" style=\"
  10804.     display: none;
  10805.     align-items: center;
  10806.     justify-content: space-between;
  10807.     background: #ffffff;
  10808.     padding: 8px 15px;
  10809.     border-radius: 10px;
  10810.     margin-bottom: 20px;
  10811.     box-shadow: 0 2px 8px rgba(0,0,0,0.05);
  10812.     border-bottom: 1px solid #eee;
  10813.     flex-wrap: wrap;
  10814. \">
  10815.  
  10816.  
  10817.   <!-- Centre : Date + Médias -->
  10818.   <div style=\"
  10819.       flex-grow: 1;
  10820.       display: flex;
  10821.       align-items: center;
  10822.       justify-content: center;
  10823.       flex-wrap: wrap;
  10824.       gap: 12px;
  10825.   \">
  10826.     <!-- Date -->
  10827.     <div style=\"font-weight: bold; font-size: 16px; color: #333;\">
  10828.       {{ x|date(\"l d F Y\")|replace({
  10829.           \"Monday\": \"Lundi\", \"Tuesday\": \"Mardi\", \"Wednesday\": \"Mercredi\",
  10830.           \"Thursday\": \"Jeudi\", \"Friday\": \"Vendredi\", \"Saturday\": \"Samedi\",
  10831.           \"Sunday\": \"Dimanche\",
  10832.           \"January\": \"Janvier\", \"February\": \"Février\", \"March\": \"Mars\",
  10833.           \"April\": \"Avril\", \"May\": \"Mai\", \"June\": \"Juin\",
  10834.           \"July\": \"Juillet\", \"August\": \"Août\", \"September\": \"Septembre\",
  10835.           \"October\": \"Octobre\", \"November\": \"Novembre\", \"December\": \"Décembre\"
  10836.       }) }}
  10837.     </div>
  10838.   <!-- Filtres Médias -->
  10839. <div class=\"filter-icons\" style=\"display: flex; gap: 8px; flex-wrap: wrap;\">
  10840.     <span class=\"filter-badge active\" data-filter=\"all\" title=\"Afficher tout\">
  10841.         <i class=\"bi bi-grid-3x3-gap-fill\" style=\"margin-right: 5px; font-size: 14px;\"></i> Tout
  10842.     </span>
  10843.     {% if groupAttach.countPhotos > 0 %}
  10844.     <span class=\"filter-badge\" data-filter=\"photo\" title=\"Filtrer les photos\">
  10845.         <i class=\"bi bi-image\" style=\"margin-right: 5px; font-size: 14px;\"></i> {{ groupAttach.countPhotos }}
  10846.     </span>
  10847.     {% endif %}
  10848.     {% if groupAttach.countVideos > 0 %}
  10849.     <span class=\"filter-badge\" data-filter=\"video\" title=\"Filtrer les vidéos\">
  10850.         <i class=\"bi bi-camera-video-fill\" style=\"margin-right: 5px; font-size: 14px;\"></i> {{ groupAttach.countVideos }}
  10851.     </span>
  10852.     {% endif %}
  10853.     {% if groupAttach.countAudio > 0 %}
  10854.     <span class=\"filter-badge\" data-filter=\"audio\" title=\"Filtrer les messages audio\">
  10855.         <i class=\"bi bi-mic-fill\" style=\"margin-right: 5px; font-size: 14px;\"></i> {{ groupAttach.countAudio }}
  10856.     </span>
  10857.     {% endif %}
  10858. </div>
  10859.   </div>
  10860.    
  10861.    
  10862.         </div>
  10863.   <!-- Bouton Jour Suivant -->
  10864.         <!-- Contenu -->
  10865.         <div class=\"entry-content\" id=\"TourContent\">
  10866.           <!-- Dropdown de filtrage par jour -->
  10867.           <div class=\"day-filter-dropdown\" data-day-index=\"{{ loop.index }}\">
  10868.             <button class=\"filter-toggle\" type=\"button\" aria-label=\"Options de filtrage\">
  10869.               <i class=\"bi bi-three-dots\"></i>
  10870.             </button>
  10871.             <div class=\"filter-dropdown-menu\">
  10872.               <div class=\"filter-option active\" data-filter=\"all\">
  10873.                 <i class=\"bi bi-grid-3x3-gap-fill\"></i>
  10874.                 <span>Tout</span>
  10875.                 <span class=\"count\" data-count-all>0</span>
  10876.               </div>
  10877.               <div class=\"filter-option\" data-filter=\"photo\">
  10878.                 <i class=\"bi bi-image\"></i>
  10879.                 <span>Photos</span>
  10880.                 <span class=\"count\" data-count-photo>{{ groupAttach.countPhotos|default(0) }}</span>
  10881.               </div>
  10882.               <div class=\"filter-option\" data-filter=\"video\">
  10883.                 <i class=\"bi bi-camera-video-fill\"></i>
  10884.                 <span>Vidéos</span>
  10885.                 <span class=\"count\" data-count-video>{{ groupAttach.countVideos|default(0) }}</span>
  10886.               </div>
  10887.               <div class=\"filter-option\" data-filter=\"audio\">
  10888.                 <i class=\"bi bi-mic-fill\"></i>
  10889.                 <span>Messages</span>
  10890.                 <span class=\"count\" data-count-audio>{{ groupAttach.countAudio|default(0) }}</span>
  10891.               </div>
  10892.             </div>
  10893.           </div>
  10894.                {% for description in sejour.jourdescripdate %}
  10895.       {%if   description.datejourphoto|date(\"m/d/Y\") !=\"\"%}{% if
  10896.             description.datejourphoto|date(\"m/d/Y\") == x|date(\"m/d/Y\") %}
  10897.           <p class=\"description\" style=\"margin-left:2%;width:95%;margin-top:1%;margin-bottom:1%;text-align:left\">
  10898.         
  10899.             {{ description.description | nl2br }}
  10900.          
  10901.           </p>   {% endif %} 
  10902.        {%endif%}{% endfor %}
  10903.  
  10904.           <!-- Conteneur des photos et vidéos -->
  10905.           <div
  10906.             class=\"rowimag no-margin\"
  10907.             style=\"
  10908.               width: 100%;
  10909.               display: flex;
  10910.               flex-wrap: wrap;
  10911.               margin: 0;
  10912.               box-sizing: border-box;
  10913.             \"
  10914.           >
  10915.             <!-- Afficher les Photos et Vidéos -->
  10916.             {% for attach in groupAttach.attachments %}
  10917.               {% if attach.libiller == 'photo' %}
  10918.            
  10919.             <div class=\"column\" data-type=\"{{ attach.libiller }}\">
  10920.             
  10921.               <div class=\"photo-zoom photo-item\">
  10922.                 <!-- Image sans lien -->
  10923.                 <img src=\"{{ attach.path }}\" alt=\"{{ attach.descreption }}\" loading=\"lazy\" decoding=\"async\" />
  10924.                 <!-- Icône \"voir\" pour ouvrir le slider -->
  10925.                 <div class=\"view-icon\" onclick=\"viewImage('{{ attach.id_attchment }}', this)\" title=\"Voir en plein écran\">
  10926.                   <i class=\"bi bi-eye-fill\"></i>
  10927.                 </div>
  10928.                 <!-- Icône du cœur avec logique existante -->
  10929.                 <div
  10930.                   class=\"heart-icon\"
  10931.                   id=\"coeur{{ attach.id_attchment }}\"
  10932.                   data-id=\"{{ attach.id_attchment }}\"
  10933.                   data-sejour-id=\"{{ sejour.id }}\"
  10934.                   data-path=\"{{ attach.path }}\"
  10935.                   data-description=\"{{ attach.descreption }}\"
  10936.                 >
  10937.                   {% if app.user %} {% if attach.is_favorite %}
  10938.                   <i
  10939.                     class=\"bi bi-heart-fill\"
  10940.                     title=\"Sélectionnée\"
  10941.                     style=\"color: #f56040\"
  10942.                   ></i>
  10943.                   {% else %}
  10944.                   <i class=\"bi bi-heart\" title=\"Ajouter à ma sélection\"></i>
  10945.                   {% endif %} {% endif %}
  10946.                 </div>
  10947.                 <div class=\"photo-actions\" style=\"display: none\">
  10948.                   <button class=\"menu-btn\">⋮</button>
  10949.                   <div class=\"menu-options\">
  10950.                     <button onclick=\"addToPack('tirage')\">
  10951.                       🖨️ Ajouter au tirage
  10952.                     </button>
  10953.                     <button onclick=\"addToPack('numerique')\">
  10954.                       💾 Ajouter au numérique
  10955.                     </button>
  10956.                   </div>
  10957.                 </div>
  10958.               
  10959.               </div>
  10960.               {% if attach.descreption != \"\" %}
  10961.               <h4 class=\"description\">{{ attach.descreption }}</h4>
  10962.               {% endif %}
  10963.             </div>
  10964.             {% endif %} 
  10965.              {% if attach.libiller == 'video' %}
  10966.            
  10967.             <div class=\"column\" data-type=\"{{ attach.libiller }}\">
  10968.                  
  10969.             
  10970.                  <div class=\"video-container\" style=\"position: relative; display: inline-block; width: 100%; border-radius: 8px; overflow: hidden;\">
  10971.                         <video class=\"photo-zoom\" controls controlslist=\"nodownload noplaybackrate\" style=\"width: 100%;\">
  10972.                           <source src=\"{{ attach.path }}\" type=\"video/mp4\" />
  10973.                           Votre navigateur ne supporte pas la lecture vidéo.
  10974.                         </video>
  10975.                       
  10976.                       </div>
  10977.               {% if attach.descreption != \"\" %}
  10978.               <h4 class=\"description\">{{ attach.descreption }}</h4>
  10979.               {% endif %}
  10980.             </div>
  10981.             {% endif %} 
  10982.             
  10983.             {% endfor %}
  10984.           </div>
  10985.           <!-- Section séparée pour les messages audio -->
  10986.           {% if groupAttach.countAudio > 0 %}
  10987.           <div class=\"audio-messages-section\" style=\"margin-top:15px; border-top: 1px solid #eee; padding: 30px;\">
  10988.             <h4 style=\"margin-bottom: 15px; color: #555\">
  10989.             
  10990.               <i class=\"bi bi-mic-fill\" style=\"margin-right: 8px; color: #ffa500\"></i>
  10991.               Messages vocaux ({{ groupAttach.countAudio }})
  10992.             </h4>
  10993.             
  10994.             {% if sejour.codeSejour|slice(0, 2) == 'PF' %}
  10995.               {# Les séjours commençant par PF ont toujours accès #}
  10996.               <div class=\"audio-messages-container\" data-type=\"audio\" style=\"display: flex; flex-wrap: wrap; gap: 15px\">
  10997.                 {% for attach in groupAttach.attachments %}
  10998.                   {% if attach.libiller == 'message' %}
  10999.                     <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;\">
  11000.                       <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 10px;\">
  11001.                         <i class=\"bi bi-mic-fill\" style=\"font-size: 20px; margin-right: 10px; color: #ffa500\"></i>
  11002.                         <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1\">
  11003.                           <source src=\"{{ attach.path }}\" type=\"audio/mp3\" />
  11004.                           Votre navigateur ne supporte pas la lecture audio.
  11005.                         </audio>
  11006.                       </div>
  11007.                       {% if attach.descreption != \"\" %}
  11008.                         <div class=\"audio-description\" style=\"padding-left: 30px\">
  11009.                           <p style=\"margin: 0; font-size: 14px; color: #555; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;\">
  11010.                             {{ attach.descreption }}
  11011.                           </p>
  11012.                         </div>
  11013.                       {% endif %}
  11014.                     </div>
  11015.                   {% endif %}
  11016.                 {% endfor %}
  11017.               </div>
  11018.             
  11019.             {% elseif sejour.codeSejour|slice(0, 2) == 'PP' and parentsejour.payment  == 1 or sejour.codeSejour|slice(0, 2) == 'EF' and parentsejour.payment  == 1 %}
  11020.               {# PP ou EF avec paiement effectué #}
  11021.               <div class=\"audio-messages-container\" data-type=\"audio\" style=\"display: flex; flex-wrap: wrap; gap: 15px\">
  11022.                 {% for attach in groupAttach.attachments %}
  11023.                   {% if attach.libiller == 'message' %}
  11024.                     <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;\">
  11025.                       <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 10px;\">
  11026.                         <i class=\"bi bi-mic-fill\" style=\"font-size: 20px; margin-right: 10px; color: #ffa500\"></i>
  11027.                         <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1\">
  11028.                           <source src=\"{{ attach.path }}\" type=\"audio/mp3\" />
  11029.                           Votre navigateur ne supporte pas la lecture audio.
  11030.                         </audio>
  11031.                       </div>
  11032.                       {% if attach.descreption != \"\" %}
  11033.                         <div class=\"audio-description\" style=\"padding-left: 30px\">
  11034.                           <p style=\"margin: 0; font-size: 14px; color: #555; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;\">
  11035.                             {{ attach.descreption }}
  11036.                           </p>
  11037.                         </div>
  11038.                       {% endif %}
  11039.                     </div>
  11040.                   {% endif %}
  11041.                 {% endfor %}
  11042.               </div>
  11043.             
  11044.             {% elseif sejour.codeSejour|slice(0, 2) == 'PP' and parentsejour.payment == 0 or sejour.codeSejour|slice(0, 2) == 'EF' and parentsejour.payment == 0 %}
  11045.               {# PP ou EF sans paiement - message d'accès limité et audio désactivés #}
  11046.               <div class=\"audio-messages-container\" style=\"display: flex; flex-wrap: wrap; gap: 15px; opacity: 0.5; pointer-events: none; filter: grayscale(100%);\">
  11047.                 <div class=\"audio-messages-restricted\" data-type=\"audio\" style=\"padding: 20px; background: #f0f0f0; border-radius: 8px; text-align: center; margin-bottom: 15px; width: 100%;\">
  11048.                   <i class=\"bi bi-lock-fill\" style=\"font-size: 24px; color: #808080; margin-bottom: 10px;\"></i>
  11049.                   <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>
  11050.                 </div>
  11051.                 {% for attach in groupAttach.attachments %}
  11052.                   {% if attach.libiller == 'message' %}
  11053.                     <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;\">
  11054.                       <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 10px;\">
  11055.                         <i class=\"bi bi-mic-fill\" style=\"font-size: 20px; margin-right: 10px; color: #ffa500\"></i>
  11056.                         <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1\" disabled>
  11057.                           <source src=\"{{ attach.path }}\" type=\"audio/mp3\" />
  11058.                           Votre navigateur ne supporte pas la lecture audio.
  11059.                         </audio>
  11060.                       </div>
  11061.                       {% if attach.descreption != \"\" %}
  11062.                         <div class=\"audio-description\" style=\"padding-left: 30px\">
  11063.                           <p style=\"margin: 0; font-size: 14px; color: #555; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;\">
  11064.                             {{ attach.descreption }}
  11065.                           </p>
  11066.                         </div>
  11067.                       {% endif %}
  11068.                     </div>
  11069.                   {% endif %}
  11070.                 {% endfor %}
  11071.               </div>
  11072.             {% endif %}
  11073.           </div>
  11074.         {% endif %}
  11075.         </div>
  11076.       </div>
  11077.     </div>
  11078.     {% endif %}
  11079.     {% endfor %}
  11080.     {% if not hasAttachments %}
  11081.   <section class=\"stay-empty-wrapper\">
  11082.   <div class=\"stay-empty-card\">
  11083.       <h2 class=\"stay-empty-title\">Aucune photo pour le moment, c'est normal.</h2>
  11084.     <p class=\"stay-empty-intro\">
  11085.         Le séjour démarre et l'équipe est pleinement avec les enfants : installation, découverte des lieux, premiers temps de vie de groupe.<br>
  11086.         Les premières photos ou messages vocaux sont généralement publiés en fin de journée d'arrivée ou le lendemain matin.
  11087.       </p>
  11088.       <!-- Bloc \"Ce qui va arriver\" + illustration -->
  11089.       <div class=\"stay-empty-expect\">
  11090.         <div class=\"stay-empty-expect-content\">
  11091.           <p class=\"stay-empty-expect-label\">Ce qui va arriver dans les prochaines heures :</p>
  11092.       <ul class=\"stay-empty-list\">
  11093.         <li>
  11094.               <span class=\"stay-empty-list-icon stay-empty-list-icon--check\">
  11095.                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  11096.                   <polyline points=\"20 6 9 17 4 12\"/>
  11097.                 </svg>
  11098.               </span>
  11099.               <span>1 photo ou message « Bien arrivés »</span>
  11100.         </li>
  11101.         <li>
  11102.               <span class=\"stay-empty-list-icon stay-empty-list-icon--photos\">
  11103.                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  11104.                   <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/>
  11105.                   <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/>
  11106.                   <polyline points=\"21 15 16 10 5 21\"/>
  11107.                 </svg>
  11108.               </span>
  11109.               <span>Quelques photos du lieu et du groupe</span>
  11110.         </li>
  11111.         <li>
  11112.               <span class=\"stay-empty-list-icon stay-empty-list-icon--vocal\">
  11113.                 <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  11114.                   <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\"/>
  11115.                   <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>
  11116.                 </svg>
  11117.               </span>
  11118.               <span>Un message vocal dès que le programme le permet</span>
  11119.         </li>
  11120.       </ul>
  11121.         </div>
  11122.         <!-- Illustration compacte -->
  11123.         <div class=\"stay-empty-illustration\">
  11124.           <svg class=\"stay-empty-phone\" viewBox=\"0 0 120 200\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">
  11125.             <rect x=\"0\" y=\"0\" width=\"120\" height=\"200\" rx=\"18\" fill=\"#1A1A2E\"/>
  11126.             <rect x=\"6\" y=\"10\" width=\"108\" height=\"180\" rx=\"14\" fill=\"#fff\"/>
  11127.             <rect x=\"12\" y=\"22\" width=\"44\" height=\"44\" rx=\"8\" fill=\"#F09E7A\" opacity=\"0.2\"/>
  11128.             <rect x=\"62\" y=\"22\" width=\"46\" height=\"44\" rx=\"8\" fill=\"#41A2AA\" opacity=\"0.2\"/>
  11129.             <rect x=\"12\" y=\"72\" width=\"96\" height=\"56\" rx=\"8\" fill=\"#9B8BF4\" opacity=\"0.15\"/>
  11130.             <circle cx=\"34\" cy=\"44\" r=\"10\" fill=\"#F09E7A\"/>
  11131.             <path d=\"M29 47l4-5 3 3 4-5 5 7H29z\" fill=\"#fff\"/>
  11132.             <circle cx=\"85\" cy=\"44\" r=\"10\" fill=\"#41A2AA\"/>
  11133.             <path d=\"M82 41v6M85 38v9M88 42v4\" stroke=\"#fff\" stroke-width=\"2\" stroke-linecap=\"round\"/>
  11134.             <circle cx=\"60\" cy=\"100\" r=\"12\" fill=\"rgba(255,255,255,0.9)\"/>
  11135.             <path d=\"M56 94l10 6-10 6V94z\" fill=\"#9B8BF4\"/>
  11136.             <rect x=\"12\" y=\"138\" width=\"96\" height=\"44\" rx=\"8\" fill=\"#F8FAFB\"/>
  11137.             <circle cx=\"34\" cy=\"160\" r=\"8\" fill=\"#E5E9F0\"/>
  11138.             <circle cx=\"60\" cy=\"160\" r=\"8\" fill=\"#41A2AA\"/>
  11139.             <circle cx=\"86\" cy=\"160\" r=\"8\" fill=\"#E5E9F0\"/>
  11140.             <rect x=\"42\" y=\"4\" width=\"36\" height=\"5\" rx=\"2.5\" fill=\"#1A1A2E\"/>
  11141.           </svg>
  11142.           <div class=\"stay-empty-bubble stay-empty-bubble--arrived\">
  11143.             <span class=\"stay-empty-bubble-icon\">
  11144.               <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  11145.                 <polyline points=\"20 6 9 17 4 12\"/>
  11146.               </svg>
  11147.             </span>
  11148.             Bien arrivés !
  11149.           </div>
  11150.           <div class=\"stay-empty-bubble stay-empty-bubble--photos\">
  11151.             <span class=\"stay-empty-bubble-icon\">
  11152.               <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  11153.                 <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/>
  11154.                 <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/>
  11155.                 <polyline points=\"21 15 16 10 5 21\"/>
  11156.               </svg>
  11157.             </span>
  11158.             +12 photos
  11159.           </div>
  11160.           <span class=\"stay-empty-illustration-label\">Exemple de nouvelles à venir</span>
  11161.         </div>
  11162.       </div>
  11163.       <!-- Note rassurante -->
  11164.       <div class=\"stay-empty-reassurance\">
  11165.         <svg class=\"stay-empty-reassurance-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  11166.           <path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\"/>
  11167.         </svg>
  11168.         <p>En cas de besoin important, l'école ou l'organisateur vous contactera directement, comme d'habitude.</p>
  11169.       </div>
  11170.       <!-- CTA -->
  11171.       <div class=\"stay-empty-footer\">
  11172.         <a href=\"{{ path('ParametresParent') }}\" class=\"stay-empty-cta\">
  11173.           <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">
  11174.             <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>
  11175.             <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>
  11176.           </svg>
  11177.           Gérer mes notifications
  11178.         </a>
  11179.     </div>
  11180.   </div>
  11181. </section>
  11182.   <div style=\"height: 200px;\"></div>
  11183.     {% endif %}
  11184.     
  11185.     <!-- JavaScript pour les pills et la gestion du nouveau contenu -->
  11186.     <script>
  11187.       document.addEventListener('DOMContentLoaded', function() {
  11188.         // Valider les liens de produits au chargement
  11189.         setTimeout(() => {
  11190.           if (typeof window.validateProductLinks === 'function') {
  11191.             window.validateProductLinks();
  11192.           }
  11193.         }, 1000);
  11194.         
  11195.         // ⚡ OPTIMISATION: Event delegation avec throttling pour éviter les clics multiples
  11196.         let clickThrottleTimeout = null;
  11197.         document.addEventListener('click', function(e) {
  11198.           // Throttling pour éviter les clics multiples rapides
  11199.           if (clickThrottleTimeout) return;
  11200.           
  11201.           const pill = e.target.closest('.stat-pill');
  11202.           if (pill) {
  11203.             clickThrottleTimeout = setTimeout(() => {
  11204.               clickThrottleTimeout = null;
  11205.             }, 100);
  11206.             
  11207.             // ⚡ OPTIMISÉ: Une seule boucle pour gérer les états actifs
  11208.             const statPills = document.querySelectorAll('.stat-pill');
  11209.             for (let i = 0; i < statPills.length; i++) {
  11210.               const p = statPills[i];
  11211.               if (p && p.classList) {
  11212.                 if (p === pill) {
  11213.                   p.classList.add('active');
  11214.                 } else {
  11215.                   p.classList.remove('active');
  11216.                 }
  11217.               }
  11218.             }
  11219.             
  11220.             // Déclencher le filtrage du contenu
  11221.             const filter = pill.getAttribute('data-filter');
  11222.             if (typeof window.filterContent === 'function') {
  11223.               window.filterContent(filter);
  11224.             }
  11225.           }
  11226.         });
  11227.         // Fonction de filtrage du contenu - globale
  11228.         window.filterContent = function(filter) {
  11229.           // ⚡ OPTIMISÉ: Suppression des console.log en production
  11230.           if (window.location.hostname === 'localhost' || window.location.hostname.includes('dev')) {
  11231.             console.log('Filtrage par:', filter);
  11232.           }
  11233.           
  11234.           const dateNavigation = document.querySelector('.date-navigation');
  11235.           const sectionDays = document.querySelector('.section-days');
  11236.           
  11237.           if (filter === 'favoris') {
  11238.             // Afficher la vue des favoris
  11239.             showFavoritesView();
  11240.           } else if (filter === 'audio') {
  11241.             // Afficher la vue des messages audio
  11242.             showAudiosView();
  11243.           } else if (filter === 'photos') {
  11244.             // Ouvrir le carrousel du jour actif ou du dernier jour
  11245.             openCurrentDayCarousel();
  11246.           } else {
  11247.             // Restaurer la vue normale des jours
  11248.             showDaysView();
  11249.           }
  11250.         }
  11251.         // Fonction pour afficher la vue des favoris - globale
  11252.         window.showFavoritesView = function() {
  11253.           const sectionDays = document.querySelector('.section-days');
  11254.           const containerGallery = document.querySelector('.container--gallery');
  11255.           
  11256.           // Masquer le container gallery
  11257.           if (containerGallery) {
  11258.             containerGallery.style.display = 'none';
  11259.           }
  11260.           
  11261.           // Mettre à jour l'état des boutons
  11262.           updatePhotosButtonState('favorites');
  11263.           updateAudioButtonState('favorites');
  11264.           updateFavoritesButtonState('favorites');
  11265.           
  11266.           const favoriteCount = getCurrentFavoriteCount();
  11267.           
  11268.           // sla vue des favoris avec e-commerce
  11269.           const favoritesHTML = `
  11270.             <div class=\"favorites-ecommerce-view\">
  11271.               <!-- Header avec progression -->
  11272.               <div class=\"favorites-header\">
  11273.                 <div class=\"favorites-title\">
  11274.                   <h3>Vos souvenirs sélectionnés</h3>
  11275.                   <span class=\"favorites-count\" id=\"favorites-count\">\${favoriteCount} photos</span>
  11276.                 </div>
  11277.                 <button class=\"btn-back-to-days\" onclick=\"window.showDaysView()\">
  11278.                   <i class=\"bi bi-arrow-left\"></i>
  11279.                   Retour aux jours
  11280.                 </button>
  11281.               </div>
  11282.             
  11283.               <!-- Grille des favoris -->
  11284.               <div class=\"favorites-content\">
  11285.                 <div class=\"favorites-grid\" id=\"favoritesGrid\">
  11286.                   \${generateFavoritesGrid()}
  11287.                 </div>
  11288.                 
  11289.                 <!-- CTA discret et premium pour rediriger vers la boutique -->
  11290.                 <a href=\"{{ path('boutique5sur5') }}\" class=\"premium-cta-subtle\" style=\"margin: 20px 0; padding: 16px 20px; background: rgba(65, 162, 170, 0.04); border: 1px solid rgba(65, 162, 170, 0.15); border-radius: 12px; cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; justify-content: space-between; gap: 12px; text-decoration: none;\">
  11291.                   <div style=\"display: flex; align-items: center; gap: 12px; flex: 1;\">
  11292.                     <div style=\"width: 40px; height: 40px; background: rgba(65, 162, 170, 0.1); border-radius: 10px; display: flex; align-items: center; justify-content: center; flex-shrink: 0;\">
  11293.                       <i class=\"bi bi-gift\" style=\"font-size: 18px; color: #41A2AA;\"></i>
  11294.                     </div>
  11295.                     <div style=\"flex: 1; min-width: 0;\">
  11296.                       <p style=\"margin: 0; font-size: 14px; font-weight: 600; color: #1a1a1a; line-height: 1.4;\">Créer des souvenirs avec vos \${favoriteCount} photos</p>
  11297.                       <p style=\"margin: 4px 0 0 0; font-size: 12px; color: #6b7280; line-height: 1.4;\">Albums, tirages et livres personnalisés</p>
  11298.                     </div>
  11299.                   </div>
  11300.                   <i class=\"bi bi-chevron-right\" style=\"font-size: 18px; color: #41A2AA; flex-shrink: 0;\"></i>
  11301.                 </a>
  11302.               </div>
  11303.             </div>
  11304.           `;
  11305.           
  11306.           sectionDays.innerHTML = favoritesHTML;
  11307.         }
  11308.         // Fonction pour afficher la vue des messages audio - globale
  11309.         window.showAudiosView = function() {
  11310.           const sectionDays = document.querySelector('.section-days');
  11311.           const containerGallery = document.querySelector('.container--gallery');
  11312.           
  11313.           // Masquer le container gallery
  11314.           if (containerGallery) {
  11315.             containerGallery.style.display = 'none';
  11316.           }
  11317.           
  11318.           // Mettre à jour l'état des boutons
  11319.           updatePhotosButtonState('audios');
  11320.           updateAudioButtonState('audios');
  11321.           updateFavoritesButtonState('audios');
  11322.           
  11323.           // Collecter tous les messages audio de tous les jours
  11324.           const allAudioMessages = [];
  11325.           const audioItems = document.querySelectorAll('.audio-message-item[data-type=\"audio\"]');
  11326.           
  11327.           audioItems.forEach(item => {
  11328.             const audio = item.querySelector('audio source');
  11329.             const description = item.querySelector('.audio-description p');
  11330.             const dayContainer = item.closest('[id^=\"demP\"]');
  11331.             let dayTitle = 'Jour inconnu';
  11332.             
  11333.             if (dayContainer) {
  11334.               // Trouver le titre du jour
  11335.               const dayIndex = dayContainer.id.replace('demP', '');
  11336.               const dayCard = document.querySelector(`[data-target=\"#demP\${dayIndex}\"]`);
  11337.               if (dayCard) {
  11338.                 dayTitle = dayCard.textContent.trim();
  11339.               } else {
  11340.                 // Essayer de trouver dans les cartes de date
  11341.                 const dateCard = document.querySelector(`.date-card[data-bs-target=\"#demP\${dayIndex}\"], .date-card[data-target=\"#demP\${dayIndex}\"]`);
  11342.                 if (dateCard) {
  11343.                   const dateText = dateCard.querySelector('.date-text, .card-title, h5, .title-line');
  11344.                   if (dateText) {
  11345.                     dayTitle = dateText.textContent.trim();
  11346.                   }
  11347.                 }
  11348.               }
  11349.             }
  11350.             
  11351.             if (audio) {
  11352.               allAudioMessages.push({
  11353.                 src: audio.src,
  11354.                 description: description ? description.textContent.trim() : '',
  11355.                 day: dayTitle,
  11356.                 isRestricted: item.closest('.audio-messages-container[style*=\"opacity: 0.5\"]') !== null
  11357.               });
  11358.             }
  11359.           });
  11360.           
  11361.           // Créer la vue des messages audio
  11362.           const audiosHTML = `
  11363.             <div class=\"audios-view\">
  11364.               <!-- Header -->
  11365.               <div class=\"audios-header\" style=\"display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding: 20px; background: #f8f9fa; border-radius: 10px;\">
  11366.                 <div class=\"audios-title\">
  11367.                   <h3><span class=\"icon-telephone-voicemail\">
  11368.   <i class=\"bi bi-telephone-fill tel\"  style=\"color: #ffd700;font-size:1.5em\"></i>
  11369.   <i class=\"bi bi-voicemail vm\" style=\"color: #ffd700;font-size: 0.9rem;
  11370.     transform: translate(-40%, -46%);\"></i>
  11371. </span>
  11372.                   <span class=\"audios-count\">\${allAudioMessages.length} messages</span>
  11373.                 </div>
  11374.                 <button class=\"btn-back-to-days\" onclick=\"window.showDaysView()\" style=\"background: #6c757d; color: white; border: none; padding: 8px 16px; border-radius: 5px; cursor: pointer;\">
  11375.                   <i class=\"bi bi-arrow-left\"></i>
  11376.                   Retour aux jours
  11377.                 </button>
  11378.               </div>
  11379.               <!-- Grille des messages audio -->
  11380.               <div class=\"audios-content\" style=\"display: flex; flex-wrap: wrap; gap: 20px;\">
  11381.                 \${allAudioMessages.map(msg => `
  11382.                   <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%);' : ''}\">
  11383.                     \${msg.day && msg.day !== 'Jour inconnu' ? `
  11384.                       <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;\">
  11385.                         \${msg.day}
  11386.                       </div>
  11387.                     ` : ''}
  11388.                     <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 12px;\">
  11389.                       <i class=\"bi bi-mic-fill\" style=\"font-size: 24px; margin-right: 15px; color: #ffa500;\"></i>
  11390.                       <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1; border-radius: 5px;\" \${msg.isRestricted ? 'disabled' : ''}>
  11391.                         <source src=\"\${msg.src}\" type=\"audio/mp3\" />
  11392.                         Votre navigateur ne supporte pas la lecture audio.
  11393.                       </audio>
  11394.                     </div>
  11395.                     \${msg.description ? `
  11396.                       <div class=\"audio-description\" style=\"padding-left: 39px;\">
  11397.                         <p style=\"margin: 0; font-size: 14px; color: #666; line-height: 1.4;\">\${msg.description}</p>
  11398.                       </div>
  11399.                     ` : ''}
  11400.                     \${msg.isRestricted ? `
  11401.                       <div class=\"audio-restricted-notice\" style=\"text-align: center; margin-top: 10px; padding: 8px; background: #fff3cd; border-radius: 5px; border: 1px solid #ffeaa7;\">
  11402.                         <i class=\"bi bi-lock-fill\" style=\"color: #856404; margin-right: 5px;\"></i>
  11403.                         <small style=\"color: #856404;\">Accès premium requis</small>
  11404.                       </div>
  11405.                     ` : ''}
  11406.                   </div>
  11407.                 `).join('')}
  11408.               </div>
  11409.               
  11410.               \${allAudioMessages.length === 0 ? `
  11411.                 <div class=\"no-audios\" style=\"text-align: center; padding: 60px 20px; color: #6c757d;\">
  11412.                   <i class=\"bi bi-mic\" style=\"font-size: 4rem; margin-bottom: 20px; opacity: 0.3;\"></i>
  11413.                   <h4>Aucun message vocal</h4>
  11414.                   <p>Il n'y a pas encore de messages vocaux dans ce séjour.</p>
  11415.                 </div>
  11416.               ` : ''}
  11417.             </div>
  11418.           `;
  11419.           
  11420.           sectionDays.innerHTML = audiosHTML;
  11421.         }
  11422.         
  11423.         // Variables pour sauvegarder le contenu original
  11424.         let originalDaysContent = null;
  11425.         
  11426.         // Sauvegarder le contenu original au chargement
  11427.         document.addEventListener('DOMContentLoaded', function() {
  11428.           setTimeout(() => {
  11429.             const containerGallery = document.querySelector('.container--gallery');
  11430.             if (containerGallery) {
  11431.               originalDaysContent = containerGallery.outerHTML;
  11432.             }
  11433.           }, 1000);
  11434.         });
  11435.         
  11436.       
  11437.         // Fonction pour ouvrir le carrousel contextuel - globale
  11438.         window.openCurrentDayCarousel = function() {
  11439.           // Détecter la vue active
  11440.           const currentView = detectCurrentView();
  11441.           
  11442.           switch (currentView) {
  11443.             case 'favorites':
  11444.               openFavoritesCarousel();
  11445.               break;
  11446.             case 'audios':
  11447.               // Dans la vue audios, pas de carrousel photos pertinent
  11448.               console.log('Carrousel photos non disponible dans la vue audios');
  11449.               return;
  11450.             case 'days':
  11451.             default:
  11452.               openActiveDayCarousel();
  11453.               break;
  11454.           }
  11455.         }
  11456.         
  11457.         // Fonction pour mettre à jour l'état du bouton photos selon le contexte
  11458.         function updatePhotosButtonState(currentView) {
  11459.           const photosBtn = document.querySelector('.mtb-btn[data-filter=\"photos\"]');
  11460.           if (!photosBtn) return;
  11461.           
  11462.           const btnIcon = photosBtn.querySelector('i');
  11463.           const btnCount = photosBtn.querySelector('.mtb-count');
  11464.           
  11465.           switch (currentView) {
  11466.             case 'favorites':
  11467.               // Dans les favoris : bouton actif, ouvre le carrousel des favoris
  11468.               photosBtn.style.opacity = '1';
  11469.               photosBtn.style.pointerEvents = 'auto';
  11470.               photosBtn.title = 'Voir le carrousel des favoris';
  11471.               if (btnIcon) btnIcon.style.color = '#007bff';
  11472.               if (btnCount) btnCount.style.display = 'none'; // Cacher le compteur
  11473.               break;
  11474.               
  11475.             case 'audios':
  11476.               // Dans les audios : bouton désactivé
  11477.               photosBtn.style.opacity = '0.4';
  11478.               photosBtn.style.pointerEvents = 'none';
  11479.               photosBtn.title = 'Carrousel non disponible dans la vue audios';
  11480.               if (btnIcon) btnIcon.style.color = '#6c757d';
  11481.               if (btnCount) btnCount.style.display = 'none';
  11482.               break;
  11483.               
  11484.             case 'days':
  11485.             default:
  11486.               // Vue normale : utiliser la logique existante du carrousel
  11487.               photosBtn.style.opacity = '1';
  11488.               photosBtn.style.pointerEvents = 'auto';
  11489.               photosBtn.title = 'Voir les photos du jour actif';
  11490.               if (btnIcon) btnIcon.style.color = '';
  11491.               if (btnCount) btnCount.style.display = 'none'; // Cacher le compteur pour éviter la confusion
  11492.               break;
  11493.           }
  11494.         }
  11495.         
  11496.         // Fonction pour mettre à jour l'état du bouton audio selon le contexte
  11497.         window.updateAudioButtonState = function updateAudioButtonState(currentView) {
  11498.           const audioBtn = document.querySelector('.mtb-btn[data-filter=\"audio\"]');
  11499.           if (!audioBtn) return;
  11500.           
  11501.           const btnCount = audioBtn.querySelector('.mtb-count');
  11502.           
  11503.           switch (currentView) {
  11504.             case 'favorites':
  11505.               // Dans les favoris : pas d'action sur le compteur audio
  11506.               break;
  11507.               
  11508.             case 'audios':
  11509.               // Dans les audios : afficher le nombre total calculé par le frontend
  11510.               const totalAudioCount = document.querySelectorAll('.audio-message-item[data-type=\"audio\"]').length;
  11511.               if (btnCount) {
  11512.                 btnCount.textContent = totalAudioCount;
  11513.               }
  11514.               break;
  11515.               
  11516.             case 'days':
  11517.             default:
  11518.               // Vue normale : compter les audios du jour actif
  11519.               const activeDayAudioCount = countActiveDayAudios();
  11520.               if (btnCount) {
  11521.                 btnCount.textContent = activeDayAudioCount;
  11522.               }
  11523.               break;
  11524.           }
  11525.         }
  11526.         
  11527.         // Fonction pour mettre à jour l'état du bouton favoris selon le contexte
  11528.         window.updateFavoritesButtonState = function updateFavoritesButtonState(currentView) {
  11529.           const favoritesBtn = document.querySelector('.mtb-btn[data-filter=\"favoris\"]');
  11530.           if (!favoritesBtn) return;
  11531.           
  11532.           const btnIcon = favoritesBtn.querySelector('i');
  11533.           const btnCount = favoritesBtn.querySelector('.mtb-count');
  11534.           
  11535.           // ✅ IMPORTANT : Le bouton favoris reste TOUJOURS accessible, peu importe la vue
  11536.           switch (currentView) {
  11537.             case 'favorites':
  11538.               // Dans les favoris : bouton actif marqué visuellement
  11539.               favoritesBtn.style.opacity = '1';
  11540.               favoritesBtn.style.pointerEvents = 'auto';
  11541.               favoritesBtn.title = 'Vous êtes dans la vue favoris';
  11542.               if (btnIcon) btnIcon.style.color = '#f56040';
  11543.               if (btnCount) btnCount.style.display = 'inline';
  11544.               favoritesBtn.classList.add('active');
  11545.               break;
  11546.               
  11547.             case 'audios':
  11548.               // Dans les audios : bouton reste actif et accessible ✅
  11549.               favoritesBtn.style.opacity = '1';
  11550.               favoritesBtn.style.pointerEvents = 'auto';
  11551.               favoritesBtn.title = 'Voir les favoris';
  11552.               if (btnIcon) btnIcon.style.color = '#f56040';
  11553.               if (btnCount) btnCount.style.display = 'inline';
  11554.               favoritesBtn.classList.remove('active');
  11555.               break;
  11556.               
  11557.             case 'days':
  11558.             default:
  11559.               // Vue normale : bouton normal et accessible
  11560.               favoritesBtn.style.opacity = '1';
  11561.               favoritesBtn.style.pointerEvents = 'auto';
  11562.               favoritesBtn.title = 'Voir les favoris';
  11563.               if (btnIcon) btnIcon.style.color = '#f56040';
  11564.               if (btnCount) btnCount.style.display = 'inline';
  11565.               favoritesBtn.classList.remove('active');
  11566.               break;
  11567.           }
  11568.         }
  11569.         
  11570.         // Fonction pour compter les audios du jour actif (réutilise la même logique)
  11571.         // ⚡ OPTIMISÉ: Cache des éléments DOM pour éviter les requêtes répétitives
  11572.         let cachedActiveDay = null;
  11573.         let cachedAudioCount = 0;
  11574.         let lastCacheTime = 0;
  11575.         const CACHE_DURATION = 1000; // 1 seconde
  11576.         
  11577.         function countActiveDayAudios() {
  11578.           const now = Date.now();
  11579.           
  11580.           // Utiliser le cache si récent
  11581.           if (cachedActiveDay && (now - lastCacheTime) < CACHE_DURATION) {
  11582.             return cachedAudioCount;
  11583.           }
  11584.           
  11585.           // Trouver le jour actuellement ouvert
  11586.           let activeDay = document.querySelector('.collapse.show[id^=\"demP\"]');
  11587.           
  11588.           // Si aucun jour ouvert, prendre le dernier jour
  11589.           if (!activeDay) {
  11590.             const allDays = document.querySelectorAll('.collapse[id^=\"demP\"]');
  11591.             activeDay = allDays[allDays.length - 1];
  11592.           }
  11593.           
  11594.           if (!activeDay) {
  11595.             cachedActiveDay = null;
  11596.             cachedAudioCount = 0;
  11597.             lastCacheTime = now;
  11598.             return 0;
  11599.           }
  11600.           
  11601.           // Compter les messages audio dans ce jour
  11602.           const audiosInDay = activeDay.querySelectorAll('.audio-message-item[data-type=\"audio\"]');
  11603.           const count = audiosInDay.length;
  11604.           
  11605.           // Mettre à jour le cache
  11606.           cachedActiveDay = activeDay;
  11607.           cachedAudioCount = count;
  11608.           lastCacheTime = now;
  11609.           
  11610.           return count;
  11611.         }
  11612.         
  11613.         // Fonction pour détecter la vue active
  11614.         // ⚡ OPTIMISÉ: Cache de la vue active pour éviter les requêtes DOM répétitives
  11615.         let cachedCurrentView = null;
  11616.         let lastViewCheck = 0;
  11617.         const VIEW_CACHE_DURATION = 500; // 500ms
  11618.         
  11619.         function detectCurrentView() {
  11620.           const now = Date.now();
  11621.           
  11622.           // Utiliser le cache si récent
  11623.           if (cachedCurrentView && (now - lastViewCheck) < VIEW_CACHE_DURATION) {
  11624.             return cachedCurrentView;
  11625.           }
  11626.           
  11627.           let view = 'days';
  11628.           if (document.querySelector('.favorites-ecommerce-view')) {
  11629.             view = 'favorites';
  11630.           } else if (document.querySelector('.audios-view')) {
  11631.             view = 'audios';
  11632.           }
  11633.           
  11634.           // Mettre à jour le cache
  11635.           cachedCurrentView = view;
  11636.           lastViewCheck = now;
  11637.           
  11638.           return view;
  11639.         }
  11640.         
  11641.         // ⚡ OPTIMISÉ: Cache global des éléments DOM fréquemment utilisés
  11642.         const domCache = {
  11643.           favoritesGrid: null,
  11644.           lastFavoritesUpdate: 0,
  11645.           CACHE_DURATION: 2000 // 2 secondes
  11646.         };
  11647.         
  11648.         function getCachedFavorites() {
  11649.           const now = Date.now();
  11650.           if (!domCache.favoritesGrid || (now - domCache.lastFavoritesUpdate) > domCache.CACHE_DURATION) {
  11651.             domCache.favoritesGrid = document.querySelector('.favorites-grid');
  11652.             domCache.lastFavoritesUpdate = now;
  11653.           }
  11654.           return domCache.favoritesGrid;
  11655.         }
  11656.         
  11657.         // Fonction pour ouvrir le carrousel des favoris
  11658.         function openFavoritesCarousel() {
  11659.           const favoritesGrid = getCachedFavorites();
  11660.           const favoriteItems = favoritesGrid ? favoritesGrid.querySelectorAll('.favorite-item') : [];
  11661.           if (favoriteItems.length > 0) {
  11662.             // Trouver le premier favori avec une action de vue
  11663.             const firstFavorite = favoriteItems[0];
  11664.             const viewBtn = firstFavorite.querySelector('.btn-view-favorite');
  11665.             if (viewBtn && viewBtn.onclick) {
  11666.               viewBtn.click();
  11667.             } else {
  11668.               // Fallback : extraire l'ID du data-id et utiliser viewImage
  11669.               const favoriteId = firstFavorite.dataset.id;
  11670.               if (favoriteId && typeof window.viewImage === 'function') {
  11671.                 window.viewImage(favoriteId, firstFavorite);
  11672.               }
  11673.             }
  11674.           } else {
  11675.             console.log('Aucun favori trouvé pour ouvrir le carrousel');
  11676.           }
  11677.         }
  11678.         
  11679.         // Fonction pour ouvrir le carrousel du jour actif
  11680.         function openActiveDayCarousel() {
  11681.           // Trouver le jour actuellement ouvert (avec classe 'show')
  11682.           let activeDay = document.querySelector('.collapse.show[id^=\"demP\"]');
  11683.           
  11684.           // Si aucun jour n'est ouvert, prendre le dernier jour
  11685.           if (!activeDay) {
  11686.             const allDays = document.querySelectorAll('.collapse[id^=\"demP\"]');
  11687.             activeDay = allDays[allDays.length - 1]; // Dernier jour
  11688.           }
  11689.           
  11690.           if (!activeDay) {
  11691.             console.warn('Aucun jour trouvé pour ouvrir le carrousel');
  11692.             return;
  11693.           }
  11694.           
  11695.           // Trouver la première photo de ce jour
  11696.           const viewIcon = activeDay.querySelector('.view-icon[onclick*=\"viewImage\"]');
  11697.           if (viewIcon) {
  11698.             // Extraire l'ID de la photo du onclick
  11699.             const onclickAttr = viewIcon.getAttribute('onclick');
  11700.             const match = onclickAttr.match(/viewImage\\('(\\d+)'/);
  11701.             if (match) {
  11702.               const imageId = match[1];
  11703.               // Ouvrir le slider avec cette image
  11704.               if (typeof window.viewImage === 'function') {
  11705.                 window.viewImage(imageId, viewIcon);
  11706.               }
  11707.             }
  11708.           } else {
  11709.             // Fallback : chercher dans tous les jours
  11710.             const allDays = document.querySelectorAll('.collapse[id^=\"demP\"]');
  11711.             for (let day of allDays) {
  11712.               const photoInDay = day.querySelector('.view-icon[onclick*=\"viewImage\"]');
  11713.               if (photoInDay) {
  11714.                 photoInDay.click();
  11715.                 break;
  11716.               }
  11717.             }
  11718.           }
  11719.         }
  11720.         // Fonction pour afficher la vue normale des jours - globale
  11721.         window.showDaysView = function() {
  11722.           const sectionDays = document.querySelector('.section-days');
  11723.           const containerGallery = document.querySelector('.container--gallery');
  11724.           
  11725.           // Si la section days contient des vues spéciales (favoris/audios), les supprimer
  11726.           if (sectionDays && (sectionDays.innerHTML.includes('favorites-ecommerce-view') || sectionDays.innerHTML.includes('audios-view'))) {
  11727.             // Restaurer le contenu original si disponible
  11728.             if (originalDaysContent) {
  11729.               sectionDays.innerHTML = originalDaysContent;
  11730.             } else {
  11731.               // Fallback : recharger la page si pas de sauvegarde
  11732.               location.reload();
  11733.               return;
  11734.             }
  11735.           }
  11736.           
  11737.           // Restaurer la visibilité du container gallery
  11738.           if (containerGallery) {
  11739.             containerGallery.style.display = 'block';
  11740.           }
  11741.           
  11742.           // Appeler le filtre \"all\" pour restaurer l'affichage complet
  11743.           if (typeof window.filterContent === 'function') {
  11744.             window.filterContent('toutVoir');
  11745.           }
  11746.           
  11747.           // Mettre à jour l'état des boutons
  11748.           updatePhotosButtonState('days');
  11749.           updateAudioButtonState('days');
  11750.           updateFavoritesButtonState('days');
  11751.         }
  11752.         // Fonction pour générer les cartes de jours (alternative simple)
  11753.         function generateDaysCards() {
  11754.           // Cette fonction pourrait régénérer les cartes, mais pour simplifier
  11755.           // on recharge la page dans showDaysView()
  11756.           return '';
  11757.         }
  11758.         // Fonction pour revenir à la vue des jours
  11759.      
  11760.         // Fonction pour générer la grille des favoris
  11761.         function generateFavoritesGrid() {
  11762.           const favorites = getFavoriteItems();
  11763.           
  11764.           if (favorites.length === 0) {
  11765.             return `
  11766.               <div class=\"no-favorites\">
  11767.                 <i class=\"bi bi-heart\" style=\"font-size: 3rem; color: #ccc; margin-bottom: 1rem;\"></i>
  11768.                 <h4>Aucun favori sélectionné</h4>
  11769.                 <p>Cliquez sur <i class=\"bi bi-heart\" style=\"color: #e91e63;\"></i> sur vos photos préférées pour les ajouter ici.</p>
  11770.               </div>
  11771.             `;
  11772.           }
  11773.           
  11774.           return favorites.map(item => `
  11775.             <div class=\"favorite-item photo-item\" data-id=\"\${item.id}\" style=\"position: relative; width: 100%; aspect-ratio: 1; border-radius: 12px; overflow: hidden; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); background: #f0f0f0;\">
  11776.               \${item.type === 'image' ? 
  11777.                 `<img src=\"\${item.url}\" alt=\"Photo favorite\" loading=\"lazy\" style=\"width: 100%; height: 100%; object-fit: cover; display: block;\">` :
  11778.                 item.type === 'video' ? 
  11779.                 `<video src=\"\${item.url}\" poster=\"\${item.thumbnail}\" style=\"width: 100%; height: 100%; object-fit: cover; display: block;\"></video>
  11780.                  <div class=\"video-overlay\" style=\"position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; background: rgba(0,0,0,0.3);\"><i class=\"bi bi-play-circle\" style=\"font-size: 48px; color: white;\"></i></div>` :
  11781.                 `<div class=\"audio-item\" style=\"width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; background: linear-gradient(135deg, rgba(65, 162, 170, 0.1) 0%, rgba(245, 96, 64, 0.1) 100%);\">
  11782.                    <i class=\"bi bi-mic-fill\" style=\"font-size: 32px; color: #41A2AA; margin-bottom: 8px;\"></i>
  11783.                    <span style=\"font-size: 14px; color: #6b7280; font-weight: 600;\">Audio \${item.duration || '00:00'}</span>
  11784.                  </div>`
  11785.               }
  11786.               <!-- Actions overlay -->
  11787.               <div class=\"favorite-actions\" style=\"position: absolute; top: 8px; right: 8px; display: flex; gap: 6px; opacity: 0; transition: opacity 0.3s ease;\">
  11788.                 <button class=\"btn-view-favorite\" onclick=\"viewFavorite('\${item.id}')\" title=\"Voir en grand\" style=\"width: 32px; height: 32px; border-radius: 8px; background: rgba(255,255,255,0.9); border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.1);\">
  11789.                   <i class=\"bi bi-eye\" style=\"font-size: 14px; color: #41A2AA;\"></i>
  11790.                 </button>
  11791.                 <button class=\"btn-remove-favorite\" onclick=\"removeFavorite('\${item.id}')\" title=\"Retirer des favoris\" style=\"width: 32px; height: 32px; border-radius: 8px; background: rgba(255,255,255,0.9); border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.1);\">
  11792.                   <i class=\"bi bi-heart-fill\" style=\"font-size: 14px; color: #f56040;\"></i>
  11793.                 </button>
  11794.               </div>
  11795.             </div>
  11796.           `).join('');
  11797.         }
  11798.         // Fonction pour réorganiser la grille des favoris
  11799.         function reorganizeFavoritesGrid() {
  11800.           const favoritesGrid = document.getElementById('favoritesGrid');
  11801.           if (!favoritesGrid) return;
  11802.           
  11803.           const remainingItems = favoritesGrid.querySelectorAll('.favorite-item');
  11804.           if (remainingItems.length === 0) {
  11805.             // Afficher le message \"Aucun favori\"
  11806.             favoritesGrid.innerHTML = `
  11807.               <div class=\"no-favorites\">
  11808.                 <i class=\"bi bi-heart\" style=\"font-size: 3rem; color: #ccc; margin-bottom: 1rem;\"></i>
  11809.                 <h4>Aucun favori sélectionné</h4>
  11810.                 <p>Cliquez sur <i class=\"bi bi-heart\" style=\"color: #e91e63;\"></i> sur vos photos préférées pour les ajouter ici.</p>
  11811.               </div>
  11812.             `;
  11813.           } else {
  11814.             // Réorganiser les éléments restants avec une animation douce
  11815.             remainingItems.forEach((item, index) => {
  11816.               item.style.transition = 'all 0.3s ease';
  11817.               item.style.order = index;
  11818.             });
  11819.           }
  11820.         }
  11821.         // Fonction pour récupérer les éléments favoris
  11822.         function getFavoriteItems() {
  11823.           const favorites = [];
  11824.           
  11825.           // ⚡ OPTIMISÉ: Cache et parcours plus efficace des favoris
  11826.           const heartIcons = document.querySelectorAll('.heart-icon');
  11827.           for (let i = 0; i < heartIcons.length; i++) {
  11828.             const heartIcon = heartIcons[i];
  11829.             const heartFill = heartIcon.querySelector('.bi-heart-fill');
  11830.             if (heartFill) {
  11831.               const id = heartIcon.getAttribute('data-id');
  11832.               const path = heartIcon.getAttribute('data-path');
  11833.               const description = heartIcon.getAttribute('data-description');
  11834.               
  11835.               if (id && path) {
  11836.                 // Déterminer le type de média
  11837.                 let type = 'image';
  11838.                 let url = path;
  11839.                 let thumbnail = path;
  11840.                 
  11841.                 if (path.includes('.mp4') || path.includes('.mov') || path.includes('.avi')) {
  11842.                   type = 'video';
  11843.                   thumbnail = path.replace(/\\.(mp4|mov|avi)\$/i, '_thumb.jpg');
  11844.                 } else if (path.includes('.mp3') || path.includes('.wav') || path.includes('.m4a')) {
  11845.                   type = 'audio';
  11846.                   url = path;
  11847.                 }
  11848.                 
  11849.                 // Récupérer la date depuis le conteneur parent
  11850.                 const dateCard = heartIcon.closest('[id^=\"demP\"]');
  11851.                 let date = 'Date inconnue';
  11852.                 if (dateCard) {
  11853.                   const dateElement = dateCard.querySelector('.full-date, .day-title');
  11854.                   if (dateElement) {
  11855.                     date = dateElement.textContent.trim();
  11856.                   }
  11857.                 }
  11858.                 
  11859.                 favorites.push({
  11860.                   id: id,
  11861.                   url: url,
  11862.                   thumbnail: thumbnail,
  11863.                   type: type,
  11864.                   date: date,
  11865.                   description: description || ''
  11866.                 });
  11867.               }
  11868.             }
  11869.           }
  11870.           
  11871.           // ⚡ OPTIMISÉ: Log conditionnel pour réduire l'impact performance
  11872.           if (favorites.length > 0) {
  11873.             console.log('Favoris trouvés:', favorites.length);
  11874.           }
  11875.           return favorites;
  11876.         }
  11877.         // Rendre les fonctions accessibles globalement
  11878.         window.viewFavorite = viewFavorite;
  11879.         window.removeFavorite = removeFavorite;
  11880.         window.getFavoriteItems = getFavoriteItems;
  11881.         // Fonction pour supprimer un favori
  11882.         function removeFavorite(id) {
  11883.          
  11884.           const heartIcon = document.querySelector(`[data-id=\"\${id}\"]`);
  11885.          
  11886.           if (heartIcon) {
  11887.             const heartFill = heartIcon.querySelector('.bi-heart-fill');
  11888.             if (heartFill && heartFill.classList) {
  11889.               heartFill.classList.remove('bi-heart-fill');
  11890.               heartFill.classList.add('bi-heart');
  11891.               heartFill.style.color = '';
  11892.             }
  11893.           }
  11894.           const favoriteItem = document.querySelector(`.favorite-item[data-id=\"\${id}\"]`);
  11895.         
  11896.           if (favoriteItem) {
  11897.             // Animation de disparition puis suppression complète
  11898.             favoriteItem.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
  11899.             favoriteItem.style.opacity = '0';
  11900.             favoriteItem.style.transform = 'scale(0.8)';
  11901.             
  11902.             setTimeout(() => {
  11903.               favoriteItem.remove();
  11904.               
  11905.               // Appeler la fonction métier si présente
  11906.               const heartIcon = document.querySelector(`#coeur\${id}`);
  11907.               const sejourId = heartIcon && heartIcon.dataset.sejourId ? heartIcon.dataset.sejourId : '';
  11908.               supprimerFavoris(id, sejourId);
  11909.               
  11910.               // Mettre à jour les compteurs
  11911.               updateAllFavoriteCounters();
  11912.               
  11913.               // Réorganiser la grille si nécessaire
  11914.               reorganizeFavoritesGrid();
  11915.             }, 300);
  11916.       
  11917.      
  11918.    
  11919.   }
  11920.           
  11921.         }
  11922.         // Slider plein écran pour les favoris
  11923.         class FavoritesSlider {
  11924.           constructor() {
  11925.             this.currentIndex = 0;
  11926.             this.favorites = [];
  11927.             this.isOpen = false;
  11928.             this.touchStartX = 0;
  11929.             this.touchEndX = 0;
  11930.           }
  11931.           open(favoriteId) {
  11932.             console.log('Ouverture du slider pour:', favoriteId);
  11933.             
  11934.             // Récupérer tous les favoris images
  11935.             this.favorites = getFavoriteItems().filter(item => item.type === 'image');
  11936.             
  11937.             if (this.favorites.length === 0) {
  11938.               console.error('Aucun favori image trouvé');
  11939.               return;
  11940.             }
  11941.             // Trouver l'index de l'image courante
  11942.             this.currentIndex = this.favorites.findIndex(fav => fav.id === favoriteId);
  11943.             if (this.currentIndex === -1) this.currentIndex = 0;
  11944.             console.log('Index courant:', this.currentIndex, 'Total:', this.favorites.length);
  11945.             this.createSlider();
  11946.             this.showSlide(this.currentIndex);
  11947.             this.attachEvents();
  11948.             this.isOpen = true;
  11949.             // Animation d'ouverture immédiate pour favoris avec diagnostic
  11950.             setTimeout(() => {
  11951.               if (window.diagnoseSliderDisplay) {
  11952.                 window.diagnoseSliderDisplay('#favoritesSlider');
  11953.               }
  11954.             }, 50);
  11955.           }
  11956.           createSlider() {
  11957.             // ⚡ OPTIMISATION: Créer le slider seulement quand nécessaire
  11958.             if (document.querySelector('#favoritesSlider')) {
  11959.               return; // Déjà créé, ne pas recréer
  11960.             }
  11961.             
  11962.             // Structure HTML minimale et optimisée
  11963.             const sliderHTML = `
  11964.               <div class=\"favorites-slider\" id=\"favoritesSlider\" style=\"
  11965.                 position: fixed !important; 
  11966.                 top: 0 !important; 
  11967.                 left: 0 !important; 
  11968.                 width: 100% !important; 
  11969.                 height: 100% !important; 
  11970.                 background: rgba(0,0,0,0.95) !important; 
  11971.                 z-index: 9999 !important; 
  11972.                 display: flex !important; 
  11973.                 align-items: center !important; 
  11974.                 justify-content: center !important; 
  11975.                 opacity: 1 !important; 
  11976.                 visibility: visible !important;
  11977.               \">
  11978.                 <div class=\"slider-overlay\"></div>
  11979.                 
  11980.                 <!-- Header avec contrôles -->
  11981.                 <div class=\"slider-header\">
  11982.                   <div class=\"slider-controls\">
  11983.                     <button class=\"slider-btn favorite-btn\" title=\"Retirer des favoris\">
  11984.                       <i class=\"bi bi-heart-fill\"></i>
  11985.                     </button>
  11986.                     <button class=\"slider-btn zoom-btn\" title=\"Zoom\">
  11987.                       <i class=\"bi bi-zoom-in\"></i>
  11988.                     </button>
  11989.                     <button class=\"slider-btn close-btn\" title=\"Fermer\">
  11990.                       <i class=\"bi bi-x-lg\"></i>
  11991.                     </button>
  11992.                   </div>
  11993.                 </div>
  11994.                 <!-- Navigation -->
  11995.                 <button class=\"slider-nav prev-btn\" title=\"Précédent\">
  11996.                   <i class=\"bi bi-arrow-left-circle-fill\"></i>
  11997.                 </button>
  11998.                 <button class=\"slider-nav next-btn\" title=\"Suivant\">
  11999.                   <i class=\"bi bi-arrow-right-circle-fill\"></i>
  12000.                 </button>
  12001.                 <!-- Container des slides -->
  12002.                 <div class=\"slider-container\">
  12003.                   <div class=\"slider-track\" id=\"sliderTrack\">
  12004.                     \${this.favorites.map((fav, index) => `
  12005.                       <div class=\"slide\" data-index=\"\${index}\">
  12006.                         <div class=\"slide-content\">
  12007.                           <img src=\"\${fav.url}\" alt=\"\${fav.description || 'Photo favorite'}\" 
  12008.                                loading=\"\${index <= 2 ? 'eager' : 'lazy'}\"
  12009.                                draggable=\"false\">
  12010.                         </div>
  12011.                         <div class=\"slide-info\">
  12012.                           <h4>\${fav.description || 'Photo favorite'}</h4>
  12013.                           <p>\${fav.date || 'Date inconnue'}</p>
  12014.                         </div>
  12015.                       </div>
  12016.                     `).join('')}
  12017.                   </div>
  12018.                 </div>
  12019.                 <!-- Thumbnails -->
  12020.                 <div class=\"slider-thumbnails\">
  12021.                   \${this.favorites.map((fav, index) => `
  12022.                     <div class=\"thumbnail \${index === this.currentIndex ? 'active' : ''}\" 
  12023.                          data-index=\"\${index}\">
  12024.                       <img src=\"\${fav.url}\" alt=\"Thumbnail \${index + 1}\">
  12025.                     </div>
  12026.                   `).join('')}
  12027.                 </div>
  12028.               </div>
  12029.             `;
  12030.             // Injecter dans le DOM
  12031.             document.body.insertAdjacentHTML('beforeend', sliderHTML);
  12032.           }
  12033.           showSlide(index) {
  12034.             if (index < 0 || index >= this.favorites.length) return;
  12035.             this.currentIndex = index;
  12036.             const track = document.getElementById('sliderTrack');
  12037.             const translateX = -index * 100;
  12038.             
  12039.             track.style.transform = `translateX(\${translateX}%)`;
  12040.             // ⚡ OPTIMISÉ: Éviter forEach sur querySelectorAll (mémoire)
  12041.             const thumbnails = document.querySelectorAll('.thumbnail');
  12042.             for (let i = 0; i < thumbnails.length; i++) {
  12043.               const thumb = thumbnails[i];
  12044.               if (thumb?.classList) {
  12045.                 thumb.classList.toggle('active', i === index);
  12046.               }
  12047.             }
  12048.             // Mettre à jour le bouton favori
  12049.             const currentFav = this.favorites[index];
  12050.             const favoriteBtn = document.querySelector('.slider-controls .favorite-btn');
  12051.             if (favoriteBtn && currentFav) {
  12052.               favoriteBtn.setAttribute('data-id', currentFav.id);
  12053.             }
  12054.           }
  12055.           nextSlide() {
  12056.             const nextIndex = (this.currentIndex + 1) % this.favorites.length;
  12057.             this.showSlide(nextIndex);
  12058.           }
  12059.           prevSlide() {
  12060.             const prevIndex = (this.currentIndex - 1 + this.favorites.length) % this.favorites.length;
  12061.             this.showSlide(prevIndex);
  12062.           }
  12063.           close() {
  12064.             if (!this.isOpen) return;
  12065.             const slider = document.querySelector('.favorites-slider');
  12066.             if (slider && slider.classList) {
  12067.               slider.classList.remove('active');
  12068.               
  12069.               setTimeout(() => {
  12070.                 slider.remove();
  12071.                 this.isOpen = false;
  12072.               }, 300);
  12073.             }
  12074.           }
  12075.           attachEvents() {
  12076.             const slider = document.getElementById('favoritesSlider');
  12077.             
  12078.             // Bouton fermer
  12079.             slider.querySelector('.close-btn').addEventListener('click', () => this.close());
  12080.             
  12081.             // Navigation
  12082.             slider.querySelector('.prev-btn').addEventListener('click', () => this.prevSlide());
  12083.             slider.querySelector('.next-btn').addEventListener('click', () => this.nextSlide());
  12084.             
  12085.             // ⚡ OPTIMISÉ: Event delegation au lieu de listeners multiples
  12086.             const thumbContainer = slider.querySelector('.thumbnails-container') || slider;
  12087.             if (thumbContainer && !thumbContainer.hasAttribute('data-thumb-delegated')) {
  12088.               thumbContainer.addEventListener('click', (e) => {
  12089.                 const thumb = e.target.closest('.thumbnail');
  12090.                 if (thumb) {
  12091.                   const thumbnails = slider.querySelectorAll('.thumbnail');
  12092.                   const index = Array.from(thumbnails).indexOf(thumb);
  12093.                   if (index !== -1) this.showSlide(index);
  12094.                 }
  12095.               });
  12096.               thumbContainer.setAttribute('data-thumb-delegated', 'true');
  12097.             }
  12098.             // Bouton favori
  12099.             slider.querySelector('.favorite-btn').addEventListener('click', (e) => {
  12100.               const favoriteId = e.currentTarget.getAttribute('data-id');
  12101.               if (favoriteId) {
  12102.                 removeFavorite(favoriteId);
  12103.                 // Recharger le slider avec les favoris mis à jour
  12104.                 setTimeout(() => {
  12105.                   this.close();
  12106.                   if (getFavoriteItems().filter(item => item.type === 'image').length > 0) {
  12107.                     this.open(this.favorites[0]?.id);
  12108.                   }
  12109.                 }, 100);
  12110.               }
  12111.             });
  12112.             // Clavier
  12113.             document.addEventListener('keydown', this.handleKeyboard.bind(this));
  12114.             
  12115.             // Clic sur overlay pour fermer
  12116.             slider.querySelector('.slider-overlay').addEventListener('click', () => this.close());
  12117.             // Touch/swipe sur mobile
  12118.             const track = slider.querySelector('.slider-track');
  12119.             track.addEventListener('touchstart', this.handleTouchStart.bind(this), { passive: true });
  12120.             track.addEventListener('touchend', this.handleTouchEnd.bind(this), { passive: true });
  12121.             // Zoom sur clic simple (5 niveaux) + double-clic (legacy)
  12122.             slider.querySelectorAll('.slide img').forEach(img => {
  12123.               let zoomLevel = 1;
  12124.               let isDragging = false;
  12125.               let startX, startY, translateX = 0, translateY = 0;
  12126.               
  12127.               // Zoom sur clic simple (nouveau système 5 niveaux)
  12128.               img.addEventListener('click', (e) => {
  12129.                 e.preventDefault();
  12130.                 e.stopPropagation();
  12131.                 
  12132.                 // Cycle à travers 5 niveaux de zoom
  12133.                 switch(zoomLevel) {
  12134.                   case 1: zoomLevel = 1.5; break;  // 1x → 1.5x
  12135.                   case 1.5: zoomLevel = 2; break;  // 1.5x → 2x
  12136.                   case 2: zoomLevel = 3; break;    // 2x → 3x
  12137.                   case 3: zoomLevel = 4; break;    // 3x → 4x
  12138.                   case 4: zoomLevel = 5; break;    // 4x → 5x
  12139.                   case 5: 
  12140.                     zoomLevel = 1;                 // 5x → 1x (reset)
  12141.                     translateX = 0;
  12142.                     translateY = 0;
  12143.                     break;
  12144.                 }
  12145.                 console.log('FavoritesSlider - Zoom niveau:', zoomLevel);
  12146.                 img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  12147.                 
  12148.                 // Curseur selon le niveau
  12149.                 if (zoomLevel === 1) {
  12150.                   img.style.cursor = 'zoom-in';
  12151.                   img.removeAttribute('data-zoomed');
  12152.                 } else if (zoomLevel === 5) {
  12153.                   img.style.cursor = 'zoom-out';
  12154.                   img.setAttribute('data-zoomed', zoomLevel);
  12155.                 } else {
  12156.                   img.style.cursor = 'zoom-in';
  12157.                   img.setAttribute('data-zoomed', zoomLevel);
  12158.                 }
  12159.               });
  12160.               
  12161.               // Drag pour déplacer l'image zoomée
  12162.               img.addEventListener('mousedown', (e) => {
  12163.                 if (zoomLevel > 1) {
  12164.                   isDragging = true;
  12165.                   startX = e.clientX - translateX;
  12166.                   startY = e.clientY - translateY;
  12167.                   img.style.cursor = 'grabbing';
  12168.                   e.preventDefault();
  12169.                   e.stopPropagation();
  12170.                 }
  12171.               });
  12172.               const handleMouseMove = (e) => {
  12173.                 if (isDragging && zoomLevel > 1) {
  12174.                   translateX = e.clientX - startX;
  12175.                   translateY = e.clientY - startY;
  12176.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  12177.                 }
  12178.               };
  12179.               const handleMouseUp = () => {
  12180.                 if (isDragging) {
  12181.                   isDragging = false;
  12182.                   if (zoomLevel === 1) {
  12183.                     img.style.cursor = 'zoom-in';
  12184.                   } else if (zoomLevel === 5) {
  12185.                     img.style.cursor = 'zoom-out';
  12186.                   } else {
  12187.                     img.style.cursor = 'zoom-in';
  12188.                   }
  12189.                 }
  12190.               };
  12191.               document.addEventListener('mousemove', handleMouseMove);
  12192.               document.addEventListener('mouseup', handleMouseUp);
  12193.               // Support tactile pour mobile
  12194.               img.addEventListener('touchstart', (e) => {
  12195.                 if (zoomLevel > 1 && e.touches.length === 1) {
  12196.                   isDragging = true;
  12197.                   const touch = e.touches[0];
  12198.                   startX = touch.clientX - translateX;
  12199.                   startY = touch.clientY - translateY;
  12200.                   e.preventDefault();
  12201.                 }
  12202.               });
  12203.               img.addEventListener('touchmove', (e) => {
  12204.                 if (isDragging && zoomLevel > 1 && e.touches.length === 1) {
  12205.                   const touch = e.touches[0];
  12206.                   translateX = touch.clientX - startX;
  12207.                   translateY = touch.clientY - startY;
  12208.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  12209.                   e.preventDefault();
  12210.                 }
  12211.               });
  12212.               img.addEventListener('touchend', () => {
  12213.                 isDragging = false;
  12214.               });
  12215.               // Initialiser le curseur
  12216.               img.style.cursor = 'zoom-in';
  12217.               
  12218.               // Garder aussi le double-clic pour compatibilité (legacy)
  12219.               img.addEventListener('dblclick', this.handleZoom.bind(this));
  12220.             });
  12221.           }
  12222.           handleKeyboard(e) {
  12223.             if (!this.isOpen) return;
  12224.             
  12225.             switch(e.key) {
  12226.               case 'Escape':
  12227.                 this.close();
  12228.                 break;
  12229.               case 'ArrowLeft':
  12230.                 e.preventDefault();
  12231.                 this.prevSlide();
  12232.                 break;
  12233.               case 'ArrowRight':
  12234.                 e.preventDefault();
  12235.                 this.nextSlide();
  12236.                 break;
  12237.             }
  12238.           }
  12239.           handleTouchStart(e) {
  12240.             this.touchStartX = e.changedTouches[0].screenX;
  12241.           }
  12242.           handleTouchEnd(e) {
  12243.             this.touchEndX = e.changedTouches[0].screenX;
  12244.             this.handleSwipe();
  12245.           }
  12246.           handleSwipe() {
  12247.             const swipeThreshold = 50;
  12248.             const diff = this.touchStartX - this.touchEndX;
  12249.             if (Math.abs(diff) > swipeThreshold) {
  12250.               if (diff > 0) {
  12251.                 this.nextSlide(); // Swipe left -> next
  12252.               } else {
  12253.                 this.prevSlide(); // Swipe right -> prev
  12254.               }
  12255.             }
  12256.           }
  12257.           handleZoom(e) {
  12258.             const img = e.target;
  12259.             
  12260.             // Vérifier que l'élément et ses propriétés existent
  12261.             if (!img || !img.classList) {
  12262.               console.warn('Élément image invalide pour le zoom');
  12263.               return;
  12264.             }
  12265.             
  12266.             // Gérer les différents niveaux de zoom
  12267.             if (img.classList.contains('zoom-4x')) {
  12268.               // Retour à la taille normale
  12269.               img.classList.remove('zoom-4x', 'zoom-3x', 'zoom-2x', 'zoomed');
  12270.               img.style.cursor = 'pointer';
  12271.               img.style.transform = 'scale(1)'; // Réinitialiser la position
  12272.             } else if (img.classList.contains('zoom-3x')) {
  12273.               // Passer au zoom 4x
  12274.               img.classList.remove('zoom-3x');
  12275.               img.classList.add('zoom-4x');
  12276.               img.style.cursor = 'zoom-out';
  12277.               img.style.transform = 'scale(4)'; // Réinitialiser la position
  12278.             } else if (img.classList.contains('zoom-2x')) {
  12279.               // Passer au zoom 3x
  12280.               img.classList.remove('zoom-2x');
  12281.               img.classList.add('zoom-3x');
  12282.               img.style.cursor = 'zoom-in';
  12283.               img.style.transform = 'scale(3)'; // Réinitialiser la position
  12284.             } else if (img.classList.contains('zoomed')) {
  12285.               // Passer au zoom 2x
  12286.               img.classList.remove('zoomed');
  12287.               img.classList.add('zoom-2x');
  12288.               img.style.cursor = 'zoom-in';
  12289.               img.style.transform = 'scale(2)'; // Réinitialiser la position
  12290.             } else {
  12291.               // Premier zoom (1.5x)
  12292.               img.classList.add('zoomed');
  12293.               img.style.cursor = 'zoom-in';
  12294.               img.style.transform = 'scale(1.5)'; // Réinitialiser la position
  12295.             }
  12296.           }
  12297.         }
  12298.         // Slider universel pour toutes les images (favoris + galerie normale)
  12299.         class UniversalImageSlider {
  12300.           constructor() {
  12301.             this.currentIndex = 0;
  12302.             this.images = [];
  12303.             this.isOpen = false;
  12304.             this.touchStartX = 0;
  12305.             this.touchEndX = 0;
  12306.           }
  12307.           // Ouvrir avec une image spécifique depuis les favoris
  12308.           openFromFavorites(favoriteId) {
  12309.             console.log('Ouverture du slider depuis favoris:', favoriteId);
  12310.             
  12311.             // Récupérer tous les favoris images
  12312.             this.images = getFavoriteItems().filter(item => item.type === 'image');
  12313.             
  12314.             if (this.images.length === 0) {
  12315.               console.error('Aucun favori image trouvé');
  12316.               return;
  12317.             }
  12318.             // Trouver l'index de l'image courante
  12319.             this.currentIndex = this.images.findIndex(img => img.id === favoriteId);
  12320.             if (this.currentIndex === -1) this.currentIndex = 0;
  12321.             this.openSlider();
  12322.           }
  12323.           // Ouvrir avec une image spécifique depuis la galerie normale
  12324.           openFromGallery(imageId, dayContainer) {
  12325.             console.log('Ouverture du slider depuis galerie:', imageId, dayContainer);
  12326.             
  12327.             // Récupérer toutes les images du jour courant
  12328.             const dayImages = [];
  12329.             
  12330.             // Chercher dans le container du jour (peut être .dynamic-card ou autre)
  12331.             let photoItems;
  12332.             if (dayContainer) {
  12333.               photoItems = dayContainer.querySelectorAll('.photo-item');
  12334.             } else {
  12335.               // Fallback: chercher dans tout le document
  12336.               photoItems = document.querySelectorAll('.photo-item');
  12337.             }
  12338.             
  12339.             console.log('Photo items trouvés:', photoItems.length);
  12340.             
  12341.             photoItems.forEach(item => {
  12342.               const img = item.querySelector('img');
  12343.               const heartIcon = item.querySelector('.heart-icon');
  12344.               
  12345.               console.log('Processing item:', {
  12346.                 img: !!img,
  12347.                 heartIcon: !!heartIcon,
  12348.                 imgSrc: img ? img.src : null,
  12349.                 heartIconId: heartIcon ? heartIcon.getAttribute('data-id') : null
  12350.               });
  12351.               
  12352.               if (img && heartIcon) {
  12353.                 dayImages.push({
  12354.                   id: heartIcon.getAttribute('data-id'),
  12355.                   url: heartIcon.getAttribute('data-path') || img.src,
  12356.                   description: heartIcon.getAttribute('data-description') || img.alt || 'Photo',
  12357.                   date: '', // Pas de date spécifique pour les images de galerie
  12358.                   type: 'image'
  12359.                 });
  12360.               }
  12361.             });
  12362.             console.log('Images trouvées:', dayImages);
  12363.             this.images = dayImages;
  12364.             
  12365.             if (this.images.length === 0) {
  12366.               console.error('Aucune image trouvée dans ce jour');
  12367.               // Essayer de créer au moins l'image courante
  12368.               const currentHeartIcon = document.querySelector(`[data-id=\"\${imageId}\"]`);
  12369.               if (currentHeartIcon) {
  12370.                 const currentImg = currentHeartIcon.closest('.photo-item').querySelector('img');
  12371.                 if (currentImg) {
  12372.                   this.images = [{
  12373.                     id: imageId,
  12374.                     url: currentHeartIcon.getAttribute('data-path') || currentImg.src,
  12375.                     description: currentHeartIcon.getAttribute('data-description') || currentImg.alt || 'Photo',
  12376.                     date: '',
  12377.                     type: 'image'
  12378.                   }];
  12379.                   console.log('Image de fallback créée:', this.images);
  12380.                 }
  12381.               }
  12382.               
  12383.               if (this.images.length === 0) {
  12384.                 return;
  12385.               }
  12386.             }
  12387.             // Trouver l'index de l'image courante
  12388.             this.currentIndex = this.images.findIndex(img => img.id === imageId);
  12389.             if (this.currentIndex === -1) this.currentIndex = 0;
  12390.             console.log('Index trouvé:', this.currentIndex);
  12391.             this.openSlider();
  12392.           }
  12393.           openSlider() {
  12394.             console.log('=== openSlider appelée ===');
  12395.             console.log('Index courant:', this.currentIndex, 'Total:', this.images.length);
  12396.             console.log('Images à afficher:', this.images);
  12397.             // Supprimer tout slider existant
  12398.             const existingSlider = document.querySelector('.universal-slider');
  12399.             if (existingSlider) {
  12400.               console.log('Suppression du slider existant');
  12401.               existingSlider.remove();
  12402.             }
  12403.             this.createSlider();
  12404.             this.showSlide(this.currentIndex);
  12405.             this.attachEvents();
  12406.             this.isOpen = true;
  12407.               // Animation d'ouverture immédiate et garantie avec diagnostic
  12408.               setTimeout(() => {
  12409.                 if (window.diagnoseSliderDisplay) {
  12410.                   window.diagnoseSliderDisplay('#universalSlider');
  12411.                 }
  12412.               }, 50);
  12413.           }
  12414.           createSlider() {
  12415.             // ⚡ OPTIMISATION: Créer seulement si nécessaire
  12416.             if (document.querySelector('#universalSlider')) {
  12417.               return; // Déjà créé
  12418.             }
  12419.             
  12420.             console.log('Création slider pour', this.images.length, 'images');
  12421.             
  12422.             // HTML optimisé et minimal
  12423.             const sliderHTML = `
  12424.               <div class=\"universal-slider\" id=\"universalSlider\" style=\"
  12425.                 position: fixed !important; 
  12426.                 top: 0 !important; 
  12427.                 left: 0 !important; 
  12428.                 width: 100% !important; 
  12429.                 height: 100% !important; 
  12430.                 background: rgba(0,0,0,0.95) !important; 
  12431.                 z-index: 9999 !important; 
  12432.                 display: flex !important; 
  12433.                 align-items: center !important; 
  12434.                 justify-content: center !important; 
  12435.                 opacity: 1 !important; 
  12436.                 visibility: visible !important;
  12437.               \">
  12438.                 <div class=\"slider-overlay\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; cursor: pointer;\"></div>
  12439.                 
  12440.                 <!-- Header avec contrôles -->
  12441.                 <div class=\"slider-header\" style=\"
  12442.                   position: absolute; 
  12443.                   top: 20px; 
  12444.                   right: 20px; 
  12445.                   display: flex; 
  12446.                   align-items: center; 
  12447.                   gap: 15px; 
  12448.                   z-index: 10001;
  12449.                 \">
  12450.                   <button class=\"slider-btn close-btn\" title=\"Fermer\" style=\"
  12451.                     background: rgba(255,255,255,0.2); 
  12452.                     border: none; 
  12453.                     color: white; 
  12454.                     width: 40px; 
  12455.                     height: 40px; 
  12456.                     border-radius: 50%; 
  12457.                     cursor: pointer; 
  12458.                     display: flex; 
  12459.                     align-items: center; 
  12460.                     justify-content: center;
  12461.                     transition: background 0.2s ease;
  12462.                   \">
  12463.                     <i class=\"bi bi-x-lg\"></i>
  12464.                   </button>
  12465.                 </div>
  12466.                 <!-- Navigation -->
  12467.                 <button class=\"slider-nav prev-btn\" title=\"Précédent\" style=\"
  12468.                   position: absolute; 
  12469.                   left: 20px; 
  12470.                   top: 50%; 
  12471.                   transform: translateY(-50%); 
  12472.                   background: rgba(255,255,255,0.2); 
  12473.                   border: none; 
  12474.                   color: white; 
  12475.                   width: 50px; 
  12476.                   height: 50px; 
  12477.                   border-radius: 50%; 
  12478.                   cursor: pointer; 
  12479.                   display: \${this.images.length > 1 ? 'flex' : 'none'}; 
  12480.                   align-items: center; 
  12481.                   justify-content: center; 
  12482.                   z-index: 10001;
  12483.                   transition: background 0.2s ease;
  12484.                 \">
  12485.                   <i class=\"bi bi-arrow-left-circle-fill\" style=\"font-size: 20px;\"></i>
  12486.                 </button>
  12487.                 <button class=\"slider-nav next-btn\" title=\"Suivant\" style=\"
  12488.                   position: absolute; 
  12489.                   right: 20px; 
  12490.                   top: 50%; 
  12491.                   transform: translateY(-50%); 
  12492.                   background: rgba(255,255,255,0.2); 
  12493.                   border: none; 
  12494.                   color: white; 
  12495.                   width: 50px; 
  12496.                   height: 50px; 
  12497.                   border-radius: 50%; 
  12498.                   cursor: pointer; 
  12499.                   display: \${this.images.length > 1 ? 'flex' : 'none'}; 
  12500.                   align-items: center; 
  12501.                   justify-content: center; 
  12502.                   z-index: 10001;
  12503.                   transition: background 0.2s ease;
  12504.                 \">
  12505.                   <i class=\"bi bi-arrow-right-circle-fill\" style=\"font-size: 20px;\"></i>
  12506.                 </button>
  12507.                 <!-- Container des slides -->
  12508.                 <div class=\"slider-container\" style=\"
  12509.                   position: relative; 
  12510.                   width: 90%; 
  12511.                   height: 90%; 
  12512.                   display: flex; 
  12513.                   align-items: center; 
  12514.                   justify-content: center; 
  12515.                   z-index: 10000;
  12516.                 \">
  12517.                   <div class=\"slider-track\" id=\"universalSliderTrack\" style=\"
  12518.                     position: relative; 
  12519.                     width: 100%; 
  12520.                     height: 100%; 
  12521.                     display: flex; 
  12522.                     align-items: center; 
  12523.                     justify-content: center;
  12524.                     overflow: hidden;
  12525.                   \">
  12526.                     \${this.images.map((img, index) => `
  12527.                       <div class=\"slide\" data-index=\"\${index}\" style=\"
  12528.                         position: absolute; 
  12529.                         width: 100%; 
  12530.                         height: 100%; 
  12531.                         display: \${index === 0 ? 'flex' : 'none'}; 
  12532.                         align-items: center; 
  12533.                         justify-content: center; 
  12534.                         flex-direction: column;
  12535.                       \">
  12536.                         <div class=\"slide-content\" style=\"
  12537.                           position: relative; 
  12538.                           max-width: 100%; 
  12539.                           max-height: 90%; 
  12540.                           display: flex; 
  12541.                           align-items: center; 
  12542.                           justify-content: center;
  12543.                         \">
  12544.                           <img src=\"\${img.url}\" alt=\"\${img.description || 'Photo'}\" 
  12545.                                loading=\"\${index <= 2 ? 'eager' : 'lazy'}\"
  12546.                                draggable=\"false\"
  12547.                                style=\"
  12548.                                  max-width: 100%; 
  12549.                                  max-height: 100%; 
  12550.                                  object-fit: contain; 
  12551.                                  cursor: zoom-in;
  12552.                                  transition: transform 0.3s ease;
  12553.                                  user-select: none;
  12554.                                \">
  12555.                         </div>
  12556.                         \${img.description ? `
  12557.                         <div class=\"slide-info\" style=\"
  12558.                           position: absolute; 
  12559.                           bottom: 60px; 
  12560.                           left: 50%; 
  12561.                           transform: translateX(-50%); 
  12562.                           text-align: center; 
  12563.                           color: white; 
  12564.                           background: rgba(0,0,0,0.6); 
  12565.                           padding: 8px 16px; 
  12566.                           border-radius: 20px; 
  12567.                           max-width: 80%;
  12568.                           font-size: 14px;
  12569.                         \">
  12570.                           \${img.description}
  12571.                         </div>
  12572.                         ` : ''}
  12573.                       </div>
  12574.                     `).join('')}
  12575.                   </div>
  12576.                 </div>
  12577.                 <!-- Galerie de thumbnails révolutionnaire -->
  12578.                 <div class=\"cinema-gallery\" style=\"
  12579.                   position: absolute; 
  12580.                   bottom: 0; 
  12581.                   left: 0; 
  12582.                   right: 0;
  12583.                   height: 180px;
  12584.                   background: linear-gradient(0deg, rgba(0,0,0,0.95) 0%, rgba(0,0,0,0.7) 50%, transparent 100%);
  12585.                   z-index: 10001;
  12586.                   display: flex;
  12587.                   flex-direction: column;
  12588.                   justify-content: flex-end;
  12589.                   padding: 0 20px 20px;
  12590.                 \">
  12591.                   
  12592.                   <!-- Info header avec compteur élégant -->
  12593.                   <div class=\"gallery-header\" style=\"
  12594.                     display: flex;
  12595.                     justify-content: space-between;
  12596.                     align-items: center;
  12597.                     margin-bottom: 15px;
  12598.                   \">
  12599.                     <div class=\"photo-counter\" style=\"
  12600.                       color: white;
  12601.                       font-size: 16px;
  12602.                       font-weight: 600;
  12603.                       display: flex;
  12604.                       align-items: center;
  12605.                       gap: 8px;
  12606.                     \">
  12607.                       <div style=\"
  12608.                         width: 8px;
  12609.                         height: 8px;
  12610.                         background: #10b981;
  12611.                         border-radius: 50%;
  12612.                         animation: pulse 2s infinite;
  12613.                       \"></div>
  12614.                       <span>\${(this.currentIndex || 0) + 1}</span>
  12615.                       <span style=\"opacity: 0.6;\">sur</span>
  12616.                       <span>\${this.images.length}</span>
  12617.                     </div>
  12618.                     <div class=\"gallery-controls\" style=\"
  12619.                       display: flex;
  12620.                       gap: 12px;
  12621.                       align-items: center;
  12622.                     \">
  12623.                       <div style=\"color: rgba(255,255,255,0.7); font-size: 12px;\">
  12624.                         Clic = Zoom 5x • Drag = Déplacer
  12625.                       </div>
  12626.                     </div>
  12627.                   </div>
  12628.                   
  12629.                   <!-- Carrousel de thumbnails cinématographique -->
  12630.                   <div class=\"cinema-carousel\" style=\"
  12631.                     position: relative;
  12632.                     height: 80px;
  12633.                     overflow: hidden;
  12634.                   \">
  12635.                     <!-- Container scrollable -->
  12636.                     <div class=\"carousel-track\" id=\"carouselTrack\" style=\"
  12637.                       display: flex;
  12638.                       gap: 12px;
  12639.                       height: 100%;
  12640.                       overflow-x: auto;
  12641.                       overflow-y: hidden;
  12642.                       scroll-behavior: smooth;
  12643.                       scrollbar-width: none;
  12644.                       -ms-overflow-style: none;
  12645.                       padding: 0 50px;
  12646.                     \">
  12647.                       \${this.images.map((img, index) => `
  12648.                         <div class=\"cinema-thumb \${index === 0 ? 'active' : ''}\" 
  12649.                              data-index=\"\${index}\" 
  12650.                              style=\"
  12651.                                flex: 0 0 auto;
  12652.                                width: \${index === 0 ? '100px' : '70px'};
  12653.                                height: 70px;
  12654.                                border-radius: 8px;
  12655.                                overflow: hidden;
  12656.                                cursor: pointer;
  12657.                                position: relative;
  12658.                                transition: transform 0.2s ease, opacity 0.2s ease;
  12659.                                transform: \${index === 0 ? 'translateY(-4px)' : 'translateY(0)'};
  12660.                                opacity: \${index === 0 ? '1' : '0.7'};
  12661.                                border: \${index === 0 ? '2px solid #10b981' : '1px solid rgba(255,255,255,0.3)'};
  12662.                              \"
  12663.                              onmouseenter=\"
  12664.                                if (\${index} !== (window.universalSlider?.currentIndex || 0)) {
  12665.                                  this.style.opacity = '0.9';
  12666.                                }
  12667.                              \"
  12668.                              onmouseleave=\"
  12669.                                if (\${index} !== (window.universalSlider?.currentIndex || 0)) {
  12670.                                  this.style.opacity = '0.7';
  12671.                                }
  12672.                              \">
  12673.                           
  12674.                           <!-- Image principale -->
  12675.                           <img src=\"\${img.url}\" 
  12676.                                alt=\"\${img.description || 'Photo'}\" 
  12677.                                loading=\"lazy\" 
  12678.                                decoding=\"async\"
  12679.                                style=\"
  12680.                                  width: 100%; 
  12681.                                  height: 100%; 
  12682.                                  object-fit: cover;
  12683.                                \">
  12684.                           
  12685.                           <!-- Numéro simplifié -->
  12686.                           <div class=\"thumb-number\" style=\"
  12687.                             position: absolute;
  12688.                             top: 4px;
  12689.                             right: 4px;
  12690.                             background: \${index === 0 ? '#10b981' : 'rgba(0,0,0,0.8)'};
  12691.                             color: white;
  12692.                             font-size: 10px;
  12693.                             font-weight: 500;
  12694.                             padding: 2px 5px;
  12695.                             border-radius: 4px;
  12696.                             min-width: 16px;
  12697.                             text-align: center;
  12698.                           \">
  12699.                             \${index + 1}
  12700.                           </div>
  12701.                           
  12702.                           <!-- Indicateur actif simplifié -->
  12703.                           \${index === 0 ? `
  12704.                           <div class=\"active-indicator\" style=\"
  12705.                             position: absolute;
  12706.                             bottom: -1px;
  12707.                             left: 50%;
  12708.                             transform: translateX(-50%);
  12709.                             width: 16px;
  12710.                             height: 2px;
  12711.                             background: #10b981;
  12712.                             border-radius: 1px;
  12713.                           \"></div>
  12714.                           ` : ''}
  12715.                           
  12716.                           <!-- Preview au hover pour les non-actifs -->
  12717.                           \${index !== 0 ? `
  12718.                           <div class=\"hover-preview\" style=\"
  12719.                             position: absolute;
  12720.                             bottom: -40px;
  12721.                             left: 50%;
  12722.                             transform: translateX(-50%);
  12723.                             background: rgba(0,0,0,0.9);
  12724.                             color: white;
  12725.                             font-size: 11px;
  12726.                             padding: 4px 8px;
  12727.                             border-radius: 6px;
  12728.                             opacity: 0;
  12729.                             pointer-events: none;
  12730.                             transition: all 0.3s ease;
  12731.                             white-space: nowrap;
  12732.                             z-index: 1000;
  12733.                           \">
  12734.                             Photo \${index + 1}
  12735.                           </div>
  12736.                           ` : ''}
  12737.                         </div>
  12738.                       `).join('')}
  12739.                     </div>
  12740.                     
  12741.                     <!-- Gradients de fade sur les côtés -->
  12742.                     <div style=\"
  12743.                       position: absolute;
  12744.                       left: 0;
  12745.                       top: 0;
  12746.                       bottom: 0;
  12747.                       width: 50px;
  12748.                       background: linear-gradient(90deg, rgba(0,0,0,0.8), transparent);
  12749.                       pointer-events: none;
  12750.                       z-index: 1;
  12751.                     \"></div>
  12752.                     <div style=\"
  12753.                       position: absolute;
  12754.                       right: 0;
  12755.                       top: 0;
  12756.                       bottom: 0;
  12757.                       width: 50px;
  12758.                       background: linear-gradient(-90deg, rgba(0,0,0,0.8), transparent);
  12759.                       pointer-events: none;
  12760.                       z-index: 1;
  12761.                     \"></div>
  12762.                   </div>
  12763.                 </div>
  12764.                 <!-- Animations CSS Optimisées -->
  12765.                 <style>
  12766.                   /* Optimisation: animations réduites et ciblées */
  12767.                   @keyframes pulse {
  12768.                     0%, 100% { opacity: 1; }
  12769.                     50% { opacity: 0.7; }
  12770.                   }
  12771.                   
  12772.                   /* Suppression du glow coûteux - remplacé par border simple */
  12773.                   .cinema-thumb.active .active-indicator {
  12774.                     background: #10b981;
  12775.                     animation: none; /* Suppression de l'animation glow */
  12776.                   }
  12777.                   
  12778.                   /* Hover optimisé - moins d'effets */
  12779.                   .cinema-thumb:hover .hover-preview {
  12780.                     opacity: 1 !important;
  12781.                     bottom: -35px !important;
  12782.                   }
  12783.                   
  12784.                   /* Masquer scrollbar */
  12785.                   .carousel-track::-webkit-scrollbar {
  12786.                     display: none;
  12787.                   }
  12788.                   
  12789.                   /* Optimisation: will-change pour les éléments animés */
  12790.                   .cinema-thumb {
  12791.                     will-change: transform, filter;
  12792.                   }
  12793.                   
  12794.                   .progress-bar {
  12795.                     will-change: width;
  12796.                   }
  12797.                 </style>
  12798.               </div>
  12799.             `;
  12800.             // Injecter dans le DOM
  12801.             console.log('Ajout du slider au DOM');
  12802.             document.body.insertAdjacentHTML('beforeend', sliderHTML);
  12803.             
  12804.             // Vérifier que le slider a été ajouté
  12805.             const addedSlider = document.querySelector('#universalSlider');
  12806.             console.log('Slider ajouté:', !!addedSlider);
  12807.             if (addedSlider) {
  12808.               console.log('Slider trouvé dans le DOM');
  12809.               console.log('Styles du slider:', {
  12810.                 display: addedSlider.style.display,
  12811.                 opacity: addedSlider.style.opacity,
  12812.                 visibility: addedSlider.style.visibility,
  12813.                 zIndex: addedSlider.style.zIndex,
  12814.                 position: addedSlider.style.position
  12815.               });
  12816.               console.log('Slider dans viewport:', addedSlider.getBoundingClientRect());
  12817.             } else {
  12818.               console.error('Erreur: slider non trouvé après ajout');
  12819.             }
  12820.           }
  12821.           showSlide(index) {
  12822.             console.log('=== showSlide appelée ===', 'index:', index, 'total:', this.images.length);
  12823.             if (index < 0 || index >= this.images.length) {
  12824.               console.log('Index invalide, arrêt');
  12825.               return;
  12826.             }
  12827.             this.currentIndex = index;
  12828.             // Masquer toutes les slides et afficher seulement la courante
  12829.             const slides = document.querySelectorAll('#universalSlider .slide');
  12830.             console.log('Slides trouvées:', slides.length);
  12831.             slides.forEach((slide, i) => {
  12832.               slide.style.display = i === index ? 'flex' : 'none';
  12833.               console.log(`Slide \${i}:`, i === index ? 'visible' : 'cachée');
  12834.             });
  12835.             // Mettre à jour le compteur
  12836.             const currentSlideSpan = document.querySelector('#universalSlider .current-slide');
  12837.             if (currentSlideSpan) {
  12838.               currentSlideSpan.textContent = index + 1;
  12839.               console.log('Compteur mis à jour:', index + 1);
  12840.             }
  12841.             // Mettre à jour les boutons de navigation
  12842.             const prevBtn = document.querySelector('#universalSlider .prev-btn');
  12843.             const nextBtn = document.querySelector('#universalSlider .next-btn');
  12844.             
  12845.             if (prevBtn) {
  12846.               prevBtn.style.opacity = index > 0 ? '1' : '0.5';
  12847.             }
  12848.             if (nextBtn) {
  12849.               nextBtn.style.opacity = index < this.images.length - 1 ? '1' : '0.5';
  12850.             }
  12851.             // Mettre à jour la galerie cinématographique
  12852.             this.updateCinemaGallery(index);
  12853.             // Mettre à jour le bouton favori
  12854.             this.updateFavoriteButton();
  12855.           }
  12856.           updateCinemaGallery(activeIndex) {
  12857.             // Mettre à jour la progress bar (optimisé)
  12858.             const progressBar = document.querySelector('.progress-bar');
  12859.             if (progressBar) {
  12860.               progressBar.style.width = `\${(activeIndex + 1) / this.images.length * 100}%`;
  12861.             }
  12862.             // Mettre à jour le compteur (optimisé)
  12863.             const counter = document.querySelector('.photo-counter span');
  12864.             if (counter) {
  12865.               counter.textContent = activeIndex + 1;
  12866.             }
  12867.             // Mettre à jour les thumbnails - optimisé avec moins de calculs
  12868.             const cinemaThumbs = document.querySelectorAll('.cinema-thumb');
  12869.             cinemaThumbs.forEach((thumb, i) => {
  12870.               const isActive = i === activeIndex;
  12871.               
  12872.               // Optimisation: changements minimaux
  12873.               if (isActive) {
  12874.                 thumb.style.width = '100px';
  12875.                 thumb.style.transform = 'translateY(-4px)';
  12876.                 thumb.style.opacity = '1';
  12877.                 thumb.style.borderColor = '#10b981';
  12878.                 thumb.style.borderWidth = '2px';
  12879.                 
  12880.                 // Numéro actif - simplifié
  12881.                 const number = thumb.querySelector('.thumb-number');
  12882.                 if (number) {
  12883.                   number.style.background = '#10b981';
  12884.                 }
  12885.               } else {
  12886.                 thumb.style.width = '70px';
  12887.                 thumb.style.transform = 'translateY(0)';
  12888.                 thumb.style.opacity = '0.7';
  12889.                 thumb.style.borderColor = 'rgba(255,255,255,0.3)';
  12890.                 thumb.style.borderWidth = '1px';
  12891.                 
  12892.                 // Numéro inactif - simplifié
  12893.                 const number = thumb.querySelector('.thumb-number');
  12894.                 if (number) {
  12895.                   number.style.background = 'rgba(0,0,0,0.8)';
  12896.                 }
  12897.               }
  12898.             });
  12899.             // Auto-scroll optimisé avec throttling
  12900.             if (!this.scrollTimeout) {
  12901.               this.scrollTimeout = setTimeout(() => {
  12902.                 const track = document.getElementById('carouselTrack');
  12903.                 const activeThumb = document.querySelector(`.cinema-thumb[data-index=\"\${activeIndex}\"]`);
  12904.                 if (track && activeThumb) {
  12905.                   const scrollLeft = activeThumb.offsetLeft - (track.clientWidth / 2) + (activeThumb.clientWidth / 2);
  12906.                   track.scrollTo({
  12907.                     left: scrollLeft,
  12908.                     behavior: 'smooth'
  12909.                   });
  12910.                 }
  12911.                 this.scrollTimeout = null;
  12912.               }, 50); // Throttle à 50ms
  12913.             }
  12914.           }
  12915.           updateFavoriteButton() {
  12916.             const currentImage = this.images[this.currentIndex];
  12917.             const favoriteBtn = document.querySelector('.slider-controls .favorite-btn');
  12918.             
  12919.             if (favoriteBtn && currentImage) {
  12920.               favoriteBtn.setAttribute('data-id', currentImage.id);
  12921.               
  12922.               // Vérifier si l'image est déjà en favoris
  12923.               const heartIcon = document.querySelector(`[data-id=\"\${currentImage.id}\"]`);
  12924.               const isFavorite = heartIcon && heartIcon.querySelector('i.bi-heart-fill');
  12925.               
  12926.               const icon = favoriteBtn.querySelector('i');
  12927.               if (isFavorite) {
  12928.                 icon.className = 'bi bi-heart-fill';
  12929.                 favoriteBtn.style.color = '#e91e63';
  12930.               } else {
  12931.                 icon.className = 'bi bi-heart';
  12932.                 favoriteBtn.style.color = 'white';
  12933.               }
  12934.             }
  12935.           }
  12936.           nextSlide() {
  12937.             const nextIndex = (this.currentIndex + 1) % this.images.length;
  12938.             this.showSlide(nextIndex);
  12939.           }
  12940.           prevSlide() {
  12941.             const prevIndex = (this.currentIndex - 1 + this.images.length) % this.images.length;
  12942.             this.showSlide(prevIndex);
  12943.           }
  12944.           close() {
  12945.             if (!this.isOpen) return;
  12946.             const slider = document.querySelector('.universal-slider');
  12947.             if (slider) {
  12948.               slider.classList.remove('active');
  12949.               
  12950.               setTimeout(() => {
  12951.                 slider.remove();
  12952.                 this.isOpen = false;
  12953.               }, 300);
  12954.             }
  12955.           }
  12956.           attachEvents() {
  12957.             console.log('=== attachEvents appelée ===');
  12958.             const slider = document.getElementById('universalSlider');
  12959.             if (!slider) {
  12960.               console.error('Slider non trouvé pour attachEvents');
  12961.               return;
  12962.             }
  12963.             console.log('Slider trouvé pour attachEvents');
  12964.             
  12965.             // Bouton fermer
  12966.             const closeBtn = slider.querySelector('.close-btn');
  12967.             if (closeBtn) {
  12968.               console.log('Bouton fermer trouvé');
  12969.               closeBtn.addEventListener('click', () => {
  12970.                 console.log('Clic fermer');
  12971.                 this.close();
  12972.               });
  12973.             }
  12974.             
  12975.             // Navigation
  12976.             const prevBtn = slider.querySelector('.prev-btn');
  12977.             const nextBtn = slider.querySelector('.next-btn');
  12978.             if (prevBtn) {
  12979.               console.log('Bouton précédent trouvé');
  12980.               prevBtn.addEventListener('click', () => {
  12981.                 console.log('Clic précédent');
  12982.                 this.prevSlide();
  12983.               });
  12984.             }
  12985.             if (nextBtn) {
  12986.               console.log('Bouton suivant trouvé');
  12987.               nextBtn.addEventListener('click', () => {
  12988.                 console.log('Clic suivant');
  12989.                 this.nextSlide();
  12990.               });
  12991.             }
  12992.             // Navigation cinématographique des thumbnails
  12993.             const cinemaThumbs = slider.querySelectorAll('.cinema-thumb');
  12994.             cinemaThumbs.forEach((thumb, index) => {
  12995.               thumb.addEventListener('click', () => {
  12996.                 console.log('Clic cinema thumbnail:', index);
  12997.                 this.showSlide(index);
  12998.                 this.updateCinemaGallery(index);
  12999.               });
  13000.             });
  13001.             console.log('Cinema thumbnails cliquables:', cinemaThumbs.length);
  13002.             // Clic sur overlay pour fermer
  13003.             const overlay = slider.querySelector('.slider-overlay');
  13004.             if (overlay) {
  13005.               overlay.addEventListener('click', () => {
  13006.                 console.log('Clic overlay');
  13007.                 this.close();
  13008.               });
  13009.             }
  13010.             // Clavier
  13011.             this.keyboardHandler = this.handleKeyboard.bind(this);
  13012.             document.addEventListener('keydown', this.keyboardHandler);
  13013.             console.log('Événements clavier attachés');
  13014.             // Zoom sur les images
  13015.             this.attachZoomEvents(slider);
  13016.             console.log('Événements zoom attachés');
  13017.             console.log('Événements attachés avec succès');
  13018.           }
  13019.           close() {
  13020.             console.log('=== close appelée ===');
  13021.             const slider = document.querySelector('.universal-slider');
  13022.             if (slider) {
  13023.               console.log('Fermeture du slider');
  13024.               // Animation de fermeture
  13025.               slider.style.opacity = '0';
  13026.               
  13027.               setTimeout(() => {
  13028.                 slider.remove();
  13029.                 console.log('Slider supprimé du DOM');
  13030.                 
  13031.                 // Nettoyer les événements
  13032.                 if (this.keyboardHandler) {
  13033.                   document.removeEventListener('keydown', this.keyboardHandler);
  13034.                   this.keyboardHandler = null;
  13035.                 }
  13036.                 
  13037.                 this.isOpen = false;
  13038.               }, 300);
  13039.             }
  13040.           }
  13041.           nextSlide() {
  13042.             if (this.currentIndex < this.images.length - 1) {
  13043.               this.showSlide(this.currentIndex + 1);
  13044.             }
  13045.           }
  13046.           prevSlide() {
  13047.             if (this.currentIndex > 0) {
  13048.               this.showSlide(this.currentIndex - 1);
  13049.             }
  13050.           }
  13051.           handleKeyboard(e) {
  13052.             if (!this.isOpen) return;
  13053.             
  13054.             switch (e.key) {
  13055.               case 'Escape':
  13056.                 this.close();
  13057.                 break;
  13058.               case 'ArrowLeft':
  13059.                 this.prevSlide();
  13060.                 break;
  13061.               case 'ArrowRight':
  13062.                 this.nextSlide();
  13063.                 break;
  13064.             }
  13065.           }
  13066.           attachZoomEvents(slider) {
  13067.             // Fonctionnalité de zoom à 5 niveaux pour les images
  13068.             const images = slider.querySelectorAll('.slide img');
  13069.             images.forEach(img => {
  13070.               let zoomLevel = 1; // 1x, 1.5x, 2x, 3x, 4x, 5x
  13071.               let isDragging = false;
  13072.               let startX = 0;
  13073.               let startY = 0;
  13074.               let translateX = 0;
  13075.               let translateY = 0;
  13076.               // Clic simple pour zoom progressif (5 niveaux)
  13077.               img.addEventListener('click', (e) => {
  13078.                 e.preventDefault();
  13079.                 e.stopPropagation();
  13080.                 
  13081.                 // Cycle à travers 5 niveaux de zoom
  13082.                 switch(zoomLevel) {
  13083.                   case 1: zoomLevel = 1.5; break;  // 1x → 1.5x
  13084.                   case 1.5: zoomLevel = 2; break;  // 1.5x → 2x
  13085.                   case 2: zoomLevel = 3; break;    // 2x → 3x
  13086.                   case 3: zoomLevel = 4; break;    // 3x → 4x
  13087.                   case 4: zoomLevel = 5; break;    // 4x → 5x
  13088.                   case 5: 
  13089.                     zoomLevel = 1;                 // 5x → 1x (reset)
  13090.                     translateX = 0;
  13091.                     translateY = 0;
  13092.                     break;
  13093.                 }
  13094.                 console.log('Zoom niveau:', zoomLevel);
  13095.                 img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  13096.                 
  13097.                 // Curseur selon le niveau
  13098.                 if (zoomLevel === 1) {
  13099.                   img.style.cursor = 'zoom-in';
  13100.                   img.removeAttribute('data-zoomed');
  13101.                 } else if (zoomLevel === 5) {
  13102.                   img.style.cursor = 'zoom-out';
  13103.                   img.setAttribute('data-zoomed', zoomLevel);
  13104.                 } else {
  13105.                   img.style.cursor = 'zoom-in';
  13106.                   img.setAttribute('data-zoomed', zoomLevel);
  13107.                 }
  13108.               });
  13109.               // Drag pour déplacer l'image zoomée
  13110.               img.addEventListener('mousedown', (e) => {
  13111.                 if (zoomLevel > 1) {
  13112.                   isDragging = true;
  13113.                   startX = e.clientX - translateX;
  13114.                   startY = e.clientY - translateY;
  13115.                   img.style.cursor = 'grabbing';
  13116.                   e.preventDefault();
  13117.                   e.stopPropagation();
  13118.                 }
  13119.               });
  13120.               // Mousemove global pour le drag
  13121.               const handleMouseMove = (e) => {
  13122.                 if (isDragging && zoomLevel > 1) {
  13123.                   translateX = e.clientX - startX;
  13124.                   translateY = e.clientY - startY;
  13125.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  13126.                 }
  13127.               };
  13128.               // Mouseup global pour arrêter le drag
  13129.               const handleMouseUp = () => {
  13130.                 if (isDragging) {
  13131.                   isDragging = false;
  13132.                   if (zoomLevel === 1) {
  13133.                     img.style.cursor = 'zoom-in';
  13134.                   } else if (zoomLevel === 5) {
  13135.                     img.style.cursor = 'zoom-out';
  13136.                   } else {
  13137.                     img.style.cursor = 'zoom-in';
  13138.                   }
  13139.                 }
  13140.               };
  13141.               document.addEventListener('mousemove', handleMouseMove);
  13142.               document.addEventListener('mouseup', handleMouseUp);
  13143.               // Touch support pour mobile
  13144.               img.addEventListener('touchstart', (e) => {
  13145.                 if (zoomLevel > 1 && e.touches.length === 1) {
  13146.                   isDragging = true;
  13147.                   const touch = e.touches[0];
  13148.                   startX = touch.clientX - translateX;
  13149.                   startY = touch.clientY - translateY;
  13150.                   e.preventDefault();
  13151.                 }
  13152.               });
  13153.               img.addEventListener('touchmove', (e) => {
  13154.                 if (isDragging && zoomLevel > 1 && e.touches.length === 1) {
  13155.                   const touch = e.touches[0];
  13156.                   translateX = touch.clientX - startX;
  13157.                   translateY = touch.clientY - startY;
  13158.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  13159.                   e.preventDefault();
  13160.                 }
  13161.               });
  13162.               img.addEventListener('touchend', () => {
  13163.                 isDragging = false;
  13164.               });
  13165.               // Initialiser le curseur
  13166.               img.style.cursor = 'zoom-in';
  13167.             });
  13168.           }
  13169.         }
  13170.         // ⚡ OPTIMISATION MAJEURE: Sliders lazy (créés seulement quand utilisés)
  13171.         let favoritesSlider = null;
  13172.         let universalSlider = null;
  13173.         
  13174.         // Fonctions pour créer les sliders à la demande
  13175.         function getFavoritesSlider() {
  13176.           if (!favoritesSlider) {
  13177.             favoritesSlider = new FavoritesSlider();
  13178.           }
  13179.           return favoritesSlider;
  13180.         }
  13181.         
  13182.         function getUniversalSlider() {
  13183.           if (!universalSlider) {
  13184.             universalSlider = new UniversalImageSlider();
  13185.           }
  13186.           return universalSlider;
  13187.         }
  13188.         // Fonction pour voir un favori avec le slider plein écran
  13189.         function viewFavorite(id) {
  13190.           console.log('Ouverture du slider pour favori:', id);
  13191.           // ⚡ OPTIMISÉ: Utiliser le slider lazy
  13192.           const slider = getUniversalSlider();
  13193.           if (slider && slider.openFromFavorites) {
  13194.             slider.openFromFavorites(id);
  13195.           } else {
  13196.             console.error('Erreur slider favoris');
  13197.           }
  13198.         }
  13199.         // Fonction pour voir une image depuis la galerie normale
  13200.         function viewImage(imageId, clickedElement) {
  13201.           console.log('=== viewImage appelée ===');
  13202.           console.log('imageId:', imageId);
  13203.           console.log('clickedElement:', clickedElement);
  13204.           
  13205.           // Trouver le container du jour - peut être plusieurs niveaux au-dessus
  13206.           let dayContainer = clickedElement;
  13207.           
  13208.           // Remonter jusqu'à trouver un container approprié
  13209.           while (dayContainer && dayContainer !== document.body) {
  13210.             console.log('Checking element:', dayContainer.tagName, dayContainer.className, dayContainer.id);
  13211.             if (dayContainer && dayContainer.classList && (
  13212.                 dayContainer.classList.contains('dynamic-card') || 
  13213.                 dayContainer.classList.contains('collapse') ||
  13214.                 dayContainer.id && dayContainer.id.startsWith('demP')
  13215.             )) {
  13216.               break;
  13217.             }
  13218.             dayContainer = dayContainer.parentElement;
  13219.           }
  13220.           
  13221.           // ⚡ OPTIMISÉ: Logs réduits pour performance
  13222.           
  13223.           // ⚡ OPTIMISÉ: Utiliser le slider lazy
  13224.           const slider = getUniversalSlider();
  13225.           if (slider && slider.openFromGallery) {
  13226.             slider.openFromGallery(imageId, dayContainer);
  13227.           } else {
  13228.             console.error('Erreur slider galerie');
  13229.           }
  13230.         }
  13231.         // ⚡ OPTIMISÉ: Fonctions globales avec sliders lazy
  13232.         window.viewImage = viewImage;
  13233.         window.viewFavorite = viewFavorite;
  13234.         window.getUniversalSlider = getUniversalSlider; // Fonction lazy au lieu de l'instance
  13235.         // Variables globales pour éviter les ReferenceError
  13236.         if (typeof favoriteCount === 'undefined') {
  13237.           window.favoriteCount = 0;
  13238.         }
  13239.         if (typeof favButton === 'undefined') {
  13240.           window.favButton = null;
  13241.         }
  13242.         if (typeof favoriteButton === 'undefined') {
  13243.           window.favoriteButton = null;
  13244.         }
  13245.         if (typeof purchaseAlertTimeout === 'undefined') {
  13246.           window.purchaseAlertTimeout = null;
  13247.         }
  13248.         
  13249.         // Définir favoriteCount globalement pour éviter les ReferenceError
  13250.         let favoriteCount = window.favoriteCount || 0;
  13251.         // Fonction de sécurité pour vérifier les éléments DOM
  13252.         function safeAddEventListener(selector, event, callback) {
  13253.           const element = document.querySelector(selector);
  13254.           if (element) {
  13255.             element.addEventListener(event, callback);
  13256.           } else {
  13257.             console.warn(`Élément non trouvé: \${selector}`);
  13258.           }
  13259.         }
  13260.         // Fonction utilitaire pour manipuler classList de manière sécurisée
  13261.         function safeClassList(element, action, ...classes) {
  13262.           if (!element || !element.classList) {
  13263.             console.warn('Élément ou classList invalide:', element);
  13264.             return false;
  13265.           }
  13266.           
  13267.           try {
  13268.             switch(action) {
  13269.               case 'add':
  13270.                 element.classList.add(...classes);
  13271.                 break;
  13272.               case 'remove':
  13273.                 element.classList.remove(...classes);
  13274.                 break;
  13275.               case 'toggle':
  13276.                 return element.classList.toggle(classes[0], classes[1]);
  13277.               case 'contains':
  13278.                 return element.classList.contains(classes[0]);
  13279.               default:
  13280.                 console.warn('Action classList inconnue:', action);
  13281.                 return false;
  13282.             }
  13283.             return true;
  13284.           } catch (error) {
  13285.             console.warn('Erreur lors de la manipulation de classList:', error);
  13286.             return false;
  13287.           }
  13288.         }
  13289.         // Rendre la fonction utilitaire globale
  13290.         window.safeClassList = safeClassList;
  13291.         // Fonction pour sécuriser automatiquement tous les accès à classList
  13292.         function secureClassListAccess() {
  13293.           // Intercepter les erreurs classList globalement
  13294.           window.addEventListener('error', function(e) {
  13295.             if (e.message && (e.message.includes('classList') || e.message.includes('Cannot read properties of null'))) {
  13296.               console.warn('Erreur DOM interceptée et corrigée:', e.message, 'Ligne:', e.lineno, 'Fichier:', e.filename);
  13297.               e.preventDefault(); // Empêcher l'erreur de se propager
  13298.               return true;
  13299.             }
  13300.           });
  13301.           
  13302.           // Intercepter les erreurs non catchées
  13303.           window.addEventListener('unhandledrejection', function(e) {
  13304.             if (e.reason && e.reason.message && e.reason.message.includes('classList')) {
  13305.               console.warn('Promise rejection classList interceptée:', e.reason.message);
  13306.               e.preventDefault();
  13307.               return true;
  13308.             }
  13309.           });
  13310.           
  13311.           console.log('Système de sécurisation DOM/classList activé');
  13312.         }
  13313.         // Activer la sécurisation
  13314.         secureClassListAccess();
  13315.         // Fonction de diagnostic pour vérifier l'affichage du slider
  13316.         function diagnoseSliderDisplay(sliderId) {
  13317.           const slider = document.querySelector(sliderId);
  13318.           if (!slider) {
  13319.             console.error('Diagnostic: Slider non trouvé -', sliderId);
  13320.             return false;
  13321.           }
  13322.           
  13323.           const styles = window.getComputedStyle(slider);
  13324.           const rect = slider.getBoundingClientRect();
  13325.           
  13326.           console.log('=== DIAGNOSTIC SLIDER ===', sliderId);
  13327.           console.log('Élément présent:', !!slider);
  13328.           console.log('Styles calculés:', {
  13329.             display: styles.display,
  13330.             opacity: styles.opacity,
  13331.             visibility: styles.visibility,
  13332.             zIndex: styles.zIndex,
  13333.             position: styles.position
  13334.           });
  13335.           console.log('Position/Taille:', rect);
  13336.           console.log('Dans le viewport:', rect.width > 0 && rect.height > 0);
  13337.           console.log('Parent:', slider.parentElement?.tagName);
  13338.           
  13339.           // Vérifier les règles CSS qui pourraient masquer le slider
  13340.           const hiddenReasons = [];
  13341.           if (styles.display === 'none') hiddenReasons.push('display: none');
  13342.           if (styles.opacity === '0') hiddenReasons.push('opacity: 0');
  13343.           if (styles.visibility === 'hidden') hiddenReasons.push('visibility: hidden');
  13344.           if (parseInt(styles.zIndex) < 0) hiddenReasons.push('z-index négatif');
  13345.           
  13346.           if (hiddenReasons.length > 0) {
  13347.             console.warn('Raisons du masquage:', hiddenReasons);
  13348.             
  13349.             // Forcer l'affichage
  13350.             console.log('Forçage de l\\'affichage...');
  13351.             slider.style.display = 'flex';
  13352.             slider.style.opacity = '1';
  13353.             slider.style.visibility = 'visible';
  13354.             slider.style.zIndex = '9999';
  13355.             slider.style.position = 'fixed';
  13356.             slider.style.top = '0';
  13357.             slider.style.left = '0';
  13358.             slider.style.width = '100%';
  13359.             slider.style.height = '100%';
  13360.             
  13361.             console.log('Slider forcé visible');
  13362.           } else {
  13363.             console.log('✅ Slider devrait être visible');
  13364.           }
  13365.           
  13366.           return true;
  13367.         }
  13368.         // Rendre la fonction globale
  13369.         window.diagnoseSliderDisplay = diagnoseSliderDisplay;
  13370.         // Fonction de sécurité pour checkFavorites
  13371.         function checkFavorites() {
  13372.           try {
  13373.             let count = 0;
  13374.             if (typeof getFavoriteItems === 'function') {
  13375.               count = getFavoriteItems().length;
  13376.             } else {
  13377.               // Fallback : compter depuis le DOM
  13378.               const giftCount = document.getElementById('giftCount');
  13379.               if (giftCount && giftCount.textContent) {
  13380.                 count = parseInt(giftCount.textContent.trim()) || 0;
  13381.               }
  13382.             }
  13383.             
  13384.             // Mettre à jour les variables globales
  13385.             window.favoriteCount = count;
  13386.             favoriteCount = count;
  13387.             
  13388.             console.log('Favoris vérifiés:', count);
  13389.             return count;
  13390.           } catch (error) {
  13391.             console.warn('Erreur lors de la vérification des favoris:', error);
  13392.             return 0;
  13393.           }
  13394.         }
  13395.         // Rendre checkFavorites globale si elle n'existe pas
  13396.         if (typeof window.checkFavorites === 'undefined') {
  13397.           window.checkFavorites = checkFavorites;
  13398.         }
  13399.         // Initialisation sécurisée après chargement du DOM
  13400.         document.addEventListener('DOMContentLoaded', function() {
  13401.           console.log('=== DOM chargé, initialisation des sliders ===');
  13402.           console.log('viewImage disponible:', typeof window.viewImage);
  13403.           console.log('viewFavorite disponible:', typeof window.viewFavorite);
  13404.           console.log('universalSlider disponible:', typeof window.universalSlider);
  13405.           
  13406.           // Vérifier que les éléments critiques existent
  13407.           const criticalElements = [
  13408.             'filtre_photos_voir',
  13409.             // Ajoutez d'autres IDs critiques ici si nécessaire
  13410.           ];
  13411.           
  13412.           criticalElements.forEach(id => {
  13413.             const element = document.getElementById(id);
  13414.             if (element) {
  13415.               console.log(`✓ Élément trouvé: \${id}`);
  13416.             } else {
  13417.               console.warn(`⚠ Élément manquant: \${id}`);
  13418.             }
  13419.           });
  13420.           
  13421.           // Initialiser checkFavorites si la fonction existe
  13422.           if (typeof window.checkFavorites === 'function') {
  13423.             window.checkFavorites();
  13424.           }
  13425.         });
  13426.       
  13427.         // Fonction pour obtenir l'image d'un produit selon son type
  13428.         function getProductImage(productId) {
  13429.           const productImages = {
  13430.             'album': '/images/produit/Album5sur5-3.jpg',
  13431.             'digital': '/images/produit/photoNumerique.jpg', 
  13432.             'prints': '/images/produit/PochettePhoto5sur5-2.jpg',
  13433.             'calendrier': '/images/produit/Calendrier5sur5-1.jpg',
  13434.             'livre': '/images/produit/LivreSouvenir5sur5-1.jpg',
  13435.             'coffret': '/images/produit/CoffretCadeau5sur5-2.jpg',
  13436.             'retro': '/images/produit/PochetteRetro5sur5-1.jpg'
  13437.           };
  13438.           
  13439.           return productImages[productId] || '/images/produit/albumm.PNG';
  13440.         }
  13441.         
  13442.         // Fonction pour générer les suggestions de produits (synchronisées avec ecommerce-sidebar)
  13443.         // 🗑️ SUPPRIMÉ : generateProductSuggestions() - remplacé par le sidebar e-commerce
  13444.         // Le sidebar e-commerce (sidebar-ecommerce-pro.js) gère maintenant tous les produits
  13445.         // de manière centralisée et dynamique
  13446.         // Fonction pour obtenir le nombre actuel de favoris
  13447.         function getCurrentFavoriteCount() {
  13448.           return getFavoriteItems().length;
  13449.         }
  13450.         // 🎯 SUPPRIMÉ: Fonction dupliquée - la vraie est dans parent-toasts.js
  13451.         // Cette fonction était en conflit avec updateProductSuggestions() de parent-toasts.js
  13452.         // qui gère déjà les mises à jour dynamiques avec dates et contexte
  13453.         
  13454.         // Fonction legacy pour compatibilité (redirige vers parent-toasts.js)
  13455.         window.updateProductSuggestionsLive = function(favoriteCount) {
  13456.           console.log('[Legacy] updateProductSuggestionsLive appelé, redirection vers parent-toasts.js');
  13457.           // La vraie logique est dans parent-toasts.js > updateProductSuggestions()
  13458.           // qui est appelée automatiquement par le MutationObserver
  13459.         }
  13460.         // Gestion du localStorage pour l'indicateur \"nouveau contenu\"
  13461.         const lastVisitKey = 'lastVisitISO';
  13462.         const currentVisit = new Date().toISOString();
  13463.         
  13464.         // Sauvegarder la visite actuelle
  13465.         localStorage.setItem(lastVisitKey, currentVisit);
  13466.         
  13467.         // Vérifier et marquer les jours avec nouveau contenu
  13468.         const dateCards = document.querySelectorAll('.date-card.modern-card');
  13469.         dateCards.forEach(card => {
  13470.           // Ici vous devriez comparer avec updatedAt du backend
  13471.           // Pour l'instant, on simule avec un attribut data-updated
  13472.           const updatedAt = card.getAttribute('data-updated');
  13473.           if (updatedAt) {
  13474.             const lastVisit = localStorage.getItem(lastVisitKey);
  13475.             if (new Date(updatedAt) > new Date(lastVisit)) {
  13476.               if (card && card.classList) {
  13477.                 card.classList.add('has-new-content');
  13478.               }
  13479.               // Ajouter le badge \"nouveau\" si pas déjà présent
  13480.               if (!card.querySelector('.badge-new')) {
  13481.                 const badge = document.createElement('span');
  13482.                 badge.className = 'badge-new';
  13483.                 badge.setAttribute('aria-label', 'Nouveau contenu');
  13484.                 card.querySelector('.title-line').appendChild(badge);
  13485.               }
  13486.             }
  13487.           }
  13488.         });
  13489.         // Gestion des aria-label dynamiques pour les cartes de jours
  13490.         dateCards.forEach(card => {
  13491.           const dayText = card.querySelector('.day').textContent.trim();
  13492.           const dateText = card.querySelector('.full-date').textContent.trim();
  13493.           const photos = card.querySelector('.media-list-horizontal li:nth-child(1)')?.textContent.trim() || '0';
  13494.           const audios = card.querySelector('.media-list-horizontal li:nth-child(2)')?.textContent.trim() || '0';
  13495.           const videos = card.querySelector('.media-list-horizontal li:nth-child(3)')?.textContent.trim() || '0';
  13496.           
  13497.           const ariaLabel = `Contenu du \${dateText} : \${photos} photos, \${audios} audios, \${videos} vidéos`;
  13498.           card.setAttribute('aria-label', ariaLabel);
  13499.         });
  13500.       });
  13501.     </script>
  13502.     
  13503.     <!-- Make sure we're showing the right content by default if no valid content is marked 'show' -->
  13504.     {% if lastValidIndex > 0 %}
  13505.     <script>
  13506.       document.addEventListener('DOMContentLoaded', function() {
  13507.         // Check if no content is showing
  13508.         if (document.querySelectorAll('.container--gallery .collapse.show').length === 0) {
  13509.           // Show the content for the last valid date
  13510.           var lastValidContent = document.getElementById('demP{{ lastValidIndex }}');
  13511.           if (lastValidContent) {
  13512.             if (lastValidContent.classList) {
  13513.               lastValidContent.classList.add('show');
  13514.             }
  13515.             
  13516.             // Also mark the corresponding date card as active
  13517.             var dateCards = document.querySelectorAll('.date-card');
  13518.             if (dateCards.length >= {{ lastValidIndex }}) {
  13519.               dateCards.forEach(card => {
  13520.                 if (card && card.classList) {
  13521.                   card.classList.remove('active');
  13522.                 }
  13523.               });
  13524.               const targetCard = dateCards[{{ lastValidIndex - 1 }}];
  13525.               if (targetCard && targetCard.classList) {
  13526.                 targetCard.classList.add('active');
  13527.               }
  13528.             }
  13529.           }
  13530.         }
  13531.       });
  13532.     </script>
  13533.     {% endif %}
  13534.   </div>
  13535. </div>
  13536.   {% endblock %} {% block Javascript %}
  13537.   {{ parent() }}
  13538.   <script>// Gestion de la sidebar des favoris
  13539. document.addEventListener('DOMContentLoaded', function() {
  13540.     const sidebar = document.getElementById('favorites-sidebar');
  13541.     const openBtn = document.getElementById('openFavoritesSidebar');
  13542.     const closeBtn = document.querySelector('.favorites-close');
  13543.     const giftButton = document.querySelector('.gift-button');
  13544.     function openSidebar() {
  13545.         if (sidebar && sidebar.classList) {
  13546.           sidebar.classList.add('active');
  13547.           updateFavoritesSidebar();
  13548.         }
  13549.     }
  13550.     function closeSidebar() {
  13551.         if (sidebar && sidebar.classList) {
  13552.           sidebar.classList.remove('active');
  13553.         }
  13554.     }
  13555.     function updateFavoritesSidebar() {
  13556.         const grid = document.getElementById('favorites-grid');
  13557.         const counter = document.getElementById('favorites-counter');
  13558.         const emptyState = document.getElementById('favorites-empty-state');
  13559.         const progress = document.getElementById('favorites-progress');
  13560.         
  13561.         const mesFavCount = document.getElementById('mesFavCount');
  13562.         const count = mesFavCount ? getFavorisCount() : 0;
  13563.         counter.textContent = count;
  13564.         
  13565.         if (count === 0) {
  13566.             emptyState.style.display = 'flex';
  13567.             grid.style.display = 'none';
  13568.         } else {
  13569.             emptyState.style.display = 'none';
  13570.             grid.style.display = 'grid';
  13571.             const percentage = (count / 20) * 100;
  13572.             progress.style.width = `\${percentage}%`;
  13573.         }
  13574.     }
  13575.     if (openBtn) {
  13576.         openBtn.addEventListener('click', openSidebar);
  13577.     }
  13578.     if (favButton) {
  13579.         favButton.addEventListener('click', openSidebar);
  13580.     }
  13581.     if (closeBtn) {
  13582.         closeBtn.addEventListener('click', closeSidebar);
  13583.     }
  13584.     document.addEventListener('click', (e) => {
  13585.         if (sidebar && sidebar.classList && sidebar.classList.contains('active') && 
  13586.             !sidebar.contains(e.target) && 
  13587.             (!favButton || !favButton.contains(e.target)) && 
  13588.             (!openBtn || !openBtn.contains(e.target))) {
  13589.             closeSidebar();
  13590.         }
  13591.     });
  13592. });
  13593. // Modification des fonctions existantes
  13594. const originalAddFavoris = window.AddFavoris;
  13595. window.AddFavoris = function(\$id, \$idSejour, \$urlimg, \$description) {
  13596.     if (originalAddFavoris) {
  13597.         originalAddFavoris(\$id, \$idSejour, \$urlimg, \$description);
  13598.     }
  13599.     
  13600.   
  13601.     
  13602.     // Vérifier si la sidebar est ouverte - noter que nous vérifions la valeur CSS right: 0
  13603.     if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  13604.         // Recharger les favoris
  13605.         loadFavorites();
  13606.     }
  13607. };
  13608. const originalSupprimerFavoris = window.supprimerFavoris;
  13609. window.supprimerFavoris = function(\$id, \$idSejour) {
  13610.     if (originalSupprimerFavoris) {
  13611.         originalSupprimerFavoris(\$id, \$idSejour);
  13612.     }
  13613.     
  13614.     // Mettre à jour tous les compteurs de favoris
  13615.     updateAllFavoriteCounters();
  13616.     
  13617.     // Vérifier si la sidebar est ouverte
  13618.     if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  13619.         // Recharger les favoris
  13620.         loadFavorites();
  13621.     }
  13622. };
  13623. // Variables globales
  13624. let selectedFavorites = [];
  13625. let allFavorites = [];
  13626. // Fonction pour mettre à jour la sidebar
  13627. function loadFavorites() {
  13628.     \$(\"#favorites-grid\").html(\"<div style='text-align:center;padding:20px;'>Chargement...</div>\");
  13629.     
  13630.     \$.ajax({
  13631.         url: \"/Parent/mes-favoris\",
  13632.         type: \"GET\",
  13633.         dataType: \"json\",
  13634.         success: function(data) {
  13635.             \$(\"#favorites-grid\").empty();
  13636.             allFavorites = data.data || [];
  13637.             
  13638.             if (allFavorites.length > 0) {
  13639.                 \$(\"#favorites-empty-state\").hide();
  13640.                 
  13641.                 \$.each(allFavorites, function(i, fav) {
  13642.                     var isSelected = selectedFavorites.includes(fav.id);
  13643.                     
  13644.                     var item = \$(\"<div class='favorite-item' style='position:relative;border-radius:8px;overflow:hidden;aspect-ratio:1;cursor:pointer;'></div>\");
  13645.                     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\");
  13646.                     
  13647.                     // Overlay de sélection
  13648.                     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>\");
  13649.                     
  13650.                     // Icône de sélection
  13651.                     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>\");
  13652.                     if (isSelected) {
  13653.                         checkIcon.append(\"<i class='bi bi-check' style='color:white;font-size:16px;'></i>\");
  13654.                     }
  13655.                     
  13656.                     selectionOverlay.append(checkIcon);
  13657.                     
  13658.                     // Overlay d'action (bouton supprimer)
  13659.                     var actionOverlay = \$(\"<div class='action-overlay' style='position:absolute;top:5px;right:5px;opacity:0;transition:opacity 0.2s;'></div>\");
  13660.                   
  13661.                     actionOverlay.append(deleteBtn);
  13662.                     
  13663.                     // Ajouter les événements
  13664.                     item.hover(
  13665.                         function() { \$(this).find(\".action-overlay\").css(\"opacity\", \"1\"); },
  13666.                         function() { \$(this).find(\".action-overlay\").css(\"opacity\", \"0\"); }
  13667.                     );
  13668.                     
  13669.                     item.click(function() {
  13670.                         toggleSelection(fav.id, \$(this).find(\".selection-overlay > div\"));
  13671.                     });
  13672.                     
  13673.                     item.append(img).append(selectionOverlay).append(actionOverlay);
  13674.                     \$(\"#favorites-grid\").append(item);
  13675.                 });
  13676.                 
  13677.                 \$(\"#favorites-counter\").text(allFavorites.length);
  13678.                 
  13679.                 // Mettre à jour le compteur sur le bouton également
  13680.                 \$(\"#openFavoritesSidebar span\").text(allFavorites.length);
  13681.                 
  13682.                 // Mettre à jour l'interface produits
  13683.                 updateProductsView();
  13684.                 
  13685.             } else {
  13686.                 \$(\"#favorites-empty-state\").show();
  13687.                 \$(\"#favorites-counter\").text(\"0\");
  13688.                 \$(\"#openFavoritesSidebar span\").text(\"0\");
  13689.                 \$(\"#selection-count\").text(\"0\");
  13690.                 updateProductsView();
  13691.             }
  13692.         },
  13693.         error: function() {
  13694.             \$(\"#favorites-grid\").html(\"<div style='color:red;text-align:center;padding:20px;'>Erreur de chargement</div>\");
  13695.         }
  13696.     });
  13697. }
  13698. // Fonction pour supprimer un favori
  13699. function removeFavorite(id) {
  13700.     \$.ajax({
  13701.         url: \"/Parent/remove-favorite/\" + id,
  13702.         type: \"POST\",
  13703.         success: function() {
  13704.             // Retirer de la sélection si présent
  13705.             selectedFavorites = selectedFavorites.filter(favId => favId != id);
  13706.             
  13707.             // Mettre à jour le compteur de sélection
  13708.             \$(\"#selection-count\").text(selectedFavorites.length);
  13709.             
  13710.             // Recharger les favoris
  13711.             loadFavorites();
  13712.             
  13713.             // Mettre à jour tous les compteurs de favoris
  13714.             updateAllFavoriteCounters();
  13715.             
  13716.             // Mettre à jour l'interface produits
  13717.             updateProductsView();
  13718.         },
  13719.         error: function() {
  13720.             alert(\"Erreur lors de la suppression du favori\");
  13721.         }
  13722.     });
  13723. }
  13724. // Fonction pour basculer la sélection d'une photo
  13725. function toggleSelection(id, checkElement) {
  13726.     const index = selectedFavorites.indexOf(id);
  13727.     
  13728.     if (index === -1) {
  13729.         // Ajouter à la sélection
  13730.         selectedFavorites.push(id);
  13731.         checkElement.css(\"background\", \"#F56040\");
  13732.         checkElement.html(\"<i class='bi bi-check' style='color:white;font-size:16px;'></i>\");
  13733.     } else {
  13734.         // Retirer de la sélection
  13735.         selectedFavorites.splice(index, 1);
  13736.         checkElement.css(\"background\", \"transparent\");
  13737.         checkElement.html(\"\");
  13738.     }
  13739.     
  13740.     // Mettre à jour le compteur
  13741.     \$(\"#selection-count\").text(selectedFavorites.length);
  13742.     
  13743.     // Mettre à jour l'interface produits
  13744.     updateProductsView();
  13745. }
  13746. // Fonction pour mettre à jour la vue des produits
  13747. function updateProductsView() {
  13748.     const current = selectedFavorites.length;
  13749.     \$(\"#product-photo-count\").text(current);
  13750.     
  13751.     let remainingForAlbum = Math.max(0, 20 - current);
  13752.     let remainingForPochette = Math.max(0, 12 - current);
  13753.     let remainingForPack = Math.max(0, 12 - current);
  13754.     const progressBar = (count, total, color) => `
  13755.         <div style=\"margin: 5px 0;\">
  13756.             <div style=\"background-color: #e9ecef; border-radius: 5px; overflow: hidden; height: 8px;\">
  13757.                 <div style=\"width: \${(count / total) * 100}%; background-color: \${color}; height: 100%;\"></div>
  13758.             </div>
  13759.             <small style=\"font-size: 12px;\">\${count}/\${total} photos</small>
  13760.         </div>
  13761.     `;
  13762.     // Liste des produits
  13763.     const products = [
  13764.         {
  13765.             name: \"Pack numérique (20 photos)\",
  13766.             required: 20,
  13767.             remaining: Math.max(0, 20 - current),
  13768.             image: \"/images/produit/photoNumerique.jpg\",
  13769.             color: \"#4caf50\",
  13770.             link: \"{{ path('PackPhotosNumerique_Favoris', {'nbr':20}) }}\",
  13771.         },
  13772.        +
  13773.         {
  13774.             name: \"Pochette photo (12 photos)\",
  13775.             required: 12,
  13776.             remaining: Math.max(0, 12 - current),
  13777.             image: \"/images/produit/PochettePhoto5sur5-2.jpg\",
  13778.             color: \"#2196f3\",
  13779.             link: \"{{ path('AjoutPochettePhotos_Favoris', {'nbr': 12}) }}\",
  13780.         },
  13781.     ].sort((a, b) => a.remaining - b.remaining);
  13782.     const productList = products
  13783.         .map((product) => {
  13784.             const count = current;
  13785.             const total = product.required;
  13786.             const remaining = product.remaining;
  13787.             return `
  13788.                 <li style=\"margin-bottom: 20px;\">
  13789.                     <div style=\"display: flex; align-items: center; gap: 10px;\">
  13790.                         <img src=\"\${product.image}\" alt=\"\${product.name}\" style=\"width: 70px; height: 70px; border-radius: 5px; object-fit: cover;\" />
  13791.                         <div style=\"flex: 1;\">
  13792.                             <strong style=\"font-size: 14px;\">\${product.name}</strong>
  13793.                             \${progressBar(count, total, product.color)}
  13794.                             \${
  13795.                                 `<small style=\"color: \${product.color}; font-size: 12px;\">
  13796.                                     Encore \${remaining} photos pour compléter \${product.name.toLowerCase()}
  13797.                                 </small>
  13798.                                 <button
  13799.                                     style=\"
  13800.                                         margin-top: 5px;
  13801.                                         padding: 6px 12px;
  13802.                                         background-color: \${product.color};
  13803.                                         color: white;
  13804.                                         border: none;
  13805.                                         border-radius: 5px;
  13806.                                         font-size: 13px;
  13807.                                         cursor: pointer;
  13808.                                     \"
  13809.                                     onclick=\"window.location.href='\${product.link}'\"
  13810.                                 >
  13811.                                     Commander
  13812.                                 </button>`
  13813.                             }
  13814.                         </div>
  13815.                     </div>
  13816.                 </li>
  13817.             `;
  13818.         })
  13819.         .join(\"\");
  13820.     const boutiqueButton = `
  13821.         <li style=\"margin-top: 25px; text-align: center;\">
  13822.             <button
  13823.                 style=\"
  13824.                     padding: 8px 15px;
  13825.                     background-color: #F56040;
  13826.                     color: white;
  13827.                     border: none;
  13828.                     border-radius: 5px;
  13829.                     font-size: 14px;
  13830.                     width: 170px;
  13831.                     height: 40px;
  13832.                     cursor: pointer;
  13833.                 \"
  13834.                 onclick=\"window.location.href='{{ path('boutique5sur5') }}'\"
  13835.             >
  13836.                 Voir toute la boutique
  13837.             </button>
  13838.         </li>
  13839.     `;
  13840.     \$(\"#product-list\").html(productList + boutiqueButton);
  13841. }
  13842. // Modifications au script existant
  13843. \$(document).ready(function() {
  13844.     // Fonctions pour ouvrir/fermer la sidebar
  13845.     \$(\"#openFavoritesSidebar\").click(function() {
  13846.         \$(\"#favorites-sidebar\").css(\"right\", \"0\");
  13847.         loadFavorites();
  13848.     });
  13849.     
  13850.     \$(\"#close-favorites-btn\").click(function() {
  13851.         closeFavoritesSidebar();
  13852.     });
  13853.     
  13854.     // Fonction pour fermer la sidebar
  13855.     window.closeFavoritesSidebar = function() {
  13856.         \$(\"#favorites-sidebar\").css(\"right\", \"-500px\");
  13857.     };
  13858.     
  13859.     // Tout sélectionner / Tout désélectionner
  13860.     \$(\"#select-all-btn\").click(function() {
  13861.         if (selectedFavorites.length === allFavorites.length) {
  13862.             // Tout désélectionner
  13863.             selectedFavorites = [];
  13864.             \$(\".selection-overlay > div\").css(\"background\", \"transparent\").html(\"\");
  13865.             \$(this).text(\"Tout sélectionner\");
  13866.         } else {
  13867.             // Tout sélectionner
  13868.             selectedFavorites = allFavorites.map(fav => fav.id);
  13869.             \$(\".selection-overlay > div\").css(\"background\", \"#F56040\").html(\"<i class='bi bi-check' style='color:white;font-size:16px;'></i>\");
  13870.             \$(this).text(\"Tout désélectionner\");
  13871.         }
  13872.         
  13873.         // Mettre à jour le compteur
  13874.         \$(\"#selection-count\").text(selectedFavorites.length);
  13875.         
  13876.         // Mettre à jour l'interface produits
  13877.         updateProductsView();
  13878.     });
  13879.     
  13880.     // Gestion des onglets
  13881.     \$(\".sidebar-tab\").click(function() {
  13882.         \$(\".sidebar-tab\").removeClass(\"active\").css({
  13883.             \"color\": \"#666\",
  13884.             \"border-bottom\": \"none\"
  13885.         });
  13886.         \$(this).addClass(\"active\").css({
  13887.             \"color\": \"#F56040\",
  13888.             \"border-bottom\": \"2px solid #F56040\"
  13889.         });
  13890.         
  13891.         const tabId = \$(this).attr(\"id\");
  13892.         \$(\".tab-content\").hide();
  13893.         
  13894.         if (tabId === \"tab-photos\") {
  13895.             \$(\"#photos-content\").show();
  13896.         } else if (tabId === \"tab-products\") {
  13897.             \$(\"#products-content\").show();
  13898.         }
  13899.     });
  13900.     
  13901.     // Modifier les fonctions existantes pour intercepter l'ajout/suppression de favoris
  13902.     const originalAddFavoris = window.AddFavoris;
  13903.     window.AddFavoris = function(\$id, \$idSejour, \$urlimg, \$description) {
  13904.         if (originalAddFavoris) {
  13905.             originalAddFavoris(\$id, \$idSejour, \$urlimg, \$description);
  13906.         }
  13907.         
  13908.         // Mettre à jour tous les compteurs de favoris
  13909.         updateAllFavoriteCounters();
  13910.         
  13911.         // Recharger les favoris si la sidebar est ouverte
  13912.         if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  13913.             loadFavorites();
  13914.         }
  13915.     };
  13916.     const originalSupprimerFavoris = window.supprimerFavoris;
  13917.     window.supprimerFavoris = function(\$id, \$idSejour) {
  13918.         if (originalSupprimerFavoris) {
  13919.             originalSupprimerFavoris(\$id, \$idSejour);
  13920.         }
  13921.         
  13922.         // Mettre à jour tous les compteurs de favoris
  13923.         updateAllFavoriteCounters();
  13924.         
  13925.         // Recharger les favoris si la sidebar est ouverte
  13926.         if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  13927.             // Retirer de la sélection si présent
  13928.             selectedFavorites = selectedFavorites.filter(favId => favId != \$id);
  13929.             loadFavorites();
  13930.         }
  13931.     };
  13932.     
  13933.     // Fermer en cliquant en dehors
  13934.     \$(document).click(function(event) {
  13935.         if (!\$(event.target).closest(\"#favorites-sidebar\").length && 
  13936.             !\$(event.target).closest(\"#openFavoritesSidebar\").length && 
  13937.             \$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  13938.             closeFavoritesSidebar();
  13939.         }
  13940.     });
  13941. });
  13942. // Initialisation de la sidebar
  13943. \$(document).ready(function() {
  13944.     // Fonctions pour ouvrir/fermer la sidebar
  13945.     \$(\"#openFavoritesSidebar\").click(function() {
  13946.         \$(\"#favorites-sidebar\").css(\"right\", \"0\");
  13947.         loadFavorites();
  13948.     });
  13949.     
  13950.     \$(\"#close-favorites-btn\").click(function() {
  13951.         \$(\"#favorites-sidebar\").css(\"right\", \"-500px\");
  13952.     });
  13953.     
  13954.     // Fermer en cliquant en dehors
  13955.     \$(document).click(function(event) {
  13956.         if (!\$(event.target).closest(\"#favorites-sidebar\").length && 
  13957.             !\$(event.target).closest(\"#openFavoritesSidebar\").length && 
  13958.             \$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  13959.             \$(\"#favorites-sidebar\").css(\"right\", \"-500px\");
  13960.         }
  13961.     });
  13962. });
  13963.   </script>
  13964.   <script src=\"{{ asset('js/splide.min.js') }}\" defer></script>
  13965.    
  13966. <script>
  13967.   document.addEventListener('DOMContentLoaded', function () {
  13968.     const openBtn = document.getElementById('openFavoritesSidebar');
  13969.     const sidebar = document.getElementById('favorites-sidebar');
  13970.     const closeBtn = document.getElementById('favorites-close');
  13971.     if (openBtn && sidebar) {
  13972.       openBtn.addEventListener('click', () => {
  13973.         if (sidebar && sidebar.classList) {
  13974.           sidebar.classList.add('active');
  13975.         }
  13976.       });
  13977.     }
  13978.     if (closeBtn && sidebar) {
  13979.       closeBtn.addEventListener('click', () => {
  13980.         if (sidebar && sidebar.classList) {
  13981.           sidebar.classList.remove('active');
  13982.         }
  13983.       });
  13984.     }
  13985.   });
  13986. </script>
  13987.  
  13988. <script>
  13989. document.addEventListener('DOMContentLoaded', function() {
  13990.   const filterBadges = document.querySelectorAll('.filter-badge');
  13991.   filterBadges.forEach(badge => {
  13992.     badge.addEventListener('click', function() {
  13993.       // Désactiver tous les badges
  13994.       filterBadges.forEach(b => {
  13995.         if (b && b.classList) {
  13996.           b.classList.remove('active');
  13997.         }
  13998.       });
  13999.       // Activer le badge cliqué
  14000.       if (this && this.classList) {
  14001.         this.classList.add('active');
  14002.       }
  14003.     });
  14004.   });
  14005. });
  14006. </script>
  14007.   <script
  14008.     type=\"text/javascript\"
  14009.     src=\"{{ asset('Accueil/js/jquery.magnific-popup.min.js') }}\"
  14010.   ></script>
  14011.   <script>
  14012. document.addEventListener('DOMContentLoaded', function () {
  14013.   const prevButtons = document.querySelectorAll('.btn-prev-day');
  14014.   const nextButtons = document.querySelectorAll('.btn-next-day');
  14015.   const dateCards = document.querySelectorAll('.date-card.modern-card');
  14016.   const collapseSections = document.querySelectorAll('.collapse');
  14017.   // 🎯 MEDIA TOOLBAR CAPSULE - État global et logique (Senior UX)
  14018.   (() => {
  14019.     // État global de filtre
  14020.     const MediaFilter = { current: 'all' };
  14021.     // Compteurs dynamiques
  14022.     const counters = { photo: 0, audio: 0, video: 0, fav: 0 };
  14023.     
  14024.     const updateCounts = () => {
  14025.       // Compter les médias dans le DOM
  14026.       counters.photo = document.querySelectorAll('.photo-item, [data-media-type=\"photo\"]').length;
  14027.       counters.video = document.querySelectorAll('[data-media-type=\"video\"]').length;
  14028.       counters.audio = document.querySelectorAll('.audio-message-item[data-type=\"audio\"]').length;
  14029.       // NE PAS recalculer seulement les favoris - ils utilisent {{ nblikes }}
  14030.       
  14031.       // Mettre à jour l'affichage (sauf favoris)
  14032.       Object.entries(counters).forEach(([k, v]) => {
  14033.         if (k !== 'fav') { // Garder seulement le compteur favoris intact
  14034.           document.querySelectorAll(`.mtb-count[data-bind=\"\${k}\"]`).forEach(el => el.textContent = v);
  14035.         }
  14036.       });
  14037.     };
  14038.     // Simple fonction pour le filtre actuel
  14039.     function setActive(filter) {
  14040.       MediaFilter.current = filter;
  14041.       
  14042.       // Exception : ne pas ajouter de classe active au bouton photos
  14043.       if (filter === 'photos') {
  14044.         const photosBtn = document.querySelector('.mtb-btn[data-filter=\"photos\"]');
  14045.         if (photosBtn) {
  14046.           photosBtn.classList.remove('active', 'is-active');
  14047.         }
  14048.       }
  14049.     }
  14050.     // Fonction simplifiée qui mappe et appelle filterContent
  14051.     function applyFilter(filter) {
  14052.       // Mapper les filtres de la capsule vers les filtres existants si nécessaire
  14053.       const filterMap = {
  14054.         'all': 'toutVoir',
  14055.         'photos': 'photos', 
  14056.         'audio': 'audio',
  14057.         'videos': 'videos',
  14058.         'favoris': 'favoris'
  14059.       };
  14060.       
  14061.       const mappedFilter = filterMap[filter] || filter;
  14062.       
  14063.       // Pour le filtre \"all\", s'assurer que la vue des jours est restaurée
  14064.       if (filter === 'all') {
  14065.         const containerGallery = document.querySelector('.container--gallery');
  14066.         if (containerGallery) {
  14067.           containerGallery.style.display = 'block';
  14068.         }
  14069.       }
  14070.       
  14071.       if (typeof window.filterContent === 'function') {
  14072.         window.filterContent(mappedFilter);
  14073.       } else {
  14074.         console.error('window.filterContent n\\'est pas disponible');
  14075.       }
  14076.     }
  14077.     // Click handlers - exactement la même logique que stat-pill
  14078.     document.addEventListener('click', (e) => {
  14079.       const btn = e.target.closest('.mtb-btn');
  14080.       if (!btn) return;
  14081.       // Bouton fermer
  14082.       if (btn.classList.contains('mtb-close')) {
  14083.         document.querySelector('.media-toolbar')?.remove();
  14084.         return;
  14085.       }
  14086.       const filter = btn.dataset.filter;
  14087.       if (!filter) return;
  14088.       // 🎯 CAS SPÉCIAL : Bouton favoris (filtre + ouvre sidebar, JAMAIS de modification du compteur)
  14089.       if (filter === 'favoris') {
  14090.         console.log('💗 BOUTON FAVORIS CLIQUÉ - Vue favoris + ouverture sidebar');
  14091.         
  14092.         // 🛡️ Protection ABSOLUE : empêcher TOUTE propagation vers d'autres handlers
  14093.         e.stopPropagation();
  14094.         e.stopImmediatePropagation();
  14095.         e.preventDefault();
  14096.         
  14097.         // 1️⃣ Activer visuellement le bouton favoris
  14098.         const mtbBtns = document.querySelectorAll('.mtb-btn[data-filter]');
  14099.         mtbBtns.forEach(b => {
  14100.           if (b === btn) {
  14101.             b.classList.add('active');
  14102.           } else {
  14103.             b.classList.remove('active');
  14104.           }
  14105.         });
  14106.         
  14107.         // 2️⃣ Filtrer la galerie pour afficher uniquement les favoris
  14108.         if (typeof window.filterContent === 'function') {
  14109.           window.filterContent('favoris');
  14110.         } else {
  14111.           console.error('❌ window.filterContent non disponible');
  14112.         }
  14113.         
  14114.         // 3️⃣ Ouvrir le sidebar e-commerce via le bouton cadeau
  14115.         const giftButton = document.getElementById('gift-button-trigger');
  14116.         if (giftButton) {
  14117.           console.log('🎁 Ouverture du sidebar via bouton cadeau');
  14118.           setTimeout(() => giftButton.click(), 100); // Petit délai pour éviter les conflits
  14119.         } else {
  14120.           console.warn('⚠️ Bouton cadeau non trouvé');
  14121.         }
  14122.         
  14123.         return; // ⛔ SORTIE IMMÉDIATE - pas de traitement supplémentaire
  14124.       }
  14125.       // 🎯 CAS SPÉCIAL : Bouton audio avec 0 message → afficher popover
  14126.       if (filter === 'audio') {
  14127.         const audioCount = btn.querySelector('.mtb-count[data-bind=\"audio\"]');
  14128.         const count = audioCount ? parseInt(audioCount.textContent.trim()) : 0;
  14129.         
  14130.         if (count === 0) {
  14131.           console.log('🎤 Bouton audio cliqué avec 0 message - affichage popover');
  14132.           
  14133.           e.stopPropagation();
  14134.           e.preventDefault();
  14135.           
  14136.           // Afficher le popover premium
  14137.           showAudioEmptyPopover(btn);
  14138.           return; // ⛔ Ne pas filtrer si 0 message
  14139.         }
  14140.       }
  14141.       // Exception pour le bouton photos : ne pas modifier les états actifs
  14142.       if (btn.dataset.filter === 'photos') {
  14143.         // Pour le bouton photos, ne pas toucher aux autres boutons
  14144.         // Juste exécuter l'action sans changer les états
  14145.       } else {
  14146.         // Pour les autres boutons : gérer les états actifs normalement
  14147.         const mtbBtns = document.querySelectorAll('.mtb-btn[data-filter]');
  14148.         for (let i = 0; i < mtbBtns.length; i++) {
  14149.           const b = mtbBtns[i];
  14150.           if (b && b.classList) {
  14151.             if (b === btn) {
  14152.               b.classList.add('active');
  14153.             } else {
  14154.               b.classList.remove('active');
  14155.             }
  14156.           }
  14157.         }
  14158.       }
  14159.       
  14160.       // Déclencher le filtrage du contenu - même logique que stat-pill
  14161.       console.log('mtb-btn click:', filter, 'filterContent type:', typeof window.filterContent);
  14162.       if (typeof window.filterContent === 'function') {
  14163.         window.filterContent(filter);
  14164.       } else {
  14165.         console.error('window.filterContent n\\'est pas une fonction!');
  14166.       }
  14167.     });
  14168.     // Expose un setter global
  14169.     window.setMediaFilter = (filter) => {
  14170.       // Pour le bouton photos : ne pas modifier les états
  14171.       if (filter !== 'photos') {
  14172.         setActive(filter);
  14173.       }
  14174.       applyFilter(filter);
  14175.     };
  14176.     // 🛡️ PROTECTION ABSOLUE : Empêcher TOUTE interaction directe avec le compteur favoris
  14177.     document.addEventListener('DOMContentLoaded', () => {
  14178.       const mesFavCount = document.getElementById('mesFavCount');
  14179.       if (mesFavCount) {
  14180.         // Bloquer tous les clics directs sur le compteur
  14181.         mesFavCount.addEventListener('click', (e) => {
  14182.           console.log('⚠️ Clic sur mesFavCount bloqué');
  14183.           e.stopPropagation();
  14184.           e.stopImmediatePropagation();
  14185.           e.preventDefault();
  14186.           return false;
  14187.         }, true); // Capture phase pour intercepter avant tout autre listener
  14188.         
  14189.         // Empêcher le double-clic
  14190.         mesFavCount.addEventListener('dblclick', (e) => {
  14191.           console.log('⚠️ Double-clic sur mesFavCount bloqué');
  14192.           e.stopPropagation();
  14193.           e.stopImmediatePropagation();
  14194.           e.preventDefault();
  14195.           return false;
  14196.         }, true);
  14197.         
  14198.         // Ajouter un style pour indiquer visuellement que c'est non-cliquable
  14199.         mesFavCount.style.pointerEvents = 'none';
  14200.         mesFavCount.style.userSelect = 'none';
  14201.         
  14202.         console.log('🛡️ Protection mesFavCount activée - compteur non-cliquable');
  14203.       }
  14204.       
  14205.       // 🎤 Initialiser l'état du bouton audio (griser si 0 message)
  14206.       initAudioButtonState();
  14207.     });
  14208.     // 🎤 Fonction pour afficher le popover \"Pas de message audio\"
  14209.     function showAudioEmptyPopover(btn) {
  14210.       // Supprimer les popovers existants
  14211.       const existingPopover = document.querySelector('.audio-empty-popover');
  14212.       if (existingPopover) {
  14213.         existingPopover.remove();
  14214.       }
  14215.       
  14216.       // Créer le popover
  14217.       const popover = document.createElement('div');
  14218.       popover.className = 'audio-empty-popover';
  14219.       popover.innerHTML = `
  14220.         <div class=\"audio-popover-content\">
  14221.           <div class=\"audio-popover-icon\">
  14222.             <i class=\"bi bi-mic-mute-fill\"></i>
  14223.           </div>
  14224.           <div class=\"audio-popover-text\">
  14225.             <strong>Aucun message audio</strong>
  14226.             <p>Pas de message audio soumis pour l'instant</p>
  14227.           </div>
  14228.         </div>
  14229.       `;
  14230.       
  14231.       // Positionner le popover
  14232.       document.body.appendChild(popover);
  14233.       
  14234.       const btnRect = btn.getBoundingClientRect();
  14235.       popover.style.position = 'fixed';
  14236.       popover.style.top = `\${btnRect.bottom + 10}px`;
  14237.       popover.style.left = `\${btnRect.left + (btnRect.width / 2)}px`;
  14238.       popover.style.transform = 'translateX(-50%)';
  14239.       
  14240.       // Animation d'entrée
  14241.       setTimeout(() => popover.classList.add('show'), 10);
  14242.       
  14243.       // Auto-fermeture après 3 secondes
  14244.       setTimeout(() => {
  14245.         popover.classList.remove('show');
  14246.         setTimeout(() => popover.remove(), 300);
  14247.       }, 3000);
  14248.       
  14249.       // Fermer au clic ailleurs
  14250.       const closeOnClick = (e) => {
  14251.         if (!popover.contains(e.target) && !btn.contains(e.target)) {
  14252.           popover.classList.remove('show');
  14253.           setTimeout(() => popover.remove(), 300);
  14254.           document.removeEventListener('click', closeOnClick);
  14255.         }
  14256.       };
  14257.       setTimeout(() => document.addEventListener('click', closeOnClick), 100);
  14258.     }
  14259.     // 🎤 Fonction pour initialiser l'état du bouton audio
  14260.     function initAudioButtonState() {
  14261.       const audioBtn = document.querySelector('.mtb-btn[data-filter=\"audio\"]');
  14262.       if (!audioBtn) return;
  14263.       
  14264.       const audioCount = audioBtn.querySelector('.mtb-count[data-bind=\"audio\"]');
  14265.       if (!audioCount) return;
  14266.       
  14267.       const count = parseInt(audioCount.textContent.trim()) || 0;
  14268.       
  14269.       if (count === 0) {
  14270.         // Masquer le compteur \"0\"
  14271.         audioCount.style.display = 'none';
  14272.         
  14273.         // Griser l'icône
  14274.         audioBtn.classList.add('disabled-audio');
  14275.         audioBtn.style.opacity = '0.4';
  14276.         audioBtn.style.cursor = 'not-allowed';
  14277.         
  14278.         const icons = audioBtn.querySelectorAll('i');
  14279.         icons.forEach(icon => {
  14280.           icon.style.color = '#999 !important';
  14281.           icon.style.filter = 'grayscale(100%)';
  14282.         });
  14283.         
  14284.         console.log('🎤 Bouton audio désactivé (0 message)');
  14285.       } else {
  14286.         // Afficher le compteur
  14287.         audioCount.style.display = 'inline';
  14288.         
  14289.         // Activer l'icône
  14290.         audioBtn.classList.remove('disabled-audio');
  14291.         audioBtn.style.opacity = '1';
  14292.         audioBtn.style.cursor = 'pointer';
  14293.         
  14294.         console.log(`🎤 Bouton audio activé (\${count} message\${count > 1 ? 's' : ''})`);
  14295.       }
  14296.     }
  14297.     // 🎤 Observer les changements du compteur audio pour mettre à jour l'état
  14298.     const audioCountObserver = new MutationObserver(() => {
  14299.       initAudioButtonState();
  14300.     });
  14301.     
  14302.     // Démarrer l'observation quand le DOM est prêt
  14303.     if (document.readyState === 'loading') {
  14304.       document.addEventListener('DOMContentLoaded', () => {
  14305.         const audioCount = document.querySelector('.mtb-count[data-bind=\"audio\"]');
  14306.         if (audioCount) {
  14307.           audioCountObserver.observe(audioCount, { 
  14308.             childList: true, 
  14309.             characterData: true, 
  14310.             subtree: true 
  14311.           });
  14312.         }
  14313.       });
  14314.     } else {
  14315.       const audioCount = document.querySelector('.mtb-count[data-bind=\"audio\"]');
  14316.       if (audioCount) {
  14317.         audioCountObserver.observe(audioCount, { 
  14318.           childList: true, 
  14319.           characterData: true, 
  14320.           subtree: true 
  14321.         });
  14322.       }
  14323.     }
  14324.     
  14325.     // Mise à jour des compteurs quand les favoris changent
  14326.     window.addEventListener('favorites:updated', updateCounts);
  14327.     
  14328.     // Initialisation
  14329.     setTimeout(() => {
  14330.       updateCounts();
  14331.       setActive('all');
  14332.     }, 100);
  14333.     // Mise à jour périodique des compteurs (sauf favoris qui reste fixe)
  14334.     setInterval(updateCounts, 2000);
  14335.   })();
  14336.   function navigateToDay(index) {
  14337.      if (index >= 0 && index < collapseSections.length) {
  14338.       // Fermer tous les jours
  14339.       collapseSections.forEach(s => {
  14340.         if (s && s.classList) {
  14341.           s.classList.remove('show');
  14342.         }
  14343.       });
  14344.       dateCards.forEach(c => {
  14345.         if (c && c.classList) {
  14346.           c.classList.remove('active');
  14347.         }
  14348.       });
  14349.       // Ouvrir le bon jour
  14350.       const targetCollapse = collapseSections[index];
  14351.       const targetCard = dateCards[index];
  14352.       if (targetCollapse && targetCard) {
  14353.         if (targetCollapse.classList) {
  14354.           targetCollapse.classList.add('show');
  14355.         }
  14356.         if (targetCard.classList) {
  14357.           targetCard.classList.add('active');
  14358.         }
  14359.       }
  14360.     }
  14361.   }
  14362.   prevButtons.forEach(button => {
  14363.     button.addEventListener('click', function () {
  14364.       const targetIndex = parseInt(this.dataset.target, 10);
  14365.       navigateToDay(targetIndex);
  14366.     });
  14367.   });
  14368.   nextButtons.forEach(button => {
  14369.     button.addEventListener('click', function () {
  14370.       const targetIndex = parseInt(this.dataset.target, 10);
  14371.       navigateToDay(targetIndex);
  14372.     });
  14373.   });
  14374. });
  14375. </script>
  14376.   <script>
  14377.     document.addEventListener('DOMContentLoaded', function() {
  14378.   const style = document.createElement('style');
  14379.   style.textContent = `
  14380.     .hidden {
  14381.       display: none !important;
  14382.     }
  14383.   `;
  14384.   document.head.appendChild(style);
  14385. });
  14386.     document.addEventListener('DOMContentLoaded', function() {
  14387.     // Get the gift button
  14388.     const giftButton = document.querySelector('.gift-button');
  14389.     if (giftButton) {
  14390.       // Keep it clickable for the gift functionality
  14391.       giftButton.style.pointerEvents = 'auto';
  14392.       
  14393.       // Add click handler for gift action
  14394.       giftButton.onclick = function(e) {
  14395.         e.preventDefault();
  14396.         e.stopPropagation();
  14397.         return false;
  14398.       };
  14399.       
  14400.       // Make sure hover still works
  14401.       favoriteButton.addEventListener('mouseover', function() {
  14402.         document.getElementById('purchase-alert').style.display = 'block';
  14403.       });
  14404.       
  14405.       // Keep any existing hover functionality
  14406.       if (typeof showSelection === 'function') {
  14407.         favoriteButton.onmouseover = showSelection;
  14408.       }
  14409.     }
  14410.     
  14411.     // Make sure the purchase alert remains interactive
  14412.     const purchaseAlert = document.getElementById('purchase-alert');
  14413.     if (purchaseAlert) {
  14414.       purchaseAlert.style.pointerEvents = 'auto';
  14415.     }
  14416.   });
  14417.     // Sélection des éléments
  14418.     const purchaseAlert = document.getElementById(\"purchase-alert\");
  14419.     const alertContent = document.getElementById(\"purchase-alert-content\");
  14420.     const likeCountLabel = document.getElementById(\"likeCount\");
  14421.     
  14422.     // Fonction pour obtenir le nombre actuel de favoris
  14423.     function getCurrentFavoriteCount() {
  14424.         const likeCountLabel = document.getElementById(\"likeCount\");
  14425.         return parseInt(likeCountLabel?.textContent.trim(), 10) || 0;
  14426.     }
  14427.     // Fonction pour mettre à jour le contenu de l'alerte
  14428.     function updatePurchaseAlert(current) {
  14429.   let remainingForAlbum = Math.max(0, 20 - current);
  14430.   let remainingForPochette = Math.max(0, 12 - current);
  14431.   let remainingForPack = Math.max(0, 12 - current);
  14432.   const progressBar = (count, total, color) => `
  14433.   <div style=\"margin: 5px 0;\">
  14434.     <div style=\"background-color: #e9ecef; border-radius: 5px; overflow: hidden; height: 8px;\">
  14435.       <div style=\"width: \${
  14436.         (count / total) * 100
  14437.       }%; background-color: \${color}; height: 100%;\"></div>
  14438.     </div>
  14439.     <small style=\"font-size: 12px;\">\${count}/\${total} photos</small>
  14440.   </div>
  14441. `;
  14442.   // Use Twig paths here:
  14443.   const products = [
  14444.       {
  14445.       name: \"Pochette photo (12 photos)\",
  14446.       required: 12,
  14447.       remaining: remainingForPochette,
  14448.       image: \"/images/produit/PochettePhoto5sur5-2.jpg\",
  14449.       color: \"#2196f3\",
  14450.       link: \"{{ path('AjoutPochettePhotos_Favoris', {'nbr': 12}) }}\",
  14451.     },
  14452.        {
  14453.       name: \"Pack numérique (20 photos)\",
  14454.       required: 20,
  14455.       remaining: remainingForAlbum,
  14456.       image: \"/images/produit/photoNumerique.jpg\",
  14457.       color: \"#4caf50\",
  14458.       link: \"{{ path('PackPhotosNumerique_Favoris', {'nbr': 20}) }}\",
  14459.     }
  14460.   
  14461.   
  14462.     
  14463.   ].sort((a, b) => a.remaining - b.remaining);
  14464.   const productList = products
  14465.     .map((product) => {
  14466.       const count = current;
  14467.       const total = product.required;
  14468.       const remaining = product.remaining;
  14469.       return `
  14470.     <li style=\"margin-bottom: 15px;\">
  14471.       <div style=\"display: flex; align-items: center; gap: 10px;\">
  14472.         <img
  14473.           src=\"\${product.image}\"
  14474.           alt=\"\${product.name}\"
  14475.           style=\"width: 65px; height: 65px; border-radius: 5px; margin-top:-19px\"
  14476.         />
  14477.         <div style=\"flex: 1;\">
  14478.           <strong style=\"font-size: 14px;\">\${product.name}</strong>
  14479.           \${progressBar(count, total, product.color)}
  14480.           \${
  14481.             remaining > 0
  14482.               ? `<small style=\"color: \${product.color}; font-size: 12px;\">
  14483.                    Encore \${remaining} photos ❤️ pour compléter \${product.name.toLowerCase()}
  14484.                  </small>`
  14485.               : `<button
  14486.                   style=\"
  14487.                     margin-top: 5px;
  14488.                     padding: 5px 8px;
  14489.                     background-color: \${product.color};
  14490.                     color: white;
  14491.                     border: none;
  14492.                     border-radius: 5px;
  14493.                     font-size: 12px;
  14494.                     cursor: pointer;
  14495.                   \"
  14496.                   onclick=\"window.location.href='\${product.link}'\"
  14497.                 >
  14498.                   Commander
  14499.                 </button>`
  14500.           }
  14501.         </div>
  14502.       </div>
  14503.     </li>
  14504.   `;
  14505.     })
  14506.     .join(\"\");
  14507.   const plusButton = `
  14508.     <li style=\"margin-bottom: 15px; text-align: center;\">
  14509.       <button
  14510.         style=\"
  14511.           padding: 5px 8px;
  14512.           background-color: #F56040;
  14513.           color: white;
  14514.           border: none;
  14515.           border-radius: 5px;
  14516.           font-size: 14px;
  14517.           line-height: 1;
  14518.           width: 150px;
  14519.           height: 40px;
  14520.           cursor: pointer;
  14521.         \"
  14522.         onclick=\"window.location.href='{{ path('boutique5sur5') }}'\"
  14523.       >
  14524.         Aller à la boutique
  14525.       </button>
  14526.     </li>
  14527.   `;
  14528.   if (current === 0) {
  14529.     alertContent.innerHTML = `
  14530.     <p style=\"font-size: 16px; font-weight: bold; color: #333;\">
  14531.       Vous n'avez pas encore de photos favorites !
  14532.     </p>
  14533.     <p style=\"margin-bottom: 20px; color: #555;\">
  14534.       Commencez à ajouter vos moments préférés pour profiter de nos offres.
  14535.     </p>
  14536.     <ul style=\"list-style-type: none; padding: 0;\">\${productList}\${plusButton}</ul>
  14537.   `;
  14538.   } else {
  14539.     alertContent.innerHTML = `
  14540.     <p style=\"font-size: 16px; font-weight: bold; color: #333;\">
  14541.       Vous avez atteint \${current} photos favorites !
  14542.     </p>
  14543.     <p style=\"margin-bottom: 20px; color: #555;\">
  14544.       Profitez de nos offres spéciales :
  14545.     </p>
  14546.     <ul style=\"list-style-type: none; padding: 0;\">\${productList}\${plusButton}</ul>
  14547.   `;
  14548.   }
  14549.   if (purchaseAlert && purchaseAlert.classList) {
  14550.     purchaseAlert.classList.remove(\"hidden\");
  14551.   }
  14552.   clearTimeout(window.purchaseAlertTimeout);
  14553.   window.purchaseAlertTimeout = setTimeout(() => {
  14554.     if (!purchaseAlert.matches(\":hover\")) {
  14555.       closePurchaseAlert();
  14556.     }
  14557.   }, 5000);
  14558. }
  14559.     // Fonction pour fermer l'alerte
  14560.     function closePurchaseAlert() {
  14561.       if (purchaseAlert && purchaseAlert.classList) {
  14562.         purchaseAlert.classList.add(\"hidden\");
  14563.       }
  14564.     }
  14565.     // Événement pour mettre à jour le contenu et afficher la popover dynamiquement au hover
  14566.     document.querySelector(\".gift-button\").addEventListener(\"mouseover\", () => {
  14567.       const currentCount = getCurrentFavoriteCount();
  14568.       updatePurchaseAlert(currentCount);
  14569.       if (purchaseAlert && purchaseAlert.classList) {
  14570.         purchaseAlert.classList.remove(\"cachee\"); // Réaffiche la popover
  14571.       }
  14572.     });
  14573.     // Nouvelles fonctions pour le bouton cadeau
  14574.     function showGiftMessage() {
  14575.       const tooltip = document.getElementById(\"giftTooltip\");
  14576.       if (tooltip) {
  14577.         if (tooltip && tooltip.classList) {
  14578.           tooltip.classList.add(\"show\");
  14579.         }
  14580.       }
  14581.     }
  14582.     function hideGiftMessage() {
  14583.       const tooltip = document.getElementById(\"giftTooltip\");
  14584.       if (tooltip) {
  14585.         if (tooltip && tooltip.classList) {
  14586.           tooltip.classList.remove(\"show\");
  14587.         }
  14588.       }
  14589.     }
  14590.     function showSelection() {
  14591.       document.getElementById(\"purchase-alert\").style.display = \"block\";
  14592.     }
  14593.     function hideSelection() {
  14594.       document.getElementById(\"selectionPopover\").style.display = \"none\";
  14595.     }
  14596.     document.addEventListener(\"DOMContentLoaded\", function () {
  14597.       const container = document.querySelector(\".date-container\");
  14598.       // Vérifie si le conteneur existe pour éviter les erreurs
  14599.       if (container) {
  14600.         container.scrollTo({
  14601.           left: container.scrollWidth, // Scroll directement à la position maximale
  14602.           behavior: \"smooth\", // Défilement fluide
  14603.         });
  14604.       }
  14605.     });
  14606.     document.addEventListener(\"DOMContentLoaded\", function () {
  14607.       const container = document.querySelector(\".date-container\");
  14608.       const leftArrow = document.querySelector(\".scroll-btn.left\");
  14609.       const rightArrow = document.querySelector(\".scroll-btn.right\");
  14610.       // Fonction pour vérifier le débordement et activer/désactiver les flèches
  14611.       function updateArrowsVisibility() {
  14612.         const isOverflowing = container.scrollWidth > container.clientWidth; // Vérifie si débordement
  14613.         leftArrow.style.display = isOverflowing ? \"flex\" : \"none\";
  14614.         rightArrow.style.display = isOverflowing ? \"flex\" : \"none\";
  14615.       }
  14616.       // Fonction pour défiler
  14617.       function scrollContainer(direction) {
  14618.         container.scrollBy({
  14619.           left: direction === \"left\" ? -200 : 200, // Défiler à gauche ou à droite
  14620.           behavior: \"smooth\",
  14621.         });
  14622.       }
  14623.       // Ajout des événements de clic pour les flèches
  14624.       leftArrow.addEventListener(\"click\", () => scrollContainer(\"left\"));
  14625.       rightArrow.addEventListener(\"click\", () => scrollContainer(\"right\"));
  14626.       // ⚡ OPTIMISÉ: Debounce resize pour éviter surcharge
  14627.       let resizeTimeout;
  14628.       const debouncedResize = () => {
  14629.         clearTimeout(resizeTimeout);
  14630.         resizeTimeout = setTimeout(updateArrowsVisibility, 150);
  14631.       };
  14632.       
  14633.       updateArrowsVisibility();
  14634.       window.addEventListener(\"resize\", debouncedResize, { passive: true });
  14635.     });
  14636.     document.addEventListener(\"DOMContentLoaded\", function () {
  14637.       const container = document.querySelector(\".date-container\");
  14638.       const leftBtn = document.querySelector(\".scroll-btn.left\");
  14639.       const rightBtn = document.querySelector(\".scroll-btn.right\");
  14640.       leftBtn.addEventListener(\"click\", () => {
  14641.         container.scrollBy({
  14642.           left: -200, // Défile vers la gauche
  14643.           behavior: \"smooth\",
  14644.         });
  14645.       });
  14646.       rightBtn.addEventListener(\"click\", () => {
  14647.         container.scrollBy({
  14648.           left: 200, // Défile vers la droite
  14649.           behavior: \"smooth\",
  14650.         });
  14651.       });
  14652.     });
  14653.  document.addEventListener(\"DOMContentLoaded\", function () {
  14654.     // Sélectionnez tous les badges de filtre
  14655.     const filterBadges = document.querySelectorAll(\".filter-badge\");
  14656.     // Sélectionnez tous les éléments de la galerie
  14657.     const galleryItems = document.querySelectorAll(\".column\");
  14658.     // Sélectionnez tous les jours
  14659.     const days = document.querySelectorAll(\".collapse\");
  14660.     // Fonction pour réinitialiser les filtres
  14661.     function resetFilters() {
  14662.         // Réinitialisez tous les éléments de la galerie
  14663.         galleryItems.forEach((item) => {
  14664.             item.style.display = \"block\";
  14665.         });
  14666.         // Réinitialisez les états des badges
  14667.         filterBadges.forEach((badge) => {
  14668.           if (badge && badge.classList) {
  14669.             badge.classList.remove(\"active\");
  14670.           }
  14671.         });
  14672.     }
  14673.     // Ajoutez un gestionnaire d'événements pour chaque badge
  14674.     filterBadges.forEach((badge) => {
  14675.         badge.addEventListener(\"click\", function () {
  14676.             const filter = this.getAttribute(\"data-filter\");
  14677.             // Réinitialisez l'état actif pour tous les badges
  14678.             filterBadges.forEach((btn) => {
  14679.               if (btn && btn.classList) {
  14680.                 btn.classList.remove(\"active\");
  14681.               }
  14682.             });
  14683.             // Ajoutez l'état actif au badge cliqué
  14684.             if (this && this.classList) {
  14685.               this.classList.add(\"active\");
  14686.             }
  14687.             // Affichez ou masquez les éléments de la galerie
  14688.             galleryItems.forEach((item) => {
  14689.                 if (filter === \"all\") {
  14690.                     item.style.display = \"block\";
  14691.                 } else if (filter === \"photo\" && item.querySelector(\"img\")) {
  14692.                     item.style.display = \"block\";
  14693.                 } else if (filter === \"video\" && item.querySelector(\"video\")) {
  14694.                     item.style.display = \"block\";
  14695.                 } else if (filter === \"audio\" && item.classList && item.classList.contains(\"audio-message-item\")) {
  14696.                     item.style.display = \"block\";
  14697.                 } else {
  14698.                     item.style.display = \"none\";
  14699.                 }
  14700.             });
  14701.         });
  14702.     });
  14703.     // Réinitialiser les filtres lors du changement de jour
  14704.     days.forEach((day) => {
  14705.         day.addEventListener(\"show.bs.collapse\", function () {
  14706.             resetFilters();
  14707.         });
  14708.     });
  14709. });
  14710.     \$(document).ready(function () {
  14711.       let zoomCounter = 0; // Initialize zoom counter
  14712.       let currentImageSrc = \"\"; // Track current image source
  14713.       let lastClickPosition = { x: 50, y: 50 }; // Default to center of image
  14714.       \$(\".container--gallery\").magnificPopup({
  14715.         delegate: \"a\",
  14716.         type: \"image\",
  14717.         mainClass: \"mfp-with-zoom mfp-img-mobile\",
  14718.         image: {
  14719.           verticalFit: true,
  14720.         },
  14721.         gallery: {
  14722.           enabled: true,
  14723.           tPrev: \"Previous (Left arrow key)\", // Alt text on left arrow
  14724.           tNext: \"Next (Right arrow key)\", // Alt text on right arrow
  14725.           tCounter: \"%curr% of %total%\", // Markup for \"1 of 7\" counter
  14726.         },
  14727.         zoom: {
  14728.           enabled: true,
  14729.           duration: 300,
  14730.           opener: function (element) {
  14731.             return element.find(\"img\");
  14732.           },
  14733.         },
  14734.         callbacks: {
  14735.           open: function () {
  14736.             // Get current image data from the link that was clicked
  14737.             const currentLink = this.currItem.el;
  14738.             const imageId =
  14739.               currentLink
  14740.                 .closest(\".photo-zoom\")
  14741.                 .find(\".heart-icon\")
  14742.                 .data(\"id\") || \"\";
  14743.             const sejourId =
  14744.               currentLink
  14745.                 .closest(\".photo-zoom\")
  14746.                 .find(\".heart-icon\")
  14747.                 .data(\"sejour-id\") || \"\";
  14748.             const imagePath =
  14749.               currentLink
  14750.                 .closest(\".photo-zoom\")
  14751.                 .find(\".heart-icon\")
  14752.                 .data(\"path\") || \"\";
  14753.             const imageDesc =
  14754.               currentLink
  14755.                 .closest(\".photo-zoom\")
  14756.                 .find(\".heart-icon\")
  14757.                 .data(\"description\") || \"\";
  14758.             const isFavorite = currentLink
  14759.               .closest(\".photo-zoom\")
  14760.               .find(\".heart-icon i\")
  14761.               .hasClass(\"bi-heart-fill\");
  14762.             const favoriteIconClass = isFavorite ? \"bi-heart-fill\" : \"bi-heart\";
  14763.             const favoriteIconColor = isFavorite ? \"#f56040\" : \"white\";
  14764.             const favoriteTooltip = isFavorite
  14765.               ? \"Retirer des favoris\"
  14766.               : \"Ajouter aux favoris\";
  14767.             const zoomControls = `
  14768.           <div class=\"mfp-zoom-controls\">
  14769.             <button class=\"zoom-btn zoom-out\" title=\"Zoom Out\"><i class=\"fa fa-search-minus\"></i></button>
  14770.             <button class=\"zoom-btn zoom-in\" title=\"Zoom In\"><i class=\"fa fa-search-plus\"></i></button>
  14771.           </div>
  14772.           <div class=\"mfp-favorite\">
  14773.             <button class=\"favorite-btn\" 
  14774.                     data-id=\"\${imageId}\" 
  14775.                     data-sejour-id=\"\${sejourId}\" 
  14776.                     data-path=\"\${imagePath}\" 
  14777.                     data-description=\"\${imageDesc}\"
  14778.                     title=\"\${favoriteTooltip}\">
  14779.               <i class=\"bi \${favoriteIconClass}\" style=\"color: \${favoriteIconColor}; text-shadow: 0px 0px 3px rgba(0,0,0,0.5);\"></i>
  14780.             </button>
  14781.           </div>
  14782.           <div class=\"mfp-counter\"></div>
  14783.         `;
  14784.             \$(\".mfp-content\").append(zoomControls);
  14785.             initializeZoomControls();
  14786.             initializeFavoriteButton();
  14787.             const intervalId = setInterval(() => {
  14788.               const newImageSrc = \$(\".mfp-img\").attr(\"src\");
  14789.               if (newImageSrc !== currentImageSrc) {
  14790.                 currentImageSrc = newImageSrc;
  14791.                 zoomCounter = 0;
  14792.                 lastClickPosition = { x: 50, y: 50 }; // Reset to center
  14793.                 attachZoomHandler(); // Reattach zoom handler to new image
  14794.                 \$(\".mfp-img\").css({
  14795.                   \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  14796.                   transform: `scale(1)`,
  14797.                 });
  14798.                 // Update favorite button for the new image
  14799.                 updateFavoriteButton();
  14800.                 initializeZoomControls();
  14801.                 updateCounter();
  14802.               }
  14803.             }, 100);
  14804.             this.content.on(\"mfpClose\", function () {
  14805.               clearInterval(intervalId);
  14806.             });
  14807.             attachZoomHandler();
  14808.           },
  14809.           close: function () {
  14810.             \$(\".mfp-zoom-controls\").remove();
  14811.             \$(\".mfp-favorite\").remove();
  14812.             \$(\".mfp-counter\").remove();
  14813.             zoomCounter = 0;
  14814.           },
  14815.         },
  14816.       });
  14817.       function attachZoomHandler() {
  14818.         \$(\".mfp-img\")
  14819.           .off(\"click\")
  14820.           .on(\"click\", function (event) {
  14821.             event.stopPropagation(); // Prevent default navigation behavior
  14822.             // Calculate click coordinates relative to the image
  14823.             const imgOffset = \$(this).offset();
  14824.             const clickX = event.pageX - imgOffset.left;
  14825.             const clickY = event.pageY - imgOffset.top;
  14826.             const imgWidth = \$(this).width();
  14827.             const imgHeight = \$(this).height();
  14828.             // Calculate transform-origin based on click position
  14829.             lastClickPosition = {
  14830.               x: (clickX / imgWidth) * 100,
  14831.               y: (clickY / imgHeight) * 100,
  14832.             };
  14833.             // Cycle through zoom levels: 1x, 1.5x, 2x
  14834.             zoomCounter = (zoomCounter + 1) % 3;
  14835.             const zoomLevels = [1, 1.5, 2];
  14836.             const zoomLevel = zoomLevels[zoomCounter];
  14837.             \$(this).css({
  14838.               \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  14839.               transform: `scale(\${zoomLevel})`,
  14840.             });
  14841.             updateZoomButtonState();
  14842.           });
  14843.       }
  14844.       function initializeZoomControls() {
  14845.         \$(\".mfp-zoom-controls .zoom-in\")
  14846.           .off(\"click\")
  14847.           .on(\"click\", function (event) {
  14848.             event.stopPropagation();
  14849.             zoomCounter = (zoomCounter + 1) % 3;
  14850.             const zoomLevels = [1, 1.5, 2];
  14851.             const zoomLevel = zoomLevels[zoomCounter];
  14852.             \$(\".mfp-img\").css({
  14853.               \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  14854.               transform: `scale(\${zoomLevel})`,
  14855.             });
  14856.             updateZoomButtonState();
  14857.           });
  14858.         \$(\".mfp-zoom-controls .zoom-out\")
  14859.           .off(\"click\")
  14860.           .on(\"click\", function (event) {
  14861.             event.stopPropagation();
  14862.             if (zoomCounter > 0) {
  14863.               zoomCounter -= 1;
  14864.               const zoomLevels = [1, 1.5, 2];
  14865.               const zoomLevel = zoomLevels[zoomCounter];
  14866.               \$(\".mfp-img\").css({
  14867.                 \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  14868.                 transform: `scale(\${zoomLevel})`,
  14869.               });
  14870.               updateZoomButtonState();
  14871.             } else {
  14872.               \$.magnificPopup.close();
  14873.             }
  14874.           });
  14875.       }
  14876.       function initializeFavoriteButton() {
  14877.         \$(\".mfp-favorite .favorite-btn\")
  14878.           .off(\"click\")
  14879.           .on(\"click\", function (event) {
  14880.             event.stopPropagation();
  14881.             const \$this = \$(this);
  14882.             const imageId = \$this.data(\"id\");
  14883.             const sejourId = \$this.data(\"sejour-id\");
  14884.             // Toggle favorite status
  14885.             const isFavorite = \$this.find(\"i\").hasClass(\"bi-heart-fill\");
  14886.             // Update the button appearance
  14887.             if (isFavorite) {
  14888.               \$this
  14889.                 .find(\"i\")
  14890.                 .removeClass(\"bi-heart-fill\")
  14891.                 .addClass(\"bi-heart\")
  14892.                 .css(\"color\", \"white\");
  14893.               \$this.attr(\"title\", \"Ajouter aux favoris\");
  14894.             } else {
  14895.               \$this
  14896.                 .find(\"i\")
  14897.                 .removeClass(\"bi-heart\")
  14898.                 .addClass(\"bi-heart-fill\")
  14899.                 .css(\"color\", \"#f56040\");
  14900.               \$this.attr(\"title\", \"Retirer des favoris\");
  14901.             }
  14902.             // Update the original heart icon in the gallery
  14903.             const originalHeartIcon = \$(
  14904.               `.heart-icon[data-id=\"\${imageId}\"]`
  14905.             ).find(\"i\");
  14906.             if (isFavorite) {
  14907.               originalHeartIcon
  14908.                 .removeClass(\"bi-heart-fill\")
  14909.                 .addClass(\"bi-heart\")
  14910.                 .css(\"color\", \"\");
  14911.             } else {
  14912.               originalHeartIcon
  14913.                 .removeClass(\"bi-heart\")
  14914.                 .addClass(\"bi-heart-fill\")
  14915.                 .css(\"color\", \"#f56040\");
  14916.             }
  14917.             // Make AJAX call to update favorite status in the backend using Parent routes
  14918.             \$.ajax({
  14919.               url: isFavorite ? \"/Parent/aSupprimerFav\" : \"/Parent/ajouterFav\",
  14920.               type: \"POST\",
  14921.               data: {
  14922.                 id: imageId,
  14923.                 idSejour: sejourId,
  14924.               },
  14925.               success: function (response) {
  14926.                 // Optional: Show a success message or handle response
  14927.                 console.log(\"Favorite status updated\", response);
  14928.               },
  14929.               error: function (error) {
  14930.                 console.error(\"Error updating favorite status\", error);
  14931.                 // Revert the icon change on error
  14932.                 if (isFavorite) {
  14933.                   \$this
  14934.                     .find(\"i\")
  14935.                     .removeClass(\"bi-heart\")
  14936.                     .addClass(\"bi-heart-fill\")
  14937.                     .css(\"color\", \"#f56040\");
  14938.                   originalHeartIcon
  14939.                     .removeClass(\"bi-heart\")
  14940.                     .addClass(\"bi-heart-fill\")
  14941.                     .css(\"color\", \"#f56040\");
  14942.                 } else {
  14943.                   \$this
  14944.                     .find(\"i\")
  14945.                     .removeClass(\"bi-heart-fill\")
  14946.                     .addClass(\"bi-heart\")
  14947.                     .css(\"color\", \"white\");
  14948.                   originalHeartIcon
  14949.                     .removeClass(\"bi-heart-fill\")
  14950.                     .addClass(\"bi-heart\")
  14951.                     .css(\"color\", \"\");
  14952.                 }
  14953.               },
  14954.             });
  14955.           });
  14956.       }
  14957.       function updateFavoriteButton() {
  14958.         // Get current image data from the current slide
  14959.         const currentSlide = \$.magnificPopup.instance.currItem.el;
  14960.         const photoZoom = currentSlide.closest(\".photo-zoom\");
  14961.         if (photoZoom.length) {
  14962.           const heartIcon = photoZoom.find(\".heart-icon\");
  14963.           const imageId = heartIcon.data(\"id\") || \"\";
  14964.           const sejourId = heartIcon.data(\"sejour-id\") || \"\";
  14965.           const imagePath = heartIcon.data(\"path\") || \"\";
  14966.           const imageDesc = heartIcon.data(\"description\") || \"\";
  14967.           const isFavorite = heartIcon.find(\"i\").hasClass(\"bi-heart-fill\");
  14968.           const favoriteIconClass = isFavorite ? \"bi-heart-fill\" : \"bi-heart\";
  14969.           const favoriteIconColor = isFavorite ? \"#f56040\" : \"white\";
  14970.           const favoriteTooltip = isFavorite
  14971.             ? \"Retirer des favoris\"
  14972.             : \"Ajouter aux favoris\";
  14973.           // Update the favorite button
  14974.           const \$favoriteBtn = \$(\".mfp-favorite .favorite-btn\");
  14975.           \$favoriteBtn.data(\"id\", imageId);
  14976.           \$favoriteBtn.data(\"sejour-id\", sejourId);
  14977.           \$favoriteBtn.data(\"path\", imagePath);
  14978.           \$favoriteBtn.data(\"description\", imageDesc);
  14979.           \$favoriteBtn.attr(\"title\", favoriteTooltip);
  14980.           \$favoriteBtn
  14981.             .find(\"i\")
  14982.             .removeClass(\"bi-heart bi-heart-fill\")
  14983.             .addClass(favoriteIconClass)
  14984.             .css(\"color\", favoriteIconColor);
  14985.         }
  14986.       }
  14987.       function updateZoomButtonState() {
  14988.         const zoomLevels = [1, 1.5, 2];
  14989.         const currentZoom = zoomLevels[zoomCounter];
  14990.         \$(\".zoom-in\").prop(\"disabled\", currentZoom === 2);
  14991.         \$(\".zoom-out\").prop(\"disabled\", currentZoom === 1);
  14992.       }
  14993.       function updateCounter() {
  14994.         const counterText = \$(\".mfp-counter\")
  14995.           .closest(\".mfp-content\")
  14996.           .find(\".mfp-counter\")
  14997.           .text();
  14998.         const matches = counterText.match(/(\\d+) of (\\d+)/);
  14999.         if (matches) {
  15000.           const currentIndex = matches[1];
  15001.           const totalImages = matches[2];
  15002.           \$(\".mfp-counter\").text(`\${currentIndex} of \${totalImages}`);
  15003.         }
  15004.       }
  15005.       // Add CSS for the favorite button and rounded image corners
  15006.       \$(\"<style>\")
  15007.         .prop(\"type\", \"text/css\")
  15008.         .html(
  15009.           `
  15010.       .mfp-favorite {
  15011.         position: absolute;
  15012.         top: 15px;
  15013.         left: 15px;
  15014.         z-index: 1046;
  15015.       }
  15016.       .favorite-btn {
  15017.         background: transparent;
  15018.         border: none;
  15019.         font-size: 24px;
  15020.         padding: 5px;
  15021.         cursor: pointer;
  15022.         outline: none;
  15023.       }
  15024.       .favorite-btn i {
  15025.         transition: all 0.3s ease;
  15026.       }
  15027.       .favorite-btn:hover i {
  15028.         transform: scale(1.2);
  15029.       }
  15030.       /* Rounded corners for zoomed images */
  15031.       .mfp-img {
  15032.         border-radius: 8px;
  15033.       }
  15034.       /* Make sure the container doesn't clip the rounded corners */
  15035.       .mfp-figure:after {
  15036.         border-radius: 8px;
  15037.       }
  15038.     `
  15039.         )
  15040.         .appendTo(\"head\");
  15041.     });
  15042.   </script>
  15043. <script>
  15044. document.addEventListener('DOMContentLoaded', function () {
  15045.   const openBtn = document.getElementById('openFavoritesBtn');
  15046.   const closeBtn = document.getElementById('closeSidebarBtn');
  15047.   const sidebar = document.getElementById('favoritesSidebar');
  15048.   const tbody = document.querySelector('#favoritesTable tbody');
  15049.   openBtn.addEventListener('click', async () => {
  15050.     try {
  15051.       const response = await fetch('/Parent/mes-favoris', {
  15052.         headers: {
  15053.           'Accept': 'application/json'
  15054.         }
  15055.       });
  15056.       const result = await response.json();
  15057.       if (!result.success || !Array.isArray(result.data)) {
  15058.         alert('Erreur lors du chargement des favoris.');
  15059.         return;
  15060.       }
  15061.       tbody.innerHTML = '';
  15062.       result.data.forEach((fav, index) => {
  15063.         const row = document.createElement('tr');
  15064.         row.innerHTML = `
  15065.           <td>\${index + 1}</td>
  15066.           <td><img src=\"\${fav.path}\" alt=\"favori\"></td>
  15067.           <td>\${fav.descreption || '—'}</td>
  15068.           <td>\${fav.created_at}</td>
  15069.         `;
  15070.         tbody.appendChild(row);
  15071.       });
  15072.       sidebar.classList.add('active');
  15073.     } catch (e) {
  15074.       console.error('Erreur réseau:', e);
  15075.       alert('Impossible de charger les favoris.');
  15076.     }
  15077.   });
  15078.   closeBtn.addEventListener('click', () => {
  15079.     sidebar.classList.remove('active');
  15080.   });
  15081. });
  15082. </script>
  15083.   <script>
  15084.         // Fonction pour vérifier et afficher l'alerte
  15085.         function checkFavoritesAlert() {
  15086.             const currentCount = window.favoriteCount || 0;
  15087.             if (currentCount >= 10) {
  15088.                 const purchaseAlert = document.getElementById('purchase-alert');
  15089.                 if (purchaseAlert) {
  15090.                     purchaseAlert.style.display = 'block'; // Affiche l'alerte
  15091.                 }
  15092.             } else {
  15093.                 purchaseAlert.style.display = 'none'; // Cache l'alerte si le nombre est réduit
  15094.             }
  15095.         }
  15096.     
  15097.         
  15098.         document.addEventListener('DOMContentLoaded', () => {
  15099.     const favoriteCount = {{ nblikes }};
  15100.     updateCardContent(favoriteCount);
  15101. });
  15102. function updateCardContent(favoriteCount) {
  15103.     const card = document.getElementById('dynamic-card');
  15104.     const cardContent = document.getElementById('dynamic-card-content');
  15105.     let produits = [];
  15106.     if (favoriteCount >= 20) {
  15107.         produits.push({
  15108.             titre: \"Album débloqué !\",
  15109.             bouton: \"Commander\",
  15110.             image: \"/images/produit/Album5sur5-3.jpg\",
  15111.             lien: \"{{ path('EditionAlbum') }}\"
  15112.         });
  15113.     }
  15114.     if (favoriteCount >= 12) {
  15115.         produits.push({
  15116.             titre: \"Pochette débloquée !\",
  15117.             bouton: \"Commander\",
  15118.             image: \"/images/produit/PochettePhoto5sur5-2.jpg\",
  15119.             lien: \"{{ path('AjoutPochettePhotos_Favoris', {'nbr': 12}) }}\"
  15120.         });
  15121.     }
  15122.     if (favoriteCount >= 5) {
  15123.         produits.push({
  15124.             titre: \"Pack numérique débloqué !\",
  15125.             bouton: \"Commander\",
  15126.             image: \"/images/produit/photoNumerique.jpg\",
  15127.             lien: \"{{ path('PackPhotosNumerique_Favoris', {'nbr': 15}) }}\"
  15128.         });
  15129.     }
  15130. if (produits.length === 0) {
  15131.   cardContent.innerHTML = `
  15132.     <div style=\"position: relative; width: 100%; height: 140px; border-radius: 15px; overflow: hidden; box-shadow: 0 4px 10px rgba(0,0,0,0.1);\">
  15133.       <div style=\"background-image: url('/images/produit/CoffretCadeau5sur5-2.jpg'); background-size: cover; background-position: center; width: 100%; height: 100%;\">
  15134.         <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;\">
  15135.           <div style=\"
  15136.     margin-top: 35px;
  15137.     color: white;
  15138.     font-size: 15px;
  15139.     font-weight: bold;
  15140.     text-align: center;
  15141.     line-height: 1;
  15142.     text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);\">
  15143.             Ajoutez des favoris ❤️<br><span style=\"font-size: 16px; font-weight: normal;\">pour débloquer un souvenir à offrir 🎁</span>
  15144.           </div>
  15145.         </div>
  15146.       </div>
  15147.     </div>
  15148.   `;
  15149.         return;
  15150.     }
  15151.     cardContent.innerHTML = `
  15152.     <div class=\"splide\" id=\"dynamicSplide\">
  15153.       <div class=\"splide__track\">
  15154.         <ul class=\"splide__list\">
  15155.           \${produits.map(produit => `
  15156.             <li class=\"splide__slide\" style=\"position: relative;\">
  15157.               <img src=\"\${produit.image}\" alt=\"\${produit.titre}\" style=\"width: 100%; height: 150px; object-fit: cover; border-radius: 8px;\">
  15158.               <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;\">
  15159.                 <div style=\"font-weight: bold; font-size: 14px;\">\${produit.titre}</div>
  15160.                 <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}'\">
  15161.                   \${produit.bouton}
  15162.                 </button>
  15163.               </div>
  15164.             </li>
  15165.           `).join('')}
  15166.         </ul>
  15167.       </div>
  15168.     </div>
  15169.     `;
  15170.     // Monte le carrousel
  15171.     new Splide('#dynamicSplide', {
  15172.         type: 'loop',
  15173.         arrows: true,
  15174.         pagination: false,
  15175.         autoplay: true,
  15176.         interval: 4000,
  15177.         speed: 800,
  15178.     }).mount();
  15179. }
  15180.         // Fonction helper pour lire le compteur de favoris (gère les badges premium)
  15181.         function getFavorisCount() {
  15182.             const mesFavCount = document.getElementById('mesFavCount');
  15183.             if (!mesFavCount) return 0;
  15184.             
  15185.             const badge = mesFavCount.querySelector('.premium-5sur5-badge');
  15186.             if (badge) {
  15187.                 return parseInt(badge.textContent.trim() || '0');
  15188.             }
  15189.             
  15190.             const countText = mesFavCount.textContent.trim();
  15191.             if (countText === 'Pas de favoris' || countText.includes('Pas de favoris')) {
  15192.                 return 0;
  15193.             }
  15194.             
  15195.             return parseInt(countText || '0');
  15196.         }
  15197.         // Fonction helper pour mettre à jour l'affichage du compteur de favoris
  15198.         function updateFavorisDisplay(count) {
  15199.             const mesFavCount = document.getElementById('mesFavCount');
  15200.             const favorisBtn = document.querySelector('.mtb-btn[data-filter=\"favoris\"]');
  15201.             const favorisIcon = favorisBtn?.querySelector('i.bi-heart-fill');
  15202.             
  15203.             if (!mesFavCount || !favorisBtn) return;
  15204.             
  15205.             if (count === 0) {
  15206.                 // Afficher \"Pas de favoris\" au lieu de \"0\" avec style premium
  15207.                 mesFavCount.innerHTML = '<span class=\"favoris-empty-text\" style=\"color: #94a3b8; font-style: italic; font-size: 11px;\">Pas de favoris</span>';
  15208.                 favorisBtn.classList.add('favoris-empty');
  15209.                 favorisBtn.disabled = true;
  15210.                 favorisBtn.title = \"Pas de favoris pour l'instant\";
  15211.                 if (favorisIcon) {
  15212.                     favorisIcon.style.color = '#cbd5e1';
  15213.                 }
  15214.             } else {
  15215.                 // Afficher le badge premium avec le nombre
  15216.                 mesFavCount.innerHTML = `<span class=\"premium-5sur5-badge\" style=\"background: rgba(245, 96, 64, 0.1); color: #F56040; font-size: 10px; padding: 2px 6px;\">\${count}</span>`;
  15217.                 favorisBtn.classList.remove('favoris-empty');
  15218.                 favorisBtn.disabled = false;
  15219.                 favorisBtn.title = \"Mes favoris\";
  15220.                 if (favorisIcon) {
  15221.                     favorisIcon.style.color = '#f56040';
  15222.                 }
  15223.             }
  15224.         }
  15225.         function supprimerFavoris(\$id, \$idSejour) {
  15226.             // 🚨 LOG CRITIQUE : Tracer TOUS les appels à supprimerFavoris
  15227.             console.error('🚨🚨🚨 supprimerFavoris() APPELÉ ! 🚨🚨🚨', {
  15228.                 id: \$id,
  15229.                 idSejour: \$idSejour,
  15230.                 stack: new Error().stack,
  15231.                 mesFavCountAvant: document.getElementById('mesFavCount')?.textContent
  15232.             });
  15233.             
  15234.             // Vider l'élément coeur pour ce favori
  15235.             const coeurElement = \$('#coeur' + \$id);
  15236.             coeurElement.empty();
  15237.             // Ajout d'une animation sur le bouton cadeau
  15238.             const giftButton = document.querySelector('.gift-button');
  15239.             if (giftButton) {
  15240.                 giftButton.classList.add('active');
  15241.                 // Retirer l'animation après qu'elle soit jouée
  15242.                 setTimeout(() => {
  15243.                     giftButton.classList.remove('active');
  15244.                 }, 600); // La durée doit correspondre à celle de l'animation
  15245.             }
  15246.             // Mise à jour de l'icône coeur
  15247.             const clas = \$('.IconImag6').hasClass('active') ? \"IconDelete IconDeletesix\" : \"IconDelete\";
  15248.             coeurElement.html(
  15249.                 `<i class=\"bi bi-heart \${clas}\" ></i>`
  15250.             );
  15251.             // METTRE À JOUR UNIQUEMENT #mesFavCount (source unique de vérité)
  15252.             // L'observer se chargera de synchroniser giftCount automatiquement
  15253.             const mesFavCount = document.getElementById('mesFavCount');
  15254.             if (mesFavCount) {
  15255.                 let currentCount = getFavorisCount();
  15256.                 currentCount = Math.max(0, currentCount - 1); // Empêche d'aller en dessous de 0
  15257.                 updateFavorisDisplay(currentCount);
  15258.                 console.log('[supprimerFavoris] ✅ mesFavCount décrémenté:', currentCount);
  15259.                 
  15260.                 // L'observer MutationObserver va automatiquement :
  15261.                 // - Synchroniser giftCount
  15262.                 // - Mettre à jour le sidebar
  15263.                 // - Mettre à jour product-suggestions
  15264.             }
  15265.             // Préparation des données pour l'Ajax
  15266.             const \$_data = { 'id': \$id, 'idSejour': \$idSejour };
  15267.             // Appel Ajax pour supprimer le favori
  15268.             \$.ajax({
  15269.                 type: \"POST\",
  15270.                 url: \"{{ path('Supprimer_fav') }}\",
  15271.                 data: \$_data,
  15272.                 success: function () {
  15273.                     // Réactiver les icônes après succès
  15274.                     \$('.IconDelete').each(function () {
  15275.                         \$(this).css('pointer-events', '');
  15276.                     });
  15277.                     
  15278.                     // Mettre à jour l'alerte avec le nouveau nombre
  15279.                     const finalCount = getCurrentFavoriteCount();
  15280.                     if (typeof updatePurchaseAlert === 'function') {
  15281.                         updatePurchaseAlert(finalCount);
  15282.                     }
  15283.                 },
  15284.                 error: function (xhr, status, error) {
  15285.                     console.error('Erreur lors de la suppression du favori :', error);
  15286.                 }
  15287.             });
  15288.         }
  15289.         function AddFavoris(\$id, \$idSejour, \$urlimg, \$description) {
  15290.             // 🟢 LOG : Tracer les ajouts de favoris
  15291.             console.log('🟢 AddFavoris() APPELÉ', {
  15292.                 id: \$id,
  15293.                 idSejour: \$idSejour,
  15294.                 mesFavCountAvant: document.getElementById('mesFavCount')?.textContent
  15295.             });
  15296.             
  15297.             // Update heart icon
  15298.             \$('#coeur' + \$id).empty();
  15299.             var clas = \$('.IconImag6').hasClass('active') ? \"IconDelete IconDeletesix\" : \"IconDelete\";
  15300.             \$('#coeur' + \$id).html(\"<i class=\\\"bi bi-heart-fill favSelect \" + clas + \"\\\" )\\\"></i>\");
  15301.             
  15302.             // METTRE À JOUR UNIQUEMENT #mesFavCount (source unique de vérité)
  15303.             // L'observer se chargera de synchroniser giftCount automatiquement
  15304.             const mesFavCount = document.getElementById('mesFavCount');
  15305.             if (mesFavCount) {
  15306.                 let currentCount = getFavorisCount();
  15307.                 currentCount++;
  15308.                 updateFavorisDisplay(currentCount);
  15309.                 console.log('[AddFavoris] ✅ mesFavCount incrémenté:', currentCount);
  15310.                 
  15311.                 // L'observer MutationObserver va automatiquement :
  15312.                 // - Synchroniser giftCount
  15313.                 // - Mettre à jour le sidebar
  15314.                 // - Mettre à jour product-suggestions
  15315.             }
  15316.             
  15317.             // Update other counters
  15318.             var \$total = parseInt(\$(\"#totalLike\").html()) + 1;
  15319.             \$(\"#totalLike\").html(\$total);
  15320.             \$(\"#totalLikeTitle\").html(\$total);
  15321.             \$(\"#totalLikeMobile\").html(\$total);
  15322.             
  15323.             // Add gift button animation
  15324.             const giftButton = document.querySelector('.gift-button');
  15325.             if (giftButton) {
  15326.                 giftButton.classList.add('active');
  15327.                 setTimeout(() => {
  15328.                     giftButton.classList.remove('active');
  15329.                 }, 600);
  15330.             }
  15331.             var \$data = { 'id': \$id, 'idSejour': \$idSejour };
  15332.             \$.ajax({
  15333.                 type: \"POST\",
  15334.                 url: \"{{ path('Ajouter_fav') }}\",
  15335.                 data: \$data,
  15336.                 success: function () {
  15337.                     \$('.IconDelete').each(function () {
  15338.                         \$(this).css('pointer-events', '');
  15339.                     });
  15340.                     if (\$description === undefined) {
  15341.                         \$description = ''; // Set it to an empty string
  15342.                     }
  15343.                     \$('.rowMaselection').append(
  15344.                         '<div class=\"column\" id=\"column-' + \$id + '\">'+
  15345.                         '<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>'+
  15346.                         '<a class=\"photo-zoom\">'+
  15347.                         '<img data-idAtach=\"'+\$id+'\" id=\"'+\$idSejour+'\" src=\"'+\$urlimg+'\"></a>'+
  15348.                         (\$description ? '<h4 id=\"commint\" class=\"titleHeadPhoto\">'+\$description+'</h4>' : '')+ // Only add the <h4> if \$description is not empty
  15349.                         '</div>'
  15350.                     );
  15351.                     // Directly update nbLikes count in the header
  15352.                     var currentNbLikes = parseInt(\$('#favoris-link-Accueilpayment .nbrpanier').text());
  15353.                     var newNbLikes = currentNbLikes + 1;
  15354.                     \$('#favoris-link-Accueilpayment .nbrpanier').text(newNbLikes);
  15355.                     
  15356.                     // Mettre à jour l'alerte avec le nouveau nombre
  15357.                     const finalCount = getCurrentFavoriteCount();
  15358.                     if (typeof updatePurchaseAlert === 'function') {
  15359.                         updatePurchaseAlert(finalCount);
  15360.                     }
  15361.                 },
  15362.                 error: function (xhr, status, error) {
  15363.                     console.error('Error:', error);
  15364.                 }
  15365.             });
  15366.         }
  15367.         \$(document).on('click', '.bi-heart, .bi-heart-fill', function (e) {
  15368.         const heartIcon       = \$(this);
  15369.         
  15370.         // 🛡️ PROTECTION : Ignorer les clics sur le bouton favoris de la toolbar
  15371.         // Ce bouton sert uniquement à FILTRER, pas à ajouter/supprimer des favoris
  15372.         if (heartIcon.closest('.mtb-btn').length > 0) {
  15373.             console.log('💗 Clic sur bouton toolbar favoris ignoré (gestion séparée)');
  15374.             return; // Ne rien faire, c'est géré par le listener de la toolbar
  15375.         }
  15376.         
  15377.         const heartContainer  = heartIcon.closest('.heart-icon');
  15378.         // Extract data attributes
  15379.         const attachmentId    = heartContainer.data('id');
  15380.         const sejourId        = heartContainer.data('sejour-id');
  15381.         const path            = heartContainer.data('path');
  15382.         const description     = heartContainer.data('description');
  15383.         const isFavorite      = heartIcon.hasClass('bi-heart-fill');
  15384.         if (isFavorite) {
  15385.             // Remove from favorites
  15386.             supprimerFavoris(attachmentId, sejourId);
  15387.         } else {
  15388.             // Add to favorites
  15389.             AddFavoris(attachmentId, sejourId, path, description);
  15390.         }
  15391.         // Update UI components after the action (sans double comptage)
  15392.         setTimeout(function() {
  15393.             const likeCountLabel = document.getElementById('likeCount');
  15394.             
  15395.             if (likeCountLabel) {
  15396.                 const currentCount = parseInt(likeCountLabel.textContent, 10) || 0;
  15397.                 
  15398.                 // Update UI components seulement
  15399.                 updateCardContent(currentCount);
  15400.                 updateFavoritesSidebar();
  15401.                 \$(\"#close-favorites-btn\").click();
  15402.                 
  15403.                 // 🎯 Product suggestions sont mis à jour automatiquement par le MutationObserver
  15404.                 // dans parent-toasts.js qui observe #mesFavCount
  15405.                 // updateProductSuggestionsLive(currentCount); // ← SUPPRIMÉ (doublon)
  15406.             }
  15407.         }, 50);
  15408.     });
  15409.         // Ajoutez les événements sur les icônes de cœur
  15410.         document.querySelectorAll('.IconDelete').forEach((icon) => {
  15411.             icon.addEventListener('click', (event) => {
  15412.                 const isFavorite = icon && icon.classList && icon.classList.contains('bi-heart-fill');
  15413.                 if (isFavorite) {
  15414.                     removeFavorite();
  15415.                     if (icon.classList) {
  15416.                       icon.classList.remove('bi-heart-fill');
  15417.                       icon.classList.add('bi-heart');
  15418.                     }
  15419.                 } else {
  15420.                     addFavorite();
  15421.                     if (icon.classList) {
  15422.                       icon.classList.remove('bi-heart');
  15423.                       icon.classList.add('bi-heart-fill');
  15424.                     }
  15425.                 }
  15426.             });
  15427.         });
  15428.         // Vérifie l'état initial
  15429.         checkFavoritesAlert();
  15430.         
  15431.         
  15432.         // ⚡ OPTIMISÉ: Réduction du délai d'initialisation
  15433.       
  15434.   </script>
  15435.   <!-- Initialisation -->
  15436.   <script>
  15437.     // ⚡ OPTIMISATION: Différer l'initialisation d'AOS pour ne pas bloquer le chargement
  15438.     setTimeout(function() {
  15439.       AOS.init({
  15440.         duration: 800,
  15441.         easing: \"ease-in-out\"
  15442.       });
  15443.     }, 100);
  15444.     // 🎯 DAY FILTER DROPDOWN LOGIC (Senior UX)
  15445.     document.addEventListener('DOMContentLoaded', function() {
  15446.       initializeDayFilters();
  15447.       
  15448.       // Initialiser le compteur audio avec la valeur correcte
  15449.       setTimeout(function() {
  15450.         updateAudioButtonState('days');
  15451.       }, 500);
  15452.     });
  15453.     function initializeDayFilters() {
  15454.       const dropdowns = document.querySelectorAll('.day-filter-dropdown');
  15455.       
  15456.       dropdowns.forEach(dropdown => {
  15457.         const toggle = dropdown.querySelector('.filter-toggle');
  15458.         const menu = dropdown.querySelector('.filter-dropdown-menu');
  15459.         const options = dropdown.querySelectorAll('.filter-option');
  15460.         const dayIndex = dropdown.dataset.dayIndex;
  15461.         const dayContainer = document.getElementById(`demP\${dayIndex}`);
  15462.         
  15463.         if (!toggle || !menu || !dayContainer) return;
  15464.         
  15465.         // Calculer et mettre à jour les compteurs initiaux
  15466.         updateDayFilterCounts(dropdown, dayContainer);
  15467.         
  15468.         // Toggle dropdown
  15469.         toggle.addEventListener('click', (e) => {
  15470.           e.stopPropagation();
  15471.           const isOpen = dropdown.classList.contains('open');
  15472.           
  15473.           // Fermer tous les autres dropdowns
  15474.           document.querySelectorAll('.day-filter-dropdown.open').forEach(d => {
  15475.             if (d !== dropdown) d.classList.remove('open');
  15476.           });
  15477.           
  15478.           // Toggle le dropdown actuel
  15479.           dropdown.classList.toggle('open', !isOpen);
  15480.         });
  15481.         
  15482.         // Gérer les clics sur les options
  15483.         options.forEach(option => {
  15484.           option.addEventListener('click', (e) => {
  15485.             e.stopPropagation();
  15486.             const filter = option.dataset.filter;
  15487.             
  15488.             // Mettre à jour l'état actif
  15489.             options.forEach(opt => opt.classList.remove('active'));
  15490.             option.classList.add('active');
  15491.             
  15492.             // Appliquer le filtre
  15493.             applyDayFilter(dayContainer, filter);
  15494.             
  15495.             // Fermer le dropdown
  15496.             dropdown.classList.remove('open');
  15497.           });
  15498.         });
  15499.       });
  15500.       
  15501.       // Fermer les dropdowns en cliquant ailleurs
  15502.       document.addEventListener('click', () => {
  15503.         document.querySelectorAll('.day-filter-dropdown.open').forEach(dropdown => {
  15504.           dropdown.classList.remove('open');
  15505.         });
  15506.       });
  15507.     }
  15508.     function updateDayFilterCounts(dropdown, dayContainer) {
  15509.       const photoItems = dayContainer.querySelectorAll('[data-type=\"photo\"]');
  15510.       const videoItems = dayContainer.querySelectorAll('[data-type=\"video\"]');
  15511.       // Compter les messages audio individuels plutôt que les conteneurs
  15512.       const audioMessageItems = dayContainer.querySelectorAll('.audio-message-item[data-type=\"audio\"]');
  15513.       const audioContainers = dayContainer.querySelectorAll('.audio-messages-container[data-type=\"audio\"]');
  15514.       const audioRestricted = dayContainer.querySelectorAll('.audio-messages-restricted[data-type=\"audio\"]');
  15515.       
  15516.       const allItems = dayContainer.querySelectorAll('[data-type]');
  15517.       
  15518.       const countAll = dropdown.querySelector('[data-count-all]');
  15519.       const countPhoto = dropdown.querySelector('[data-count-photo]');
  15520.       const countVideo = dropdown.querySelector('[data-count-video]');
  15521.       const countAudio = dropdown.querySelector('[data-count-audio]');
  15522.       
  15523.       // Compter les messages audio individuels + conteneurs + sections restreintes
  15524.       const totalAudio = audioMessageItems.length + audioContainers.length + audioRestricted.length;
  15525.       
  15526.       if (countAll) countAll.textContent = allItems.length;
  15527.       if (countPhoto) countPhoto.textContent = photoItems.length;
  15528.       if (countVideo) countVideo.textContent = videoItems.length;
  15529.       if (countAudio) countAudio.textContent = totalAudio;
  15530.       
  15531.       // Masquer les options sans contenu
  15532.       const photoOption = dropdown.querySelector('[data-filter=\"photo\"]');
  15533.       const videoOption = dropdown.querySelector('[data-filter=\"video\"]');
  15534.       const audioOption = dropdown.querySelector('[data-filter=\"audio\"]');
  15535.       
  15536.       if (photoOption) photoOption.style.display = photoItems.length > 0 ? 'flex' : 'none';
  15537.       if (videoOption) videoOption.style.display = videoItems.length > 0 ? 'flex' : 'none';
  15538.       if (audioOption) audioOption.style.display = totalAudio > 0 ? 'flex' : 'none';
  15539.     }
  15540.     function applyDayFilter(dayContainer, filter) {
  15541.       const items = dayContainer.querySelectorAll('[data-type]');
  15542.       
  15543.       items.forEach(item => {
  15544.         if (filter === 'all' || item.dataset.type === filter) {
  15545.           item.style.display = '';
  15546.           item.classList.remove('filtered-out');
  15547.         } else {
  15548.           item.style.display = 'none';
  15549.           item.classList.add('filtered-out');
  15550.         }
  15551.       });
  15552.       
  15553.       // Animation fluide pour les éléments visibles
  15554.       requestAnimationFrame(() => {
  15555.         const visibleItems = dayContainer.querySelectorAll('[data-type]:not(.filtered-out)');
  15556.         visibleItems.forEach((item, index) => {
  15557.           item.style.animation = `fadeInUp 0.3s ease forwards \${index * 0.05}s`;
  15558.         });
  15559.       });
  15560.     }
  15561.     // Animation CSS pour fadeInUp
  15562.     if (!document.querySelector('#dayFilterAnimations')) {
  15563.       const style = document.createElement('style');
  15564.       style.id = 'dayFilterAnimations';
  15565.       style.textContent = `
  15566.         @keyframes fadeInUp {
  15567.           from {
  15568.             opacity: 0;
  15569.             transform: translateY(20px);
  15570.           }
  15571.           to {
  15572.             opacity: 1;
  15573.             transform: translateY(0);
  15574.           }
  15575.         }
  15576.       `;
  15577.       document.head.appendChild(style);
  15578.     }
  15579.     document.addEventListener(\"DOMContentLoaded\", function () {
  15580.       const dateCards = document.querySelectorAll(\".date-card\");
  15581.       const sections = document.querySelectorAll(\".collapse\");
  15582.       dateCards.forEach((card) => {
  15583.         card.addEventListener(\"click\", function () {
  15584.           // Supprimer les classes actives des autres cartes et sections
  15585.           dateCards.forEach((c) => c.classList.remove(\"active\"));
  15586.           sections.forEach((s) => s.classList.remove(\"show\"));
  15587.           // Ajouter la classe active à la carte cliquée
  15588.           this.classList.add(\"active\");
  15589.           // Récupérer la cible et afficher la bonne section
  15590.           const targetId = this.getAttribute(\"data-bs-target\");
  15591.           const targetSection = document.querySelector(targetId);
  15592.           if (targetSection) {
  15593.             targetSection.classList.add(\"show\");
  15594.           }
  15595.         });
  15596.       });
  15597.     });
  15598.     document.addEventListener(\"DOMContentLoaded\", function () {
  15599.       // Initialisation du carrousel Splide
  15600.       var splide = new Splide(\"#imageSlider\", {
  15601.         type: \"loop\",
  15602.         perPage: 1,
  15603.         autoplay: true,
  15604.         interval: 6000,
  15605.         pauseOnHover: false,
  15606.         pauseOnFocus: false,
  15607.         pagination: false,
  15608.         arrows: false,
  15609.       });
  15610.       splide.mount();
  15611.       // ⚠️ Scroll automatique désactivé pour meilleure UX
  15612.       // Les utilisateurs peuvent défiler manuellement quand ils le souhaitent
  15613.     });
  15614.   </script>
  15615.   <script>
  15616.    
  15617.     const giftButton = document.querySelector('.gift-button');
  15618.     if (giftButton) {
  15619.         giftButton.addEventListener('click', () => {
  15620.         // Ajouter la classe 'active' pour déclencher l'éclat
  15621.             giftButton.classList.add('active');
  15622.         // Retirer l'animation après qu'elle soit jouée
  15623.         setTimeout(() => {
  15624.                 giftButton.classList.remove('active');
  15625.         }, 600); // La durée doit correspondre à celle de l'animation
  15626.             
  15627.             // Optionnel : rediriger vers la page de commande
  15628.             // window.location.href = '/commande';
  15629.     });
  15630.     }
  15631.     
  15632.     //const HeartAddButton = document.querySelector('.IconDelete');
  15633.     \$(\".IconDelete\").on('click', () => {
  15634.         // Ajouter la classe 'active' pour déclencher l'éclat
  15635.         favoriteButton.classList.add('active');
  15636.         // Retirer l'animation après qu'elle soit jouée
  15637.         setTimeout(() => {
  15638.             favoriteButton.classList.remove('active');
  15639.         }, 600); // La durée doit correspondre à celle de l'animation
  15640.     });
  15641.     \$(document).ready(function() {
  15642.         // Attach click event to collapse triggers
  15643.         const lastCard = \$('.date-card.modern-card.active');
  15644.         const lastTargetId = lastCard.attr('data-bs-target');
  15645.         if (lastTargetId) {
  15646.             \$(lastTargetId).collapse('show'); // Expand the last collapse section
  15647.             LoadImagesCloud(\$(lastTargetId)); // Load images for the last day
  15648.         }
  15649.         \$('[data-bs-toggle=\"collapse\"]').on('click', function() {
  15650.             var targetId = \$(this).attr('data-bs-target'); // Get the target ID
  15651.             \$('.date-card.modern-card').removeClass('active'); // Remove 'active' class from all cards
  15652.             \$(this).addClass('active'); // Add 'active' class to the clicked card
  15653.             LoadImagesCloud(\$(targetId)); // Ensure this function works as expected
  15654.                // Hide all other collapses except the one clicked
  15655.                \$('[data-bs-target]').each(function() {
  15656.                 var currentTargetId = \$(this).attr('data-bs-target');
  15657.                 // If the current collapse is not the one clicked, hide it
  15658.                 if (currentTargetId !== targetId) {
  15659.                     \$(currentTargetId).collapse('hide');
  15660.                     //\$('[data-bs-toggle=\"collapse\"]').removeClass('active'); // Remove active class from all cards
  15661.                     //Modifier leurs style en non active aussi
  15662.                 }
  15663.             });
  15664.         });
  15665.     });
  15666.   
  15667.             \$(document).ready(function () {
  15668.               
  15669.                 {% if app.session.get(\"paymentmoniteco\") %}
  15670.                 {% if app.session.get(\"paymentmoniteco\") == \"succses\" %}
  15671.                 Swal.fire({
  15672.                     icon: 'success',
  15673.                     title: ' succès ',
  15674.                     text: 'votre commande est validée'
  15675.                 });
  15676.                 {% endif %}
  15677.                 {% endif %}
  15678.                 if (\$total1 > 0) {
  15679.                     \$('.iconeFleche').first().click();
  15680.                     //  \$([document.documentElement, document.body]).animate({
  15681.                     //  scrollTop: \$('.iconeFleche').last().offset().top
  15682.                     //  }, );
  15683.                 }
  15684.                 else {
  15685.                     \$(window).scrollTop(0);
  15686.                 }
  15687.                 var slider = \$('.responsive').slick({
  15688.                     infinite: true,
  15689.                     slidesToShow: 1,
  15690.                     slidesToScroll: 1,
  15691.                     autoplay: true,
  15692.                     autoplaySpeed: 4000,
  15693.                     pauseOnFocus: false,
  15694.                     pauseOnHover: false,
  15695.                     draggable: false,
  15696.                     fade: true
  15697.                 });
  15698.                 \$('.responsive').css('display', 'block');
  15699.                 \$('.namePRD').css('display', 'block');
  15700.                 var currSlide = 0;
  15701.                 var nextSlide = 0;
  15702.                 slider.on('afterChange', function (event, slick, currentSlide) {
  15703.                     console.log(typeof (\$('.slick-active .slick-current').find('.imgproduit2')) != \"undefined\");
  15704.                     if (typeof (\$('.slick-active .slick-current').find('.imgproduit2')) != \"undefined\") {
  15705.                         setTimeout(function () {
  15706.                             \$('.slick-active .imgproduit1').removeClass('animated fadeIn');
  15707.                             \$('.slick-active .imgproduit1').addClass('animated fadeOut');
  15708.                             \$('.slick-active .imgproduit1').css('display', 'none');
  15709.                             \$('.slick-active .imgproduit2').css('display', 'block');
  15710.                             \$('.slick-active .imgproduit2').removeClass('animated fadeOut');
  15711.                             \$('.slick-active .imgproduit2').addClass('animated fadeIn');
  15712.                         }, 2000);
  15713.                     }
  15714.                 });
  15715.                 slider.on('beforeChange', function (event, slick, currentSlide, nextSlide) {
  15716.                     currSlide = currentSlide;
  15717.                     \$('.imgproduit2').each(function () {
  15718.                         \$(this).removeClass('animated fadeIn');
  15719.                         \$(this).addClass('animated fadeOut');
  15720.                         \$(this).css('display', 'none');
  15721.                     });
  15722.                     \$('.imgproduit1').each(function () {
  15723.                         \$(this).css('display', 'block');
  15724.                         \$(this).removeClass('animated fadeOut');
  15725.                         \$(this).addClass('animated fadeIn');
  15726.                     });
  15727.                 });
  15728.                 \$('.columnPub').each(function () {
  15729.                     \$(this).slick({
  15730.                         infinite: true,
  15731.                         speed: 50,
  15732.                         fade: true,
  15733.                         slidesToShow: 1,
  15734.                         slidesToScroll: 1,
  15735.                         autoplay: true,
  15736.                         pauseOnFocus: false,
  15737.                         pauseOnHover: false,
  15738.                         draggable: false
  15739.                     });
  15740.                     \$(this).css('display', 'block');
  15741.                 });
  15742.                 \$(\"#offrePack\").click();
  15743.                 {%if app.user.showpubprod != 'false' %}
  15744.                 \$('#btnPubProd').click();
  15745.                 \$('.modal-backdrop').css('background-color', 'rgba(0, 0, 0, 0.2)');
  15746.                 {% endif %}
  15747.             });
  15748.             \$(\"#closeImage\").click(function () {
  15749.                 \$('#myModalImage').css('display', \"none\");
  15750.             });
  15751.             \$.ajax({
  15752.                 type: \"POST\",
  15753.                 url: \"{{ path(\"delateSession_parent\") }}\",
  15754.                 success: function () { }
  15755.             });
  15756.             function afficheDiv(elem) {
  15757.                 \$('.nav-link').each(function () {
  15758.                     \$(this).removeClass('active');
  15759.                 });
  15760.                 elem.addClass('active');
  15761.                 if (elem.attr('id') === \"esphoto\" || elem.attr('id') === \"esphotoMobile\") {
  15762.                     \$(\"#espacphoto\").show();
  15763.                     \$(\"#espacemessage\").hide();
  15764.                     \$(\"#espaceMa_selection\").hide();
  15765.                     pageMenu = 'MonSejour'
  15766.                     \$(this).addClass('active');
  15767.                    \$('#imageActifphoto').css('display', 'block');
  15768.                      \$('#imagenoActifphoto').css('display', 'none');
  15769.                    \$('#VocalActivee').css('display', 'none');
  15770.                      \$('#noActifVocal').css('display', 'block');
  15771.                 }
  15772.                 if (elem.attr('id') === \"esmessage\" || elem.attr('id') === \"esmessageMobile\") {
  15773.                     \$(\"#espacphoto\").hide();
  15774.                     \$(\"#espaceMa_selection\").hide();
  15775.                     \$(\"#espacemessage\").show();
  15776.                     pageMenu = 'BoiteVocale'
  15777.                     \$(\"#espaceMa_selection\").hide();
  15778.                     \$(this).addClass('active');
  15779.                   \$('#imageActifphoto').css('display', 'none');
  15780.                      \$('#imagenoActifphoto').css('display', 'block');
  15781.                    \$('#VocalActivee').css('display', 'block');
  15782.                      \$('#noActifVocal').css('display', 'none');
  15783.                 }
  15784.                 if (elem.attr('id') === \"esselection\" || elem.attr('id') === \"esselectionMobile\") {
  15785.                     \$(\"#espacphoto\").hide();
  15786.                     \$(\"#espacemessage\").hide();
  15787.                     \$(\"#espaceMa_selection\").show();
  15788.                     \$(homeNavmob).removeClass('bi bi-house-door-fill');
  15789.                     \$(homeNavmob).addClass('bi bi-house-door');
  15790.                     \$(micromob).removeClass('bi bi-mic-fill');
  15791.                     \$(micromob).addClass('bi bi-mic');
  15792.                     \$(selecNavmob).removeClass('bi bi-heart');
  15793.                     \$(selecNavmob).addClass('bi bi-heart-fill');
  15794.                 }
  15795.             }
  15796.             function LoadImagesCloud(\$element) {
  15797.                 \$element.find('.photo-zoom img').each(function (\$this) {
  15798.                     if (\$(this).attr('data-src') != \$(this).attr('src')) {
  15799.                         \$(this).attr('src', \$(this).attr('data-src'));
  15800.                     }
  15801.                 });
  15802.             }
  15803.   </script>
  15804.   <script>
  15805.     // ⚡ OPTIMISATION: Regroupement des initialisations jQuery
  15806.     \$(document).ready(function () {
  15807.       // Modal PubProd
  15808.       \$(\"#PubProd\").on(\"hidden.bs.modal\", function () {
  15809.         \$(document).trigger(\"modalClosed\");
  15810.       });
  15811.       
  15812.       // NoShow checkbox
  15813.       \$(\"#noShow\").on(\"change\", function () {
  15814.         if (\$(this).is(\":checked\")) {
  15815.           \$.ajax({
  15816.             url: \"/Parent/showpub\",
  15817.             type: \"POST\",
  15818.             dataType: \"json\",
  15819.             success: function (response) {
  15820.               if (response.status === \"success\") {
  15821.                 console.log(\"User showpubprod updated successfully.\");
  15822.               } else {
  15823.                 console.log(\"Error:\", response.message);
  15824.               }
  15825.             },
  15826.             error: function (xhr, status, error) {
  15827.               console.log(\"AJAX Error:\", error);
  15828.             },
  15829.           });
  15830.         }
  15831.       });
  15832.     });
  15833.   </script>
  15834. </div>
  15835. <!-- Script pour la sidebar des favoris -->
  15836. <script>
  15837.   // ⚡ OPTIMISATION: Utiliser requestIdleCallback pour ne pas bloquer le thread principal
  15838.  
  15839.   
  15840.     
  15841.     // Charger les favoris
  15842.     function loadFavorites() {
  15843.       \$.ajax({
  15844.         url: \"/Parent/mes-favoris\",
  15845.         type: \"GET\",
  15846.         dataType: \"json\",
  15847.         beforeSend: function() {
  15848.           \$(\"#favorites-grid\").html(\"<div style='text-align:center'>Chargement...</div>\");
  15849.         },
  15850.         success: function(data) {
  15851.           \$(\"#favorites-grid\").empty();
  15852.           
  15853.           if (data.data && data.data.length > 0) {
  15854.             \$(\"#favorites-empty-state\").hide();
  15855.             
  15856.             \$.each(data.data, function(i, fav) {
  15857.               var item = \$(\"<div class='favorite-item'></div>\");
  15858.               var img = \$(\"<img>\").attr(\"src\", fav.path).attr(\"alt\", fav.descreption || \"Photo favorite\");
  15859.               var overlay = \$(\"<div class='favorite-overlay'></div>\");
  15860.         
  15861.               
  15862.               btn.click(function(e) {
  15863.                 e.preventDefault();
  15864.                 e.stopPropagation();
  15865.                 removeFavorite(fav.id);
  15866.               });
  15867.               
  15868.               overlay.append(btn);
  15869.               item.append(img).append(overlay);
  15870.               \$(\"#favorites-grid\").append(item);
  15871.             });
  15872.             
  15873.             \$(\"#favorites-counter\").text(data.data.length);
  15874.             var percentage = (data.data.length / 10) * 100;
  15875.             \$(\"#favorites-progress\").css(\"width\", percentage + \"%\");
  15876.             
  15877.           } else {
  15878.             \$(\"#favorites-empty-state\").show();
  15879.             \$(\"#favorites-counter\").text(\"0\");
  15880.             \$(\"#favorites-progress\").css(\"width\", \"0%\");
  15881.           }
  15882.         },
  15883.         error: function() {
  15884.           \$(\"#favorites-grid\").html(\"<div style='color:red;text-align:center'>Erreur de chargement</div>\");
  15885.         }
  15886.       });
  15887.     }
  15888.     
  15889.     // Supprimer un favori
  15890.     function removeFavorite(id) {
  15891.       \$.ajax({
  15892.         url: \"/Parent/remove-favorite/\" + id,
  15893.         type: \"POST\",
  15894.         success: function() {
  15895.           loadFavorites();
  15896.           
  15897.           // Mettre à jour tous les compteurs de favoris
  15898.           updateAllFavoriteCounters();
  15899.         },
  15900.         error: function() {
  15901.           alert(\"Erreur lors de la suppression du favori\");
  15902.         }
  15903.       });
  15904.     }
  15905.   });
  15906. </script>
  15907. <!-- === E-COMMERCE SIDEBAR JAVASCRIPT === -->
  15908. <script>
  15909. // Configuration UX_VARIANT pour A/B testing
  15910. let UX_VARIANT = 'EMOTION'; // ou 'URGENCY'
  15911. // Variables globales e-commerce
  15912. let sejourEndDate = null; // À définir avec la vraie date de fin du séjour
  15913. // Fonction utilitaire robuste pour gérer les compteurs de favoris
  15914. window.getFavoriteCount = function getFavoriteCount() {
  15915.   const likeCountInput = document.getElementById('likeCount');
  15916.   if (likeCountInput) {
  15917.     // Priorité à la valeur de l'input
  15918.     const value = likeCountInput.value || likeCountInput.textContent || 0;
  15919.     return parseInt(value, 10) || 0;
  15920.   }
  15921.   
  15922.   // Fallback sur giftCount
  15923.   const giftCount = document.getElementById('giftCount');
  15924.   if (giftCount && giftCount.textContent) {
  15925.     return parseInt(giftCount.textContent.trim(), 10) || 0;
  15926.   }
  15927.   
  15928.   return 0;
  15929. };
  15930. window.setFavoriteCount = function setFavoriteCount(count) {
  15931.   const likeCountInput = document.getElementById('likeCount');
  15932.   if (likeCountInput) {
  15933.     // Mettre à jour les deux propriétés pour être sûr
  15934.     likeCountInput.value = count;
  15935.     likeCountInput.textContent = count;
  15936.   }
  15937.   
  15938.   // Mettre à jour les autres compteurs
  15939.   const giftCount = document.getElementById('giftCount');
  15940.   if (giftCount) {
  15941.     giftCount.textContent = count;
  15942.   }
  15943.   
  15944.   const mesFavCount = document.getElementById('mesFavCount');
  15945.   if (mesFavCount) {
  15946.     mesFavCount.textContent = count;
  15947.   }
  15948.   
  15949.   // Mettre à jour l'input hidden
  15950.   const nbFavCurrentInput = document.getElementById('nbFavCurrent');
  15951.   if (nbFavCurrentInput) {
  15952.     nbFavCurrentInput.value = count;
  15953.   }
  15954. };
  15955. // Fonction pour définir la date de fin du séjour
  15956. window.setSejourEndDate = function setSejourEndDate(dateString) {
  15957.   sejourEndDate = dateString;
  15958.   console.log('🎯 Sejour end date set to:', sejourEndDate);
  15959.   
  15960.   // Mettre à jour le countdown si le sidebar est ouvert
  15961.   updateCountdownTimer();
  15962. };
  15963. // Fonctions d'ouverture/fermeture du sidebar
  15964. window.openEcommerceSidebar = function openEcommerceSidebar() {
  15965.   const sidebar = document.getElementById('ecommerce-sidebar');
  15966.   if (!sidebar) {
  15967.     console.error('❌ E-commerce sidebar element not found!');
  15968.     return false;
  15969.   }
  15970.   
  15971.   console.log('🎁 [OPEN SIDEBAR] Ouverture du sidebar e-commerce...');
  15972.   const favCount = window.getFavoriteCount ? window.getFavoriteCount() : 0;
  15973.   console.log('🎁 [OPEN SIDEBAR] Favoris actuels:', favCount);
  15974.   
  15975.   // D'abord ouvrir le sidebar pour que les éléments soient dans le DOM
  15976.   sidebar.classList.add('active');
  15977.   console.log('🎁 [OPEN SIDEBAR] Sidebar classe \"active\" ajoutée');
  15978.   
  15979.   // Puis mettre à jour le contenu (petit délai pour que le DOM soit prêt)
  15980.   setTimeout(() => {
  15981.     console.log('🎁 [OPEN SIDEBAR] Mise à jour du contenu...');
  15982.     
  15983.     // Appeler la fonction de parent-toasts.js
  15984.     if (typeof window.parentConversion !== 'undefined' && typeof window.parentConversion.updateSidebar === 'function') {
  15985.       console.log('✅ [OPEN SIDEBAR] Appel de parentConversion.updateSidebar()');
  15986.       window.parentConversion.updateSidebar();
  15987.     } else {
  15988.       console.warn('⚠️ [OPEN SIDEBAR] parent-toasts.js non disponible, fallback sur fonction locale');
  15989.       // Fallback sur la fonction locale
  15990.       if (typeof window.updateEcommerceSidebarContent === 'function') {
  15991.         window.updateEcommerceSidebarContent(favCount);
  15992.       }
  15993.     }
  15994.   }, 100); // 100ms de délai pour que le sidebar soit visible
  15995.   
  15996.   return true;
  15997. };
  15998. window.closeEcommerceSidebar = function closeEcommerceSidebar() {
  15999.   const sidebar = document.getElementById('ecommerce-sidebar');
  16000.   if (sidebar) {
  16001.     sidebar.classList.remove('active');
  16002.     console.log('🎯 E-commerce sidebar closed');
  16003.   } else {
  16004.     console.error('❌ E-commerce sidebar element not found!');
  16005.   }
  16006. };
  16007. // 🚫 FONCTION LEGACY SUPPRIMÉE - Utiliser parent-toasts.js à la place
  16008. // Cette fonction était en conflit avec updateEcommerceSidebar() de parent-toasts.js
  16009. // qui gère TOUT : titre, sous-titre, compteurs, visibilité des produits, CTA, etc.
  16010. window.updateEcommerceSidebarContent = function updateEcommerceSidebarContent(favoriteCount) {
  16011.   console.warn('[LEGACY] updateEcommerceSidebarContent appelé - Redirection vers parent-toasts.js');
  16012.   
  16013.   // Rediriger vers la vraie fonction
  16014.   if (typeof window.parentConversion !== 'undefined' && typeof window.parentConversion.updateSidebar === 'function') {
  16015.     window.parentConversion.updateSidebar();
  16016.   } else {
  16017.     console.error('[LEGACY] parent-toasts.js non disponible !');
  16018.   }
  16019. }
  16020. // 🚫 FONCTION SUPPRIMÉE - Géré par parent-toasts.js
  16021. // Tout est maintenant géré dans updateEcommerceSidebar() de parent-toasts.js
  16022. // Fonction pour gérer le countdown
  16023. window.updateCountdownTimer = function updateCountdownTimer() {
  16024.   const countdownTimer = document.getElementById('countdown-timer');
  16025.   const daysLeftSpan = document.getElementById('days-left');
  16026.   
  16027.   if (!countdownTimer || !daysLeftSpan) return;
  16028.   
  16029.   // Si pas de date définie, utiliser une date par défaut (6 semaines à partir d'aujourd'hui)
  16030.   let expirationDate;
  16031.   if (sejourEndDate) {
  16032.     const endDate = new Date(sejourEndDate);
  16033.     expirationDate = new Date(endDate.getTime() + (6 * 7 * 24 * 60 * 60 * 1000)); // +6 semaines
  16034.   } else {
  16035.     // Date par défaut : 6 semaines à partir d'aujourd'hui
  16036.     expirationDate = new Date();
  16037.     expirationDate.setDate(expirationDate.getDate() + (6 * 7));
  16038.   }
  16039.   
  16040.   const now = new Date();
  16041.   const daysLeft = Math.ceil((expirationDate - now) / (24 * 60 * 60 * 1000));
  16042.   
  16043.   if (daysLeft <= 10 && daysLeft > 0) {
  16044.     countdownTimer.style.display = 'block';
  16045.     daysLeftSpan.textContent = daysLeft;
  16046.     
  16047.     // Mettre à jour les titres avec le countdown si variante URGENCY
  16048.     if (UX_VARIANT === 'URGENCY') {
  16049.       const title = document.getElementById('ecommerce-title');
  16050.       if (title) {
  16051.         const favoriteCount = parseInt(document.getElementById('giftCount')?.textContent || '0');
  16052.         if (favoriteCount > 0) {
  16053.           if (favoriteCount < 5) {
  16054.             title.innerHTML = `⏳ \${favoriteCount} souvenirs - Plus que \${daysLeft} jours !`;
  16055.           } else if (favoriteCount < 12) {
  16056.             title.innerHTML = `⏳ \${favoriteCount} magnifiques souvenirs - Plus que \${daysLeft} jours !`;
  16057.           } else {
  16058.             title.innerHTML = `⏳ Superbe collection de \${favoriteCount} photos - Plus que \${daysLeft} jours !`;
  16059.           }
  16060.         }
  16061.       }
  16062.     }
  16063.   } else {
  16064.     countdownTimer.style.display = 'none';
  16065.   }
  16066. }
  16067. // Fonction pour commander un produit
  16068. window.orderProduct = function orderProduct(productType) {
  16069.   let favoriteCount = 0;
  16070.   
  16071.   // Méthode 1: Fonction getCurrentFavoriteCount
  16072.   try {
  16073.     if (typeof getCurrentFavoriteCount === 'function') {
  16074.       favoriteCount = getCurrentFavoriteCount();
  16075.     }
  16076.   } catch (e) {
  16077.     console.log('⚠️ getCurrentFavoriteCount non disponible:', e);
  16078.   }
  16079.   
  16080.   // Méthode 2: Element giftCount
  16081.   if (favoriteCount === 0) {
  16082.     const giftCount = document.getElementById('giftCount');
  16083.     if (giftCount && giftCount.textContent) {
  16084.       favoriteCount = parseInt(giftCount.textContent.trim()) || 0;
  16085.     }
  16086.   }
  16087.   
  16088.   // Méthode 3: Récupérer depuis les éléments qui affichent le nombre de favoris
  16089.   if (favoriteCount === 0) {
  16090.     const albumFavCount = document.getElementById('album-fav-count');
  16091.     const digitalFavCount = document.getElementById('digital-fav-count');
  16092.     
  16093.     if (albumFavCount && albumFavCount.textContent) {
  16094.       favoriteCount = parseInt(albumFavCount.textContent.trim()) || 0;
  16095.     } else if (digitalFavCount && digitalFavCount.textContent) {
  16096.       favoriteCount = parseInt(digitalFavCount.textContent.trim()) || 0;
  16097.     }
  16098.   }
  16099.   
  16100.   // Méthode 4: Variable globale likes
  16101.   if (favoriteCount === 0 && typeof likes !== 'undefined' && likes) {
  16102.     favoriteCount = likes.length || 0;
  16103.   }
  16104.   
  16105.   // Méthode 5: Compter les éléments liked dans le DOM
  16106.   if (favoriteCount === 0) {
  16107.     const likedElements = document.querySelectorAll('.liked, .photo.liked, [data-liked=\"true\"]');
  16108.     favoriteCount = likedElements.length;
  16109.   }
  16110.   
  16111.   // Debug pour voir la valeur récupérée
  16112.   console.log('🔍 Nombre de favoris détecté:', favoriteCount);
  16113.   
  16114.   if (favoriteCount === 0) {
  16115.     // Afficher une notification plus élégante
  16116.     const notification = document.createElement('div');
  16117.     notification.className = 'favorite-notification';
  16118.     notification.innerHTML = `
  16119.       <div class=\"notification-content\">
  16120.         <i class=\"bi bi-heart\" style=\"color: #e91e63; font-size: 1.5rem; margin-right: 10px;\"></i>
  16121.         <span>Veuillez d'abord sélectionner des photos favorites !</span>
  16122.         <button onclick=\"this.parentElement.parentElement.remove()\" style=\"background: none; border: none; color: #666; font-size: 1.2rem; margin-left: 10px;\">&times;</button>
  16123.       </div>
  16124.     `;
  16125.     
  16126.     // Styles pour la notification
  16127.     notification.style.cssText = `
  16128.       position: fixed;
  16129.       top: 20px;
  16130.       right: 20px;
  16131.       background: #fff;
  16132.       border: 2px solid #e91e63;
  16133.       border-radius: 8px;
  16134.       padding: 15px;
  16135.       box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  16136.       z-index: 10000;
  16137.       animation: slideInRight 0.3s ease;
  16138.     `;
  16139.     
  16140.     // Ajouter l'animation CSS si elle n'existe pas
  16141.     if (!document.getElementById('notification-styles')) {
  16142.       const style = document.createElement('style');
  16143.       style.id = 'notification-styles';
  16144.       style.textContent = `
  16145.         @keyframes slideInRight {
  16146.           from { transform: translateX(100%); opacity: 0; }
  16147.           to { transform: translateX(0); opacity: 1; }
  16148.         }
  16149.         .notification-content {
  16150.           display: flex;
  16151.           align-items: center;
  16152.         }
  16153.       `;
  16154.       document.head.appendChild(style);
  16155.     }
  16156.     
  16157.     document.body.appendChild(notification);
  16158.     
  16159.     // Supprimer automatiquement après 5 secondes
  16160.     setTimeout(() => {
  16161.       if (notification.parentElement) {
  16162.         notification.remove();
  16163.       }
  16164.     }, 5000);
  16165.     
  16166.     return;
  16167.   }
  16168.   
  16169.   // Construire l'URL avec les favoris pré-sélectionnés
  16170.   let orderUrl = '';
  16171.   
  16172.   switch (productType) {
  16173.     case 'album':
  16174.       orderUrl = `{{ path('EditionAlbum') }}?favorites=\${favoriteCount}`;
  16175.       break;
  16176.     case 'digital':
  16177.       orderUrl = `{{ path('PackPhotosNumerique_Favoris', {'nbr': 15}) }}?favorites=\${favoriteCount}`;
  16178.       break;
  16179.     case 'prints':
  16180.       orderUrl = `{{ path('AjoutPochettePhotos_Favoris', {'nbr': 12}) }}?favorites=\${favoriteCount}`;
  16181.       break;
  16182.     default:
  16183.       console.error('Type de produit non reconnu:', productType);
  16184.       alert('Erreur: Type de produit non reconnu');
  16185.       return;
  16186.   }
  16187.   
  16188.   // Analytics/tracking
  16189.   console.log('Product ordered', { productType, favoriteCount, url: orderUrl });
  16190.   
  16191.   // Redirection vers la commande
  16192.   if (orderUrl) {
  16193.     // Vérifier que l'URL est valide
  16194.     try {
  16195.       new URL(orderUrl, window.location.origin);
  16196.     window.location.href = orderUrl;
  16197.     } catch (error) {
  16198.       console.error('URL invalide générée:', orderUrl, error);
  16199.       alert('Erreur: Impossible de générer le lien de commande');
  16200.     }
  16201.   } else {
  16202.     console.error('Aucune URL générée pour le produit:', productType);
  16203.     alert('Erreur: Impossible de générer le lien de commande');
  16204.   }
  16205. }
  16206. // Fonction pour tester tous les liens de produits
  16207. window.testProductLinks = function() {
  16208.   const products = ['album', 'digital', 'prints'];
  16209.   const favoriteCount = window.getFavoriteCount() || 0;
  16210.   
  16211.   console.log('🧪 Test des liens de produits avec', favoriteCount, 'favoris');
  16212.   
  16213.   products.forEach(productType => {
  16214.     try {
  16215.       let testUrl = '';
  16216.       switch (productType) {
  16217.         case 'album':
  16218.           testUrl = `{{ path('EditionAlbum') }}?favorites=\${favoriteCount}`;
  16219.           break;
  16220.         case 'digital':
  16221.           testUrl = `{{ path('PackPhotosNumerique_Favoris', {'nbr': 15}) }}?favorites=\${favoriteCount}`;
  16222.           break;
  16223.         case 'prints':
  16224.           testUrl = `{{ path('AjoutPochettePhotos_Favoris', {'nbr': 12}) }}?favorites=\${favoriteCount}`;
  16225.           break;
  16226.       }
  16227.       
  16228.       // Vérifier que l'URL est valide
  16229.       const url = new URL(testUrl, window.location.origin);
  16230.       console.log(`✅ \${productType}: \${url.href}`);
  16231.     } catch (error) {
  16232.       console.error(`❌ \${productType}: Erreur URL`, error);
  16233.     }
  16234.   });
  16235. };
  16236. // Fonction pour valider les liens au chargement de la page
  16237. window.validateProductLinks = function() {
  16238.   // Vérifier que tous les boutons de produits existent
  16239.   const albumBtn = document.querySelector('button[onclick*=\"orderProduct(\\'album\\')\"]');
  16240.   const digitalBtn = document.querySelector('button[onclick*=\"orderProduct(\\'digital\\')\"]');
  16241.   const printsBtn = document.querySelector('button[onclick*=\"orderProduct(\\'prints\\')\"]');
  16242.   
  16243.   if (!albumBtn) console.warn('⚠️ Bouton album non trouvé');
  16244.   if (!digitalBtn) console.warn('⚠️ Bouton digital non trouvé');
  16245.   if (!printsBtn) console.warn('⚠️ Bouton prints non trouvé');
  16246.   
  16247.   // Tester les liens
  16248.   window.testProductLinks();
  16249. };
  16250. // Fonction centrale de mise à jour de TOUS les compteurs de favoris
  16251. window.updateAllFavoriteCounters = function() {
  16252.   // Récupérer le compte depuis #mesFavCount (source unique de vérité)
  16253.   const mesFavCount = document.getElementById('mesFavCount');
  16254.   let favoriteCount = 0;
  16255.   
  16256.   if (mesFavCount) {
  16257.     favoriteCount = parseInt(mesFavCount.textContent || '0');
  16258.   }
  16259.   
  16260.   console.log('[updateAllFavoriteCounters] 💗 Synchronisation:', favoriteCount, 'favoris');
  16261.   
  16262.   // Synchroniser giftCount (bouton cadeau) avec animation
  16263.   const giftCount = document.getElementById('giftCount');
  16264.   if (giftCount) {
  16265.     giftCount.textContent = favoriteCount;
  16266.     giftCount.classList.remove('gift-count-bounce');
  16267.     setTimeout(() => giftCount.classList.add('gift-count-bounce'), 10);
  16268.   }
  16269.   
  16270.   // Mettre à jour les compteurs dans le sidebar même s'il n'est pas ouvert
  16271.   const albumCount = document.getElementById('album-count');
  16272.   const digitalCount = document.getElementById('digital-count');
  16273.   const printsCount = document.getElementById('prints-count');
  16274.   
  16275.   if (albumCount) albumCount.textContent = favoriteCount;
  16276.   if (digitalCount) digitalCount.textContent = favoriteCount;
  16277.   if (printsCount) printsCount.textContent = Math.min(favoriteCount, 12);
  16278.   
  16279.   // Mettre à jour les icônes de favoris dans les produits
  16280.   const albumFavCount = document.getElementById('album-fav-count');
  16281.   const digitalFavCount = document.getElementById('digital-fav-count');
  16282.   const printsFavCount = document.getElementById('prints-fav-count');
  16283.   
  16284.   if (albumFavCount) albumFavCount.textContent = favoriteCount;
  16285.   if (digitalFavCount) digitalFavCount.textContent = favoriteCount;
  16286.   if (printsFavCount) printsFavCount.textContent = Math.min(favoriteCount, 12);
  16287.   
  16288.   // Mettre à jour le sidebar si ouvert
  16289.   const sidebar = document.getElementById('ecommerce-sidebar');
  16290.   if (sidebar && sidebar.classList.contains('active')) {
  16291.     console.log('🔄 Sidebar is open, updating content with favoriteCount:', favoriteCount);
  16292.     window.updateEcommerceSidebarContent(favoriteCount);
  16293.   } else {
  16294.     console.log('ℹ️ Sidebar is closed, but updating content anyway for consistency');
  16295.     // Mettre à jour le contenu même si le sidebar n'est pas ouvert pour la cohérence
  16296.     window.updateEcommerceSidebarContent(favoriteCount);
  16297.   }
  16298. };
  16299. // Fonction pour retirer un favori de la grille et exécuter supprimerFavoris
  16300. window.removeFavorite = function removeFavorite(itemId) {
  16301.   // Animation simple de disparition puis suppression
  16302.   const favoriteItem = document.querySelector(`.favorite-item[data-id=\"\${itemId}\"]`);
  16303.  
  16304.   if (favoriteItem) {
  16305.     favoriteItem.classList.add('fade-out');
  16306.     setTimeout(() => {
  16307.       favoriteItem.remove();
  16308.       // Appeler la fonction métier si présente
  16309.       if (typeof window.supprimerFavoris === 'function') {
  16310.         const heartIcon = document.querySelector(`#coeur\${itemId}`);
  16311.         const sejourId = heartIcon && heartIcon.dataset.sejourId ? heartIcon.dataset.sejourId : '';
  16312.         window.supprimerFavoris(itemId, sejourId);
  16313.       }
  16314.       // Mettre à jour les compteurs
  16315.       updateAllFavoriteCounters();
  16316.     }, 200);
  16317.   }
  16318. };
  16319. // Vérifier que la fonction est bien définie
  16320. console.log('🔍 removeFavorite function defined:', typeof window.removeFavorite);
  16321. // (Nettoyé) Pas de délégation globale ici; les boutons utilisent des onclick simples
  16322. // Fonction pour voir un favori en grand
  16323. window.viewFavorite = function viewFavorite(itemId) {
  16324.   console.log('👁️ Viewing favorite:', itemId);
  16325.   
  16326.   // Essayer d'utiliser la fonction viewImage existante
  16327.   if (typeof window.viewImage === 'function') {
  16328.     window.viewImage(itemId, null);
  16329.   } else {
  16330.     console.log('ℹ️ viewImage function not available, opening in new tab');
  16331.     // Fallback: ouvrir dans un nouvel onglet
  16332.     const favoriteItem = document.querySelector(`.favorite-item[data-id=\"\${itemId}\"] img`);
  16333.     if (favoriteItem && favoriteItem.src) {
  16334.       window.open(favoriteItem.src, '_blank');
  16335.     }
  16336.   }
  16337. };
  16338. // Fonction de debug pour tester les compteurs
  16339. window.debugFavoriteCounters = function() {
  16340.   console.log('🔍 Debug Favorite Counters:');
  16341.   console.log('- getFavoriteCount():', window.getFavoriteCount());
  16342.   console.log('- likeCount input value:', document.getElementById('likeCount')?.value);
  16343.   console.log('- likeCount textContent:', document.getElementById('likeCount')?.textContent);
  16344.   console.log('- giftCount textContent:', document.getElementById('giftCount')?.textContent);
  16345.   console.log('- album-count textContent:', document.getElementById('album-count')?.textContent);
  16346.   console.log('- digital-count textContent:', document.getElementById('digital-count')?.textContent);
  16347.   console.log('- prints-count textContent:', document.getElementById('prints-count')?.textContent);
  16348.   console.log('- Sidebar active:', document.getElementById('ecommerce-sidebar')?.classList.contains('active'));
  16349. };
  16350. // Fonction de test pour les boutons de favoris
  16351. window.testFavoriteButtons = function() {
  16352.   console.log('🧪 Testing favorite buttons:');
  16353.   const removeButtons = document.querySelectorAll('.btn-remove-favorite');
  16354.   const viewButtons = document.querySelectorAll('.btn-view-favorite');
  16355.   
  16356.   console.log('- Remove buttons found:', removeButtons.length);
  16357.   console.log('- View buttons found:', viewButtons.length);
  16358.   
  16359.   removeButtons.forEach((btn, index) => {
  16360.     console.log(`- Remove button \${index}:`, {
  16361.       itemId: btn.dataset.itemId,
  16362.       hasClickListener: btn.onclick !== null
  16363.     });
  16364.   });
  16365.   
  16366.   viewButtons.forEach((btn, index) => {
  16367.     console.log(`- View button \${index}:`, {
  16368.       itemId: btn.dataset.itemId,
  16369.       hasClickListener: btn.onclick !== null
  16370.     });
  16371.   });
  16372. };
  16373. // Fermer le sidebar en cliquant en dehors
  16374. document.addEventListener('click', function(e) {
  16375.   const sidebar = document.getElementById('ecommerce-sidebar');
  16376.   const giftButton = document.querySelector('.gift-button');
  16377.   
  16378.   if (sidebar && sidebar.classList.contains('active') && 
  16379.       !sidebar.contains(e.target) && 
  16380.       !giftButton.contains(e.target)) {
  16381.     window.closeEcommerceSidebar();
  16382.   }
  16383. });
  16384. // Fermer avec Escape
  16385. document.addEventListener('keydown', function(e) {
  16386.   if (e.key === 'Escape') {
  16387.     window.closeEcommerceSidebar();
  16388.   }
  16389. });
  16390. // Initialisation au chargement
  16391. document.addEventListener('DOMContentLoaded', function() {
  16392.   // Vérifier que les éléments existent
  16393.   const sidebar = document.getElementById('ecommerce-sidebar');
  16394.   const giftButton = document.getElementById('gift-button-trigger');
  16395.   
  16396.   // Event listener propre pour le bouton cadeau
  16397.   if (giftButton) {
  16398.     giftButton.addEventListener('click', function(e) {
  16399.       e.preventDefault();
  16400.       e.stopPropagation();
  16401.       window.openEcommerceSidebar();
  16402.     });
  16403.   }
  16404.   
  16405.   // Définir la date de fin du séjour si disponible
  16406.   {% if sejour and sejour.dateFinSejour is defined %}
  16407.     window.setSejourEndDate('{{ sejour.dateFinSejour|date(\"Y-m-d\") }}');
  16408.   {% endif %}
  16409.   
  16410.   // Mise à jour initiale du contenu
  16411.   let favoriteCount = 0;
  16412.   try {
  16413.     if (typeof getCurrentFavoriteCount === 'function') {
  16414.       favoriteCount = getCurrentFavoriteCount();
  16415.     } else {
  16416.       // Essayer d'abord l'input likeCount
  16417.       const likeCountInput = document.getElementById('likeCount');
  16418.       if (likeCountInput && likeCountInput.value) {
  16419.         favoriteCount = parseInt(likeCountInput.value, 10) || 0;
  16420.       } else {
  16421.         // Fallback sur giftCount
  16422.         const giftCount = document.getElementById('giftCount');
  16423.         if (giftCount && giftCount.textContent) {
  16424.           favoriteCount = parseInt(giftCount.textContent.trim()) || 0;
  16425.         }
  16426.       }
  16427.     }
  16428.   } catch (e) {
  16429.     console.log('⚠️ Fallback pour favoriteCount initial:', e);
  16430.     // Fallback sur likeCount input
  16431.     const likeCountInput = document.getElementById('likeCount');
  16432.     if (likeCountInput && likeCountInput.value) {
  16433.       favoriteCount = parseInt(likeCountInput.value, 10) || 0;
  16434.     } else {
  16435.       const giftCount = document.getElementById('giftCount');
  16436.       if (giftCount && giftCount.textContent) {
  16437.         favoriteCount = parseInt(giftCount.textContent.trim()) || 0;
  16438.       }
  16439.     }
  16440.   }
  16441.   
  16442.   window.updateEcommerceSidebarContent(favoriteCount);
  16443.   
  16444. });
  16445. </script>
  16446. <!-- 🎯 DAY FILTER POPOVER (instancié une seule fois) -->
  16447. <div id=\"dayFilterPopover\" class=\"day-popover\" role=\"dialog\" aria-modal=\"true\" aria-hidden=\"true\">
  16448.   <div class=\"dp-arrow\" aria-hidden=\"true\"></div>
  16449.   <div class=\"dp-content\" role=\"group\" aria-label=\"Filtres du jour\">
  16450.     <button class=\"dp-btn\" data-filter=\"all\" title=\"Tout\" aria-pressed=\"true\">
  16451.       <i class=\"bi bi-grid-3x3-gap-fill\"></i><span class=\"dp-count dp-label\">Tout</span>
  16452.     </button>
  16453.     <button class=\"dp-btn\" data-filter=\"photos\" title=\"Photos\" aria-pressed=\"false\">
  16454.       <i class=\"bi bi-images\"></i><span class=\"dp-count\" data-bind=\"photo\">0</span>
  16455.     </button>
  16456.     <button class=\"dp-btn\" data-filter=\"audio\" title=\"Audios\" aria-pressed=\"false\">
  16457.       <i class=\"bi bi-mic-fill\"></i><span class=\"dp-count\" data-bind=\"audio\">0</span>
  16458.     </button>
  16459.     <button class=\"dp-btn\" data-filter=\"videos\" title=\"Vidéos\" aria-pressed=\"false\">
  16460.       <i class=\"bi bi-camera-video-fill\"></i><span class=\"dp-count\" data-bind=\"video\">0</span>
  16461.     </button>
  16462.     <button class=\"dp-btn\" data-filter=\"favoris\" title=\"Favoris\" aria-pressed=\"false\">
  16463.       <i class=\"bi bi-heart-fill\" style=\"color:#f56040\"></i><span class=\"dp-count\" data-bind=\"fav\">0</span>
  16464.     </button>
  16465.     <button class=\"dp-btn dp-close\" title=\"Fermer\" aria-label=\"Fermer\">
  16466.       <i class=\"bi bi-x-lg\"></i>
  16467.     </button>
  16468.   </div>
  16469. </div>
  16470. {# ==================== Zones B2C Suggestions ==================== #}
  16471. {# Sidebar suggestions (desktop) #}
  16472. <aside class=\"col-lg-3 d-none d-lg-block\" style=\"position:sticky;top:100px;\">
  16473.   <div id=\"parentSuggestions\" class=\"pcb-sticky\">
  16474.     {# Rempli dynamiquement par parent-b2c-nuke.js #}
  16475.   </div>
  16476. </aside>
  16477. {# Bloc suggestions mobile #}
  16478. <div class=\"col-12 d-lg-none mt-3\">
  16479.   <div id=\"parentSuggestionsMobile\">
  16480.     {# Rempli dynamiquement par parent-b2c-nuke.js #}
  16481.   </div>
  16482. </div>
  16483. {# ==================== SIDEBAR E-COMMERCE ==================== #}
  16484. <script src=\"{{ asset('js/sidebar-ecommerce-pro.js') }}\"></script>
  16485. {% endblock %}
  16486. ""Parent/DetailsSejour.html.twig""/var/www/5sur5sejour/templates/Parent/DetailsSejour.html.twig");
  16487.     }
  16488. }