{"product_id":"the-game-of-the-cite-of-carcassonne","title":"Le Jeu de la Cité Médiévale de Carcassonne","description":"\u003cstyle\u003e\n  variant-radios,\n  variant-selects {\n    position: absolute !important;\n    left: -9999px !important;\n    top: -9999px !important;\n    opacity: 0 !important;\n    pointer-events: none !important;\n    height: 1px !important;\n    width: 1px !important;\n    overflow: hidden !important;\n  }\n\n  quantity-input,\n  .quantity-input,\n  .product-form__quantity,\n  [name=\"quantity-input\"] {\n    display: none !important;\n  }\n\n  .carca-game-wrapper {\n    font-family: 'Segoe UI', sans-serif;\n    max-width: 800px;\n    margin: 0 auto;\n    color: #333;\n    line-height: 1.6;\n  }\n\n  .carca-game-booking-bar {\n    margin-bottom: 22px;\n    display: flex;\n    justify-content: center;\n  }\n\n  .carca-game-book-btn {\n    appearance: none;\n    border: 2px solid #a94442;\n    background: #a94442;\n    color: #fff;\n    border-radius: 14px;\n    padding: 14px 24px;\n    cursor: pointer;\n    font-weight: 700;\n    font-size: 16px;\n    line-height: 1.2;\n    text-align: center;\n    transition: all 0.2s ease;\n    box-shadow: 0 4px 10px rgba(169, 68, 66, 0.18);\n    width: 100%;\n  }\n\n  .carca-game-book-btn:hover {\n    transform: translateY(-1px);\n  }\n\n  .carca-game-confirmed-badge {\n    margin-top: 10px;\n    display: none;\n    color: #1f6b2b;\n    font-weight: 700;\n  }\n\n  \/* MODAL *\/\n  .carca-game-modal {\n    position: fixed !important;\n    inset: 0 !important;\n    width: 100vw !important;\n    height: 100vh !important;\n    display: none !important;\n    align-items: center !important;\n    justify-content: center !important;\n    z-index: 2147483000 !important;\n    padding: 24px !important;\n    box-sizing: border-box !important;\n  }\n\n  .carca-game-modal.open {\n    display: flex !important;\n  }\n\n  .carca-game-modal-backdrop {\n    position: fixed !important;\n    inset: 0 !important;\n    background: rgba(0, 0, 0, 0.35) !important;\n    backdrop-filter: blur(6px) !important;\n    -webkit-backdrop-filter: blur(6px) !important;\n    z-index: 1 !important;\n  }\n\n  .carca-game-modal-dialog {\n    position: relative !important;\n    z-index: 2 !important;\n    width: min(760px, calc(100vw - 32px)) !important;\n    max-width: 760px !important;\n    max-height: min(86vh, 900px) !important;\n    overflow-y: auto !important;\n    background: #fff !important;\n    border-radius: 18px !important;\n    box-shadow: 0 24px 80px rgba(0, 0, 0, 0.28) !important;\n    border: 1px solid #e9e9e9 !important;\n  }\n\n  .carca-game-modal-header {\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    gap: 16px;\n    padding: 18px 22px;\n    border-bottom: 1px solid #ececec;\n    position: sticky;\n    top: 0;\n    background: #fff;\n    z-index: 3;\n    border-top-left-radius: 18px;\n    border-top-right-radius: 18px;\n  }\n\n  .carca-game-modal-main-title {\n    margin: 0;\n    font-size: 18px;\n    line-height: 1.3;\n    color: #222;\n    font-weight: 700;\n  }\n\n  .carca-game-modal-close {\n    appearance: none;\n    background: transparent;\n    border: none;\n    color: #8a8a8a;\n    font-size: 32px;\n    line-height: 1;\n    cursor: pointer;\n    padding: 0;\n    width: 34px;\n    height: 34px;\n    flex: 0 0 auto;\n  }\n\n  .carca-game-modal-body {\n    padding: 24px 22px 26px 22px;\n  }\n\n  .carca-game-step {\n    display: none;\n  }\n\n  .carca-game-step.active {\n    display: block;\n  }\n\n  .carca-game-step-title {\n    color: #a94442;\n    font-size: 20px;\n    margin: 0 0 8px 0;\n  }\n\n  .carca-game-step-subtitle {\n    margin: 0 0 18px 0;\n    color: #666;\n    font-size: 14px;\n    line-height: 1.5;\n  }\n\n  .carca-game-actions {\n    display: flex;\n    justify-content: flex-end;\n    gap: 10px;\n    flex-wrap: wrap;\n    margin-top: 20px;\n  }\n\n  .carca-game-btn {\n    appearance: none;\n    border: 1px solid #cfcfcf;\n    background: #fff;\n    color: #333;\n    border-radius: 999px;\n    padding: 12px 20px;\n    cursor: pointer;\n    font-weight: 700;\n    font-size: 15px;\n    min-width: 110px;\n  }\n\n  .carca-game-btn.primary {\n    background: #d2a3a2;\n    border-color: #d2a3a2;\n    color: #fff;\n  }\n\n  .carca-game-btn.secondary-red {\n    background: #a94442;\n    border-color: #a94442;\n    color: #fff;\n  }\n\n  .carca-game-review-box {\n    background: #f8f8f8;\n    border: 1px solid #e2e2e2;\n    border-radius: 14px;\n    padding: 18px;\n  }\n\n  .carca-game-review-item {\n    margin-bottom: 14px;\n  }\n\n  .carca-game-review-item:last-child {\n    margin-bottom: 0;\n  }\n\n  .carca-game-review-label {\n    font-weight: 700;\n    color: #a94442;\n    margin-bottom: 3px;\n  }\n\n  \/* Participants control *\/\n  .carca-game-participants-control {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    gap: 20px;\n    margin: 24px 0 8px 0;\n  }\n\n  .carca-game-participants-btn {\n    appearance: none;\n    width: 48px;\n    height: 48px;\n    border-radius: 50%;\n    border: 2px solid #a94442;\n    background: #fff;\n    color: #a94442;\n    font-size: 24px;\n    font-weight: 700;\n    cursor: pointer;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    transition: all 0.2s ease;\n    line-height: 1;\n  }\n\n  .carca-game-participants-btn:hover {\n    background: #a94442;\n    color: #fff;\n  }\n\n  .carca-game-participants-btn:disabled {\n    opacity: 0.35;\n    cursor: not-allowed;\n    pointer-events: none;\n  }\n\n  .carca-game-participants-value {\n    font-size: 36px;\n    font-weight: 700;\n    color: #a94442;\n    min-width: 50px;\n    text-align: center;\n  }\n\n  .carca-game-price-display {\n    text-align: center;\n    font-size: 18px;\n    font-weight: 700;\n    color: #a94442;\n    margin: 12px 0 6px 0;\n    min-height: 28px;\n    transition: opacity 0.2s ease;\n  }\n\n  .carca-game-group-note {\n    text-align: center;\n    font-size: 13px;\n    color: #888;\n    margin: 10px 0 0 0;\n    line-height: 1.5;\n  }\n\n  .carca-game-group-note a {\n    color: #a94442;\n    font-weight: 600;\n  }\n\n  \/* CALENDAR *\/\n  .carca-game-cal-label {\n    display: block;\n    font-weight: 700;\n    margin-bottom: 12px;\n    color: #333;\n    font-size: 15px;\n  }\n\n  .carca-game-cal-wrap {\n    display: flex;\n    gap: 0;\n    border: 1px solid #e0e0e0;\n    border-radius: 14px;\n    overflow: hidden;\n    background: #fff;\n  }\n\n  .carca-game-cal-month {\n    flex: 1 1 50%;\n    min-width: 0;\n    padding: 18px 16px;\n  }\n\n  .carca-game-cal-month:first-child {\n    border-right: 1px solid #e0e0e0;\n  }\n\n  .carca-game-cal-month-header {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    gap: 8px;\n    margin-bottom: 14px;\n    position: relative;\n  }\n\n  .carca-game-cal-month-title {\n    font-weight: 700;\n    font-size: 15px;\n    color: #222;\n    text-align: center;\n  }\n\n  .carca-game-cal-nav {\n    appearance: none;\n    background: none;\n    border: none;\n    cursor: pointer;\n    font-size: 18px;\n    color: #555;\n    padding: 4px 8px;\n    border-radius: 6px;\n    line-height: 1;\n    transition: background 0.15s;\n  }\n\n  .carca-game-cal-nav:hover {\n    background: #f0f0f0;\n  }\n\n  .carca-game-cal-nav.hidden {\n    visibility: hidden;\n  }\n\n  .carca-game-cal-grid {\n    display: grid;\n    grid-template-columns: repeat(7, 1fr);\n    gap: 0;\n  }\n\n  .carca-game-cal-dow {\n    text-align: center;\n    font-size: 12px;\n    font-weight: 600;\n    color: #999;\n    padding: 0 0 8px 0;\n    text-transform: capitalize;\n  }\n\n  .carca-game-cal-day {\n    text-align: center;\n    padding: 0;\n    aspect-ratio: 1;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    font-size: 14px;\n    border-radius: 50%;\n    cursor: pointer;\n    color: #222;\n    font-weight: 500;\n    transition: background 0.15s, color 0.15s;\n    border: none;\n    background: none;\n    appearance: none;\n    width: 100%;\n  }\n\n  .carca-game-cal-day:hover:not(.disabled):not(.empty) {\n    background: #f7e8e8;\n  }\n\n  .carca-game-cal-day.selected {\n    background: #a94442;\n    color: #fff;\n    font-weight: 700;\n  }\n\n  .carca-game-cal-day.disabled {\n    color: #ccc;\n    cursor: default;\n    pointer-events: none;\n  }\n\n  .carca-game-cal-day.empty {\n    cursor: default;\n    pointer-events: none;\n  }\n\n  .carca-game-cal-selected-display {\n    margin-top: 14px;\n    padding: 10px 14px;\n    background: #f7e8e8;\n    border: 1px solid #a94442;\n    border-radius: 10px;\n    font-size: 14px;\n    color: #a94442;\n    font-weight: 600;\n    display: none;\n    text-align: center;\n  }\n\n  .carca-game-cal-selected-display.visible {\n    display: block;\n  }\n\n  @media (max-width: 749px) {\n    .carca-game-modal {\n      padding: 8px !important;\n    }\n\n    .carca-game-modal-dialog {\n      width: calc(100vw - 16px) !important;\n      max-height: 92vh !important;\n      border-radius: 14px !important;\n    }\n\n    .carca-game-modal-header {\n      padding: 14px 14px 12px 14px;\n      border-top-left-radius: 14px;\n      border-top-right-radius: 14px;\n    }\n\n    .carca-game-modal-main-title {\n      font-size: 15px;\n    }\n\n    .carca-game-modal-body {\n      padding: 14px 12px 18px 12px;\n    }\n\n    .carca-game-step-title {\n      font-size: 17px;\n    }\n\n    .carca-game-step-subtitle {\n      font-size: 13px;\n    }\n\n    .carca-game-cal-wrap {\n      flex-direction: column;\n      border-radius: 12px;\n    }\n\n    .carca-game-cal-month {\n      flex: 1 1 auto;\n      padding: 14px 12px;\n    }\n\n    .carca-game-cal-month:first-child {\n      border-right: none;\n      border-bottom: 1px solid #e0e0e0;\n    }\n\n    .carca-game-cal-day {\n      font-size: 13px;\n    }\n\n    .carca-game-cal-month-title {\n      font-size: 14px;\n    }\n\n    .carca-game-btn {\n      padding: 11px 16px;\n      font-size: 14px;\n      min-width: 90px;\n    }\n  }\n\u003c\/style\u003e\n\n\u003cdiv class=\"carca-game-wrapper\"\u003e\n  \u003c!-- Short Description --\u003e\n  \u003cp style=\"font-size: 18px; margin-bottom: 20px; text-align: justify;\"\u003eGlissez-vous dans la peau d'un enquêteur médiéval et transformez votre visite de Carcassonne en une aventure inoubliable. Parcourez les ruelles pavées de la Cité fortifiée, levez les yeux vers les blasons, déchiffrez les inscriptions latines, comptez les gargouilles et percez les secrets cachés dans chaque recoin.\u003c\/p\u003e\n  \u003cp style=\"font-size: 18px; margin-bottom: 20px; text-align: justify; font-weight: 600;\"\u003eQuatorze quêtes vous attendent. Relevez-les toutes, gagnez le titre de Chevalier de la Cité et vivez Carcassonne comme jamais auparavant.\u003c\/p\u003e\n\n  \u003c!-- BOOKING BUTTON --\u003e\n  \u003cdiv class=\"carca-game-booking-bar\"\u003e\n    \u003cbutton type=\"button\" class=\"carca-game-book-btn\" id=\"carca-game-open-modal\"\u003e\n      Choisissez votre date\n    \u003c\/button\u003e\n  \u003c\/div\u003e\n\n  \u003c!-- Two-card horizontal stack on desktop \/ vertical on mobile --\u003e\n  \u003cdiv style=\"display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 18px; margin-bottom: 26px;\"\u003e\n    \u003c!-- What to Expect Card --\u003e\n    \u003cdiv style=\"background-color: #f7e8e8; border: 2px solid #a94442; padding: 18px; border-radius: 12px; box-shadow: 0 4px 8px rgba(169,68,66,0.08);\"\u003e\n      \u003ch3 style=\"color: #a94442; font-size: 18px; margin-bottom: 10px;\"\u003e\u003cstrong\u003eÀ quoi vous attendre\u003c\/strong\u003e\u003c\/h3\u003e\n      \u003cul style=\"padding-left: 18px; margin: 0; color: #222; font-weight: 500; text-align: justify;\"\u003e\n        \u003cli style=\"margin-bottom: 8px;\"\u003e\u003cstrong\u003eUne aventure médiévale immersive\u003c\/strong\u003e\u003c\/li\u003e\n        \u003cli style=\"margin-bottom: 8px;\"\u003eTour de Carcassonne est un jeu d'exploration, d'observation, de réflexion et de déduction qui révèle les histoires cachées et les détails surprenants de la Cité fortifiée.\u003c\/li\u003e\n        \u003cli style=\"margin-bottom: 8px;\"\u003e\u003cstrong\u003eIdéal pour les adultes et les enfants\u003c\/strong\u003e — favorise la curiosité et l'esprit d'équipe.\u003c\/li\u003e\n        \u003cli style=\"margin-bottom: 8px;\"\u003eUne des activités les plus abordables de Carcassonne.\u003c\/li\u003e\n      \u003c\/ul\u003e\n    \u003c\/div\u003e\n    \u003c!-- Game Details Card --\u003e\n    \u003cdiv style=\"background-color: #f7e8e8; border: 2px solid #a94442; padding: 18px; border-radius: 12px; box-shadow: 0 4px 8px rgba(169,68,66,0.08);\"\u003e\n      \u003ch3 style=\"color: #a94442; font-size: 18px; margin-bottom: 10px;\"\u003e\u003cstrong\u003eDétails du jeu\u003c\/strong\u003e\u003c\/h3\u003e\n      \u003cul style=\"padding-left: 18px; margin: 0; color: #222; font-weight: 500; text-align: justify;\"\u003e\n        \u003cli style=\"margin-bottom: 8px;\"\u003e\u003cstrong\u003eLangues disponibles :\u003c\/strong\u003e français, anglais, espagnol, catalan, allemand, occitan, italien, portugais, néerlandais, chinois simplifié, japonais, coréen, ukrainien, russe (14 langues — vous choisissez après la réservation).\u003c\/li\u003e\n        \u003cli style=\"margin-bottom: 8px;\"\u003e\u003cstrong\u003eDurée :\u003c\/strong\u003e 1 à 2 heures selon votre rythme.\u003c\/li\u003e\n        \u003cli style=\"margin-bottom: 8px;\"\u003e\u003cstrong\u003eAucune connexion internet requise.\u003c\/strong\u003e\u003c\/li\u003e\n        \u003cli style=\"margin-bottom: 8px;\"\u003e\u003cstrong\u003eLivraison :\u003c\/strong\u003e tout est envoyé automatiquement par email \u003cstrong\u003e10 à 30 secondes\u003c\/strong\u003e après votre commande.\u003c\/li\u003e\n        \u003cli style=\"margin-bottom: 8px;\"\u003e\u003cstrong\u003ePour qui :\u003c\/strong\u003e adultes et enfants.\u003c\/li\u003e\n      \u003c\/ul\u003e\n    \u003c\/div\u003e\n  \u003c\/div\u003e\n\n  \u003c!-- Expandable Full Description --\u003e\n  \u003cdiv style=\"margin-bottom: 26px;\"\u003e\n    \u003cdetails style=\"border: 1px solid #e0e6ea; padding: 18px; border-radius: 12px; background: #fff;\"\u003e\n      \u003csummary style=\"font-size: 17px; cursor: pointer; color: #a94442; font-weight: bold;\"\u003eCliquez ici pour lire l'histoire complète\u003c\/summary\u003e\n      \u003cdiv style=\"margin-top: 14px; text-align: justify; color: #222; line-height: 1.6;\"\u003e\n        \u003cp\u003eLe dernier chevalier a rendu son ultime souffle, laissant derrière lui un parchemin énigmatique. Ce message s'adresse à ceux qui oseront relever le défi pour lui succéder.\u003c\/p\u003e\n        \u003cp\u003eCar être Chevalier de la Cité, c'est bien plus qu'un titre : c'est connaître Carcassonne dans ses moindres recoins, comprendre son histoire, lever les yeux vers les blasons, déchiffrer les inscriptions latines et compter les gargouilles.\u003c\/p\u003e\n        \u003cp\u003eQuatorze quêtes vous attendent à travers la Cité.\u003c\/p\u003e\n      \u003c\/div\u003e\n    \u003c\/details\u003e\n  \u003c\/div\u003e\n\n  \u003c!-- Game Delivery Card --\u003e\n  \u003cdiv style=\"background-color: #fafafa; border-left: 6px solid #a94442; padding: 18px; border-radius: 10px; margin-bottom: 18px;\"\u003e\n    \u003ch3 style=\"color: #a94442; font-size: 18px; margin: 0 0 10px 0;\"\u003e\u003cstrong\u003eLivraison du jeu\u003c\/strong\u003e\u003c\/h3\u003e\n    \u003cp style=\"margin: 0; color: #222; text-align: justify;\"\u003eTout est envoyé automatiquement par email \u003cstrong\u003e10 à 30 secondes\u003c\/strong\u003e après votre commande. Pour retrouver votre commande, connectez-vous sur notre plateforme sécurisée \u003ca href=\"https:\/\/tickets-connect.com\" style=\"color: #a94442; font-weight: bold;\" target=\"_blank\"\u003etickets-connect.com\u003c\/a\u003e. Vous choisirez votre langue préférée directement sur la plateforme après la réservation.\u003c\/p\u003e\n  \u003c\/div\u003e\n\n  \u003cdiv class=\"carca-game-confirmed-badge\" id=\"carca-game-confirmed-badge\"\u003e\n    Détails de réservation enregistrés pour ce produit. Vous pouvez maintenant l'ajouter au panier.\n  \u003c\/div\u003e\n\u003c\/div\u003e\n\n\u003c!-- MODAL --\u003e\n\u003cdiv class=\"carca-game-modal\" id=\"carca-game-modal\" aria-hidden=\"true\"\u003e\n  \u003cdiv class=\"carca-game-modal-backdrop\" id=\"carca-game-modal-backdrop\"\u003e\u003c\/div\u003e\n\n  \u003cdiv class=\"carca-game-modal-dialog\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"carca-game-modal-title\"\u003e\n    \u003cdiv class=\"carca-game-modal-header\"\u003e\n      \u003ch2 class=\"carca-game-modal-main-title\" id=\"carca-game-modal-title\"\u003e\n        Tour de Carcassonne - Jeu d'Exploration\n      \u003c\/h2\u003e\n      \u003cbutton type=\"button\" class=\"carca-game-modal-close\" id=\"carca-game-modal-close\" aria-label=\"Fermer\"\u003e\u0026times;\u003c\/button\u003e\n    \u003c\/div\u003e\n\n    \u003cdiv class=\"carca-game-modal-body\"\u003e\n      \u003c!-- STEP 1: Participants --\u003e\n      \u003cdiv class=\"carca-game-step active\" id=\"carca-game-step-1\"\u003e\n        \u003ch3 class=\"carca-game-step-title\"\u003eCombien de participants ?\u003c\/h3\u003e\n        \u003cp class=\"carca-game-step-subtitle\"\u003eSélectionnez le nombre de participants pour le jeu. Vous choisirez votre langue préférée après la réservation.\u003c\/p\u003e\n\n        \u003cdiv class=\"carca-game-participants-control\"\u003e\n          \u003cbutton type=\"button\" class=\"carca-game-participants-btn\" id=\"carca-game-participants-minus\" aria-label=\"Retirer un participant\"\u003e\u0026minus;\u003c\/button\u003e\n          \u003cspan class=\"carca-game-participants-value\" id=\"carca-game-participants-value\"\u003e1\u003c\/span\u003e\n          \u003cbutton type=\"button\" class=\"carca-game-participants-btn\" id=\"carca-game-participants-plus\" aria-label=\"Ajouter un participant\"\u003e+\u003c\/button\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv class=\"carca-game-price-display\" id=\"carca-game-price-display\"\u003e\u003c\/div\u003e\n\n        \u003cp class=\"carca-game-group-note\"\u003ePour les groupes de plus de 10 participants, merci de nous contacter directement à \u003ca href=\"mailto:contact@visit-carcassonne.com\"\u003econtact@visit-carcassonne.com\u003c\/a\u003e\u003c\/p\u003e\n\n        \u003cdiv class=\"carca-game-actions\"\u003e\n          \u003cbutton type=\"button\" class=\"carca-game-btn secondary-red\" id=\"carca-game-to-step-2\"\u003eSuivant\u003c\/button\u003e\n        \u003c\/div\u003e\n      \u003c\/div\u003e\n\n      \u003c!-- STEP 2: Date selection --\u003e\n      \u003cdiv class=\"carca-game-step\" id=\"carca-game-step-2\"\u003e\n        \u003ch3 class=\"carca-game-step-title\"\u003eChoisissez la date\u003c\/h3\u003e\n        \u003cp class=\"carca-game-step-subtitle\"\u003eSélectionnez la date à laquelle vous prévoyez de jouer à Carcassonne.\u003c\/p\u003e\n        \u003cinput type=\"hidden\" id=\"carca-game-date\" value=\"\"\u003e\n        \u003cdiv id=\"carca-game-cal-container\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"carca-game-cal-selected-display\" id=\"carca-game-cal-selected-display\"\u003e\u003c\/div\u003e\n\n        \u003cdiv class=\"carca-game-actions\"\u003e\n          \u003cbutton type=\"button\" class=\"carca-game-btn\" id=\"carca-game-back-to-step-1\"\u003eRetour\u003c\/button\u003e\n          \u003cbutton type=\"button\" class=\"carca-game-btn secondary-red\" id=\"carca-game-to-step-3\"\u003eSuivant\u003c\/button\u003e\n        \u003c\/div\u003e\n      \u003c\/div\u003e\n\n      \u003c!-- STEP 3: Review --\u003e\n      \u003cdiv class=\"carca-game-step\" id=\"carca-game-step-3\"\u003e\n        \u003ch3 class=\"carca-game-step-title\"\u003eVérifiez vos informations\u003c\/h3\u003e\n        \u003cp class=\"carca-game-step-subtitle\"\u003eVeuillez vérifier l'ensemble des informations avant de confirmer.\u003c\/p\u003e\n\n        \u003cdiv class=\"carca-game-review-box\" id=\"carca-game-review-box\"\u003e\u003c\/div\u003e\n\n        \u003cdiv class=\"carca-game-actions\"\u003e\n          \u003cbutton type=\"button\" class=\"carca-game-btn\" id=\"carca-game-restart\"\u003eRecommencer\u003c\/button\u003e\n          \u003cbutton type=\"button\" class=\"carca-game-btn secondary-red\" id=\"carca-game-confirm\"\u003eConfirmer\u003c\/button\u003e\n        \u003c\/div\u003e\n      \u003c\/div\u003e\n    \u003c\/div\u003e\n  \u003c\/div\u003e\n\u003c\/div\u003e\n\n\u003cscript\u003e\ndocument.addEventListener('DOMContentLoaded', function () {\n  const variantMap = {\n    1:  '56792466981188',\n    2:  '56792467013956',\n    3:  '56792467046724',\n    4:  '56792467079492',\n    5:  '56792467112260',\n    6:  '56792467145028',\n    7:  '56792467177796',\n    8:  '56792467210564',\n    9:  '56792467243332',\n    10: '56792467276100'\n  };\n\n  const modal = document.getElementById('carca-game-modal');\n  const modalOpenBtn = document.getElementById('carca-game-open-modal');\n  const modalCloseBtn = document.getElementById('carca-game-modal-close');\n  const modalBackdrop = document.getElementById('carca-game-modal-backdrop');\n\n  const totalSteps = 3;\n  const steps = [];\n  for (let i = 1; i \u003c= totalSteps; i++) {\n    steps.push(document.getElementById('carca-game-step-' + i));\n  }\n\n  const dateInput = document.getElementById('carca-game-date');\n  const reviewBox = document.getElementById('carca-game-review-box');\n  const confirmedBadge = document.getElementById('carca-game-confirmed-badge');\n\n  const toStep2Btn = document.getElementById('carca-game-to-step-2');\n  const backToStep1Btn = document.getElementById('carca-game-back-to-step-1');\n  const toStep3Btn = document.getElementById('carca-game-to-step-3');\n  const restartBtn = document.getElementById('carca-game-restart');\n  const confirmBtn = document.getElementById('carca-game-confirm');\n\n  const calContainer = document.getElementById('carca-game-cal-container');\n  const calSelectedDisplay = document.getElementById('carca-game-cal-selected-display');\n\n  const participantsValue = document.getElementById('carca-game-participants-value');\n  const participantsMinusBtn = document.getElementById('carca-game-participants-minus');\n  const participantsPlusBtn = document.getElementById('carca-game-participants-plus');\n  const priceDisplay = document.getElementById('carca-game-price-display');\n  let participantsCount = 1;\n\n  const priceCache = {};\n\n  \/* ===== VARIANT \u0026 PRICE ===== *\/\n  function getVariantForCount(count) {\n    return variantMap[count] || variantMap[1];\n  }\n\n  function syncNativeVariant(variantId) {\n    if (!variantId) return;\n    const mainProduct = document.querySelector('product-info') || document.querySelector('main');\n    if (!mainProduct) return;\n\n    const idInputs = mainProduct.querySelectorAll('form[action*=\"\/cart\/add\"] input[name=\"id\"]');\n    idInputs.forEach(function (input) {\n      input.value = variantId;\n      input.setAttribute('value', variantId);\n      input.dispatchEvent(new Event('input', { bubbles: true }));\n      input.dispatchEvent(new Event('change', { bubbles: true }));\n    });\n\n    const url = new URL(window.location.href);\n    url.searchParams.set('variant', variantId);\n    window.history.replaceState({}, '', url.toString());\n  }\n\n  function extractDisplayedPrice(doc, sectionId) {\n    const selectors = [\n      '#price-' + sectionId,\n      '.price',\n      '[id^=\"price-\"]'\n    ];\n\n    for (var s = 0; s \u003c selectors.length; s++) {\n      var el = doc.querySelector(selectors[s]);\n      if (!el) continue;\n\n      var salePrice =\n        el.querySelector('.price-item--sale') ||\n        el.querySelector('.price-item--regular') ||\n        el.querySelector('.money') ||\n        el;\n\n      var text = salePrice.textContent.replace(\/\\s+\/g, ' ').trim();\n      if (text) return text;\n    }\n\n    return '';\n  }\n\n  async function getFormattedPriceForVariant(variantId) {\n    if (priceCache[variantId]) return priceCache[variantId];\n\n    const productInfo = document.querySelector('product-info');\n    if (!productInfo) return '';\n\n    const sectionId = productInfo.dataset.section;\n    if (!sectionId) return '';\n\n    const productUrl = window.location.pathname;\n    const fetchUrl = productUrl + '?variant=' + variantId + '\u0026section_id=' + sectionId;\n\n    try {\n      const response = await fetch(fetchUrl);\n      const htmlText = await response.text();\n      const parser = new DOMParser();\n      const doc = parser.parseFromString(htmlText, 'text\/html');\n\n      const priceText = extractDisplayedPrice(doc, sectionId);\n      priceCache[variantId] = priceText || '';\n      return priceCache[variantId];\n    } catch (error) {\n      console.error('Price fetch error:', error);\n      return '';\n    }\n  }\n\n  async function refreshPriceAndForm(variantId) {\n    if (!variantId) return;\n    const productInfo = document.querySelector('product-info');\n    if (!productInfo) return;\n\n    const sectionId = productInfo.dataset.section;\n    if (!sectionId) return;\n\n    const productUrl = window.location.pathname;\n    const fetchUrl = productUrl + '?variant=' + variantId + '\u0026section_id=' + sectionId;\n\n    try {\n      const response = await fetch(fetchUrl);\n      const htmlText = await response.text();\n      const parser = new DOMParser();\n      const doc = parser.parseFromString(htmlText, 'text\/html');\n\n      const newPrice = doc.querySelector('#price-' + sectionId);\n      const currentPrice = document.querySelector('#price-' + sectionId);\n      if (newPrice \u0026\u0026 currentPrice) currentPrice.innerHTML = newPrice.innerHTML;\n\n      const newSku = doc.querySelector('#Sku-' + sectionId);\n      const currentSku = document.querySelector('#Sku-' + sectionId);\n      if (newSku \u0026\u0026 currentSku) currentSku.innerHTML = newSku.innerHTML;\n\n      const newInventory = doc.querySelector('#Inventory-' + sectionId);\n      const currentInventory = document.querySelector('#Inventory-' + sectionId);\n      if (newInventory \u0026\u0026 currentInventory) currentInventory.innerHTML = newInventory.innerHTML;\n\n      const newPricePerItem = doc.querySelector('#Price-Per-Item-' + sectionId);\n      const currentPricePerItem = document.querySelector('#Price-Per-Item-' + sectionId);\n      if (newPricePerItem \u0026\u0026 currentPricePerItem) currentPricePerItem.innerHTML = newPricePerItem.innerHTML;\n\n      const newProductForm = doc.querySelector('#product-form-' + sectionId);\n      const currentProductForm = document.querySelector('#product-form-' + sectionId);\n      if (newProductForm \u0026\u0026 currentProductForm) {\n        const newButton = newProductForm.querySelector('[name=\"add\"]');\n        const currentButton = currentProductForm.querySelector('[name=\"add\"]');\n        if (newButton \u0026\u0026 currentButton) {\n          currentButton.disabled = newButton.disabled;\n          currentButton.innerHTML = newButton.innerHTML;\n        }\n\n        const newHiddenInput = newProductForm.querySelector('input[name=\"id\"]');\n        const currentHiddenInput = currentProductForm.querySelector('input[name=\"id\"]');\n        if (newHiddenInput \u0026\u0026 currentHiddenInput) {\n          currentHiddenInput.value = newHiddenInput.value;\n        }\n      }\n    } catch (error) {\n      console.error('Variant refresh error:', error);\n    }\n  }\n\n  async function updatePriceDisplay() {\n    const variantId = getVariantForCount(participantsCount);\n    priceDisplay.style.opacity = '0.4';\n    const price = await getFormattedPriceForVariant(variantId);\n    priceDisplay.textContent = price ? price : '';\n    priceDisplay.style.opacity = '1';\n  }\n\n  async function syncAll() {\n    const variantId = getVariantForCount(participantsCount);\n    syncNativeVariant(variantId);\n    await refreshPriceAndForm(variantId);\n  }\n\n  \/* ===== QUANTITY SYNC ===== *\/\n  function syncQuantityToProduct(qty) {\n    const qtyInput = document.querySelector('input[name=\"quantity\"]');\n    if (qtyInput) {\n      qtyInput.value = qty;\n      qtyInput.dispatchEvent(new Event('change', { bubbles: true }));\n    }\n    const qtySelect = document.querySelector('select[name=\"quantity\"]');\n    if (qtySelect) {\n      qtySelect.value = qty;\n      qtySelect.dispatchEvent(new Event('change', { bubbles: true }));\n    }\n    const qtyInputEl = document.querySelector('quantity-input input');\n    if (qtyInputEl) {\n      qtyInputEl.value = qty;\n      qtyInputEl.dispatchEvent(new Event('change', { bubbles: true }));\n    }\n  }\n\n  \/* ===== PARTICIPANTS ===== *\/\n  function updateParticipantsUI() {\n    participantsValue.textContent = participantsCount;\n    participantsMinusBtn.disabled = participantsCount \u003c= 1;\n    participantsPlusBtn.disabled = participantsCount \u003e= 10;\n    syncQuantityToProduct(1);\n    const variantId = getVariantForCount(participantsCount);\n    syncNativeVariant(variantId);\n    refreshPriceAndForm(variantId);\n    updatePriceDisplay();\n  }\n\n  participantsMinusBtn.addEventListener('click', function () {\n    if (participantsCount \u003e 1) {\n      participantsCount--;\n      updateParticipantsUI();\n    }\n  });\n\n  participantsPlusBtn.addEventListener('click', function () {\n    if (participantsCount \u003c 10) {\n      participantsCount++;\n      updateParticipantsUI();\n    }\n  });\n\n  \/* ===== CALENDAR ===== *\/\n  const today = new Date();\n  today.setHours(0, 0, 0, 0);\n  const minDate = new Date(today);\n  const maxDate = new Date(today);\n  maxDate.setDate(maxDate.getDate() + 365);\n\n  let calBaseMonth = minDate.getMonth();\n  let calBaseYear = minDate.getFullYear();\n  let selectedDate = null;\n\n  const monthNamesFull = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'];\n  const dowLabels = ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'];\n\n  function renderCalendar() {\n    const isMobile = window.innerWidth \u003c= 749;\n    const monthsToShow = isMobile ? 1 : 2;\n\n    let html = '\u003cdiv class=\"carca-game-cal-wrap\"\u003e';\n\n    for (let m = 0; m \u003c monthsToShow; m++) {\n      let month = calBaseMonth + m;\n      let year = calBaseYear;\n      if (month \u003e 11) {\n        month -= 12;\n        year += 1;\n      }\n\n      const showPrev = (m === 0);\n      const showNext = (m === monthsToShow - 1);\n\n      html += '\u003cdiv class=\"carca-game-cal-month\"\u003e';\n      html += '\u003cdiv class=\"carca-game-cal-month-header\"\u003e';\n\n      if (showPrev) {\n        const canGoPrev = !(calBaseYear === minDate.getFullYear() \u0026\u0026 calBaseMonth \u003c= minDate.getMonth());\n        html += '\u003cbutton type=\"button\" class=\"carca-game-cal-nav ' + (canGoPrev ? '' : 'hidden') + '\" data-dir=\"prev\" aria-label=\"Mois précédent\"\u003e\u0026#8249;\u003c\/button\u003e';\n      }\n\n      html += '\u003cspan class=\"carca-game-cal-month-title\"\u003e' + monthNamesFull[month] + ' ' + year + '\u003c\/span\u003e';\n\n      if (showNext) {\n        const lastVisMonth = month;\n        const lastVisYear = year;\n        const canGoNext = !(lastVisYear === maxDate.getFullYear() \u0026\u0026 lastVisMonth \u003e= maxDate.getMonth());\n        html += '\u003cbutton type=\"button\" class=\"carca-game-cal-nav ' + (canGoNext ? '' : 'hidden') + '\" data-dir=\"next\" aria-label=\"Mois suivant\"\u003e\u0026#8250;\u003c\/button\u003e';\n      }\n\n      html += '\u003c\/div\u003e';\n\n      html += '\u003cdiv class=\"carca-game-cal-grid\"\u003e';\n      for (let d = 0; d \u003c 7; d++) {\n        html += '\u003cdiv class=\"carca-game-cal-dow\"\u003e' + dowLabels[d] + '\u003c\/div\u003e';\n      }\n\n      const firstDay = new Date(year, month, 1);\n      let startDow = firstDay.getDay();\n      startDow = startDow === 0 ? 6 : startDow - 1;\n\n      const daysInMonth = new Date(year, month + 1, 0).getDate();\n\n      for (let e = 0; e \u003c startDow; e++) {\n        html += '\u003cdiv class=\"carca-game-cal-day empty\"\u003e\u003c\/div\u003e';\n      }\n\n      for (let day = 1; day \u003c= daysInMonth; day++) {\n        const date = new Date(year, month, day);\n        const isDisabled = date \u003c minDate || date \u003e maxDate;\n        const isSelected = selectedDate \u0026\u0026 date.getTime() === selectedDate.getTime();\n\n        let cls = 'carca-game-cal-day';\n        if (isDisabled) cls += ' disabled';\n        if (isSelected) cls += ' selected';\n\n        const dateStr = year + '-' + String(month + 1).padStart(2, '0') + '-' + String(day).padStart(2, '0');\n\n        html += '\u003cbutton type=\"button\" class=\"' + cls + '\" data-date=\"' + dateStr + '\"\u003e' + day + '\u003c\/button\u003e';\n      }\n\n      html += '\u003c\/div\u003e\u003c\/div\u003e';\n    }\n\n    html += '\u003c\/div\u003e';\n    calContainer.innerHTML = html;\n\n    calContainer.querySelectorAll('.carca-game-cal-day:not(.disabled):not(.empty)').forEach(function (btn) {\n      btn.addEventListener('click', function () {\n        const parts = btn.dataset.date.split('-');\n        selectedDate = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2]));\n        dateInput.value = btn.dataset.date;\n\n        calSelectedDisplay.textContent = selectedDate.toLocaleDateString('fr-FR', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });\n        calSelectedDisplay.classList.add('visible');\n\n        renderCalendar();\n      });\n    });\n\n    calContainer.querySelectorAll('.carca-game-cal-nav').forEach(function (btn) {\n      btn.addEventListener('click', function () {\n        if (btn.dataset.dir === 'prev') {\n          calBaseMonth--;\n          if (calBaseMonth \u003c 0) { calBaseMonth = 11; calBaseYear--; }\n        } else {\n          calBaseMonth++;\n          if (calBaseMonth \u003e 11) { calBaseMonth = 0; calBaseYear++; }\n        }\n        renderCalendar();\n      });\n    });\n  }\n\n  \/* ===== MODAL LOGIC ===== *\/\n  function showStep(stepNumber) {\n    steps.forEach(function (step) { if (step) step.classList.remove('active'); });\n    var target = document.getElementById('carca-game-step-' + stepNumber);\n    if (target) target.classList.add('active');\n  }\n\n  if (modal.parentElement !== document.body) {\n    document.body.appendChild(modal);\n  }\n\n  function openModal() {\n    modal.classList.add('open');\n    modal.setAttribute('aria-hidden', 'false');\n    document.documentElement.style.overflow = 'hidden';\n    document.body.style.overflow = 'hidden';\n    updatePriceDisplay();\n    renderCalendar();\n  }\n\n  function closeModal() {\n    modal.classList.remove('open');\n    modal.setAttribute('aria-hidden', 'true');\n    document.documentElement.style.overflow = '';\n    document.body.style.overflow = '';\n  }\n\n  function resetModalFields() {\n    participantsCount = 1;\n    updateParticipantsUI();\n    dateInput.value = '';\n    selectedDate = null;\n    calSelectedDisplay.classList.remove('visible');\n    calSelectedDisplay.textContent = '';\n    calBaseMonth = minDate.getMonth();\n    calBaseYear = minDate.getFullYear();\n    showStep(1);\n  }\n\n  function escapeHtml(str) {\n    return String(str || '')\n      .replace(\/\u0026\/g, '\u0026amp;')\n      .replace(\/\u003c\/g, '\u0026lt;')\n      .replace(\/\u003e\/g, '\u0026gt;')\n      .replace(\/\"\/g, '\u0026quot;')\n      .replace(\/'\/g, '\u0026#039;');\n  }\n\n  function updateReview() {\n    var displayDate = selectedDate\n      ? selectedDate.toLocaleDateString('fr-FR', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })\n      : '';\n\n    reviewBox.innerHTML =\n      '\u003cdiv class=\"carca-game-review-item\"\u003e' +\n        '\u003cdiv class=\"carca-game-review-label\"\u003eNombre de participants\u003c\/div\u003e' +\n        '\u003cdiv\u003e' + participantsCount + '\u003c\/div\u003e' +\n      '\u003c\/div\u003e' +\n      '\u003cdiv class=\"carca-game-review-item\"\u003e' +\n        '\u003cdiv class=\"carca-game-review-label\"\u003eDate\u003c\/div\u003e' +\n        '\u003cdiv\u003e' + escapeHtml(displayDate) + '\u003c\/div\u003e' +\n      '\u003c\/div\u003e' +\n      '\u003cdiv class=\"carca-game-review-item\"\u003e' +\n        '\u003cdiv class=\"carca-game-review-label\"\u003eLangue\u003c\/div\u003e' +\n        '\u003cdiv\u003eVous choisirez votre langue préférée après la réservation sur tickets-connect.com\u003c\/div\u003e' +\n      '\u003c\/div\u003e';\n  }\n\n  let savedBookingData = null;\n\n  function saveBookingDetailsToForms() {\n    savedBookingData = {\n      'Number of Participants': String(participantsCount),\n      'Game Date': dateInput.value\n    };\n    confirmedBadge.style.display = 'block';\n    unlockCartButtons();\n  }\n\n  function getCartButtons() {\n    var selectors = [\n      'button[name=\"add\"]',\n      'button[type=\"submit\"][name=\"add\"]',\n      '.shopify-payment-button button',\n      '.shopify-payment-button__button',\n      'buy-it-now button',\n      '[data-shopify=\"payment-button\"] button'\n    ];\n    return document.querySelectorAll(selectors.join(', '));\n  }\n\n  function lockCartButtons() {\n    getCartButtons().forEach(function (btn) {\n      btn.disabled = true;\n      btn.style.opacity = '0.4';\n      btn.style.cursor = 'not-allowed';\n      btn.style.pointerEvents = 'none';\n    });\n  }\n\n  function unlockCartButtons() {\n    getCartButtons().forEach(function (btn) {\n      btn.disabled = false;\n      btn.style.opacity = '';\n      btn.style.cursor = '';\n      btn.style.pointerEvents = '';\n    });\n  }\n\n  lockCartButtons();\n  var productSection = document.querySelector('product-info') || document.querySelector('.product');\n  if (productSection) {\n    var observer = new MutationObserver(function () {\n      if (!savedBookingData) {\n        lockCartButtons();\n      }\n    });\n    observer.observe(productSection, { childList: true, subtree: true });\n  }\n\n  \/\/ Intercept fetch calls to \/cart\/add to inject booking properties\n  const originalFetch = window.fetch;\n  window.fetch = function (url, options) {\n    if (typeof url === 'string' \u0026\u0026 url.includes('\/cart\/add')) {\n      if (!savedBookingData) {\n        alert('Veuillez choisir votre date et compléter les détails de réservation avant d\\'ajouter au panier.');\n        return Promise.reject(new Error('Booking details required'));\n      }\n      if (options \u0026\u0026 options.body instanceof FormData) {\n        for (const [key, value] of Object.entries(savedBookingData)) {\n          options.body.append('properties[' + key + ']', value);\n        }\n      }\n    }\n    return originalFetch.apply(this, arguments);\n  };\n\n  function validateStep1() {\n    if (participantsCount \u003c 1) {\n      alert('Veuillez sélectionner au moins 1 participant.');\n      return false;\n    }\n    return true;\n  }\n\n  function validateStep2() {\n    if (!dateInput.value) {\n      alert('Veuillez sélectionner une date.');\n      return false;\n    }\n    return true;\n  }\n\n  \/* ===== EVENT LISTENERS ===== *\/\n  modalOpenBtn.addEventListener('click', function () {\n    openModal();\n    showStep(1);\n  });\n\n  modalCloseBtn.addEventListener('click', closeModal);\n  modalBackdrop.addEventListener('click', closeModal);\n\n  toStep2Btn.addEventListener('click', function () {\n    if (!validateStep1()) return;\n    renderCalendar();\n    showStep(2);\n  });\n\n  backToStep1Btn.addEventListener('click', function () {\n    showStep(1);\n  });\n\n  toStep3Btn.addEventListener('click', function () {\n    if (!validateStep2()) return;\n    updateReview();\n    showStep(3);\n  });\n\n  restartBtn.addEventListener('click', function () {\n    resetModalFields();\n    savedBookingData = null;\n    confirmedBadge.style.display = 'none';\n    lockCartButtons();\n    closeModal();\n  });\n\n  confirmBtn.addEventListener('click', function () {\n    saveBookingDetailsToForms();\n    closeModal();\n  });\n\n  let resizeTimer;\n  window.addEventListener('resize', function () {\n    clearTimeout(resizeTimer);\n    resizeTimer = setTimeout(renderCalendar, 150);\n  });\n\n  syncAll();\n});\n\u003c\/script\u003e\n","brand":"Visit Carcassonne","offers":[{"title":"1","offer_id":56792466981188,"sku":null,"price":5.0,"currency_code":"EUR","in_stock":true},{"title":"2","offer_id":56792467013956,"sku":null,"price":9.0,"currency_code":"EUR","in_stock":true},{"title":"3","offer_id":56792467046724,"sku":null,"price":12.0,"currency_code":"EUR","in_stock":true},{"title":"4","offer_id":56792467079492,"sku":null,"price":14.0,"currency_code":"EUR","in_stock":true},{"title":"5","offer_id":56792467112260,"sku":null,"price":15.0,"currency_code":"EUR","in_stock":true},{"title":"6","offer_id":56792467145028,"sku":null,"price":16.0,"currency_code":"EUR","in_stock":true},{"title":"7","offer_id":56792467177796,"sku":null,"price":17.0,"currency_code":"EUR","in_stock":true},{"title":"8","offer_id":56792467210564,"sku":null,"price":18.0,"currency_code":"EUR","in_stock":true},{"title":"9","offer_id":56792467243332,"sku":null,"price":19.0,"currency_code":"EUR","in_stock":true},{"title":"10","offer_id":56792467276100,"sku":null,"price":20.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0900\/0252\/2436\/files\/medieval-cite-citadel-of-carcassonne-by-night.png?v=1753436810","url":"https:\/\/visit-carcassonne.com\/fr\/products\/jeu-cite-carcassonne","provider":"Visit Carcassonne","version":"1.0","type":"link"}