{% extends 'vitrine/en/layout.html.twig' %}{% block title %}Cathedral Heritage Suite - 8-Guest Rental Strasbourg Center{% endblock title %}{% block description %}Rent our 83m² suite in the heart of Strasbourg. 3 bedrooms, sleeps 8, 100m from Cathedral. Kitchen fully furnished, 2 bathrooms. Book your stay today!{% endblock description %}{% block robots %}index,follow{% endblock robots %}{% block canonical %}<link rel="canonical" href="https://cathedraleheritage.com" /><link rel="alternate" hreflang="fr" href="https://cathedraleheritage.com/fr" /><link rel="alternate" hreflang="en" href="https://cathedraleheritage.com" /><link rel="alternate" hreflang="x-default" href="https://cathedraleheritage.com" />{% endblock canonical %}{% block body %}<section id="hero" class="text-light no-top no-bottom relative overflow-hidden z-1000"><div class="abs w-100 abs-centered z-2"><div class="container"><div class="spacer-double"></div><div class="row g-4 align-items-center justify-content-center"><div class="col-md-8 text-center"><h1 class="mb-2" style="color:white;">Welcome to Cathedral Heritage Suite</h1><p class="lead mb-3" style="color:white; font-size:22px;">Beautifully appointed apartment accommodating up to 8 guests in Strasbourg's prestigious historical city center</p><a class="btn-main btn-line bg-blur fx-slide" href="#about" style="color:white;"><span>Find out more</span></a></div></div></div></div><div class="vertical-center"><div class="swiper"><div class="swiper-wrapper"><div class="swiper-slide"><div class="swiper-inner" data-bgimage="url(/images/salon2.jpeg)"><div class="sw-overlay op-5"></div></div></div><div class="swiper-slide"><div class="swiper-inner" data-bgimage="url(/images/chambre2.jpeg)"><div class="sw-overlay op-5"></div></div></div><div class="swiper-slide"><div class="swiper-inner" data-bgimage="url(/images/noel.jpeg)"><div class="sw-overlay op-5"></div></div></div></div></div></div><div class="abs w-100 bottom-0 z-2 pb-4 sm-hide"><div class="container"><div class="row"><div class="col-lg-12"><div class="d-flex justify-content-between"><div><h6 style="color:white;">Cathedral 100m away</h6></div><div><h6 style="color:white;">Museums 200m away</h6></div><div><h6 style="color:white;">Petite France 300m away</h6></div></div></div></div></div></div><div class="gradient-edge-bottom op-8"></div></section><section id="about"><div class="container"><div class="row g-4 align-items-end justify-content-between"><div class="col-lg-5"><div class="subtitle">About the apartment</div><h2>Modern suite in the heart of Strasbourg's Grande Île</h2></div><div class="col-lg-4"><p class="mb-4" style="color:#212121;">Spacious fully equipped appartement ideal for families and groups up to 8 people : 1 master bedroom with en-suite bathroom, one double bedroom, one bedroom with two double bunk beds (sleeps 4), maximum weight of 100kg for upper bunks.</p><p class="mb-4" style="color:#212121;">Kitchen fully furnished and cozy living-dining room to share great moments together.</p><p class="mb-4" style="color:#212121;">Amenities: hairdryer, dishwasher, washer-dryer, microwave, oven, ironing board with iron, Nespresso coffee machine, kettle, TV, Wi-Fi and USB outlets for charging your devices.</p></div></div><div class="spacer-single"></div><div class="row g-4"><div class="col-md-2"><div class="relative"><h5>Size</h5><div class="d-flex justify-content-start align-items-center" style="padding-top:6px;"><img src="/images/home.png" width="37" class="me-3" alt=""><div class="fs-20 fw-600" style="color:#212121;">83 m²</div></div></div></div><div class="col-md-2"><div class="relative"><h5>Bedrooms</h5><div class="d-flex justify-content-start align-items-center" style="padding-top:4px;"><img src="/images/bed.png" width="37" class="me-3" alt=""><div class="fs-20 fw-600" style="color:#212121;">3</div></div></div></div><div class="col-md-2"><div class="relative"><h5>Living Room</h5><div class="d-flex justify-content-start align-items-center"><img src="/images/sofa.png" width="50" class="me-3" alt=""><div class="fs-20 fw-600" style="color:#212121;">Included</div></div></div></div><div class="col-md-2"><div class="relative"><h5>Kitchen</h5><div class="d-flex justify-content-start align-items-center" style="padding-top:6px;"><img src="/images/cooking.png" width="37" class="me-3" alt=""><div class="fs-20 fw-600" style="color:#212121;">Included</div></div></div></div><div class="col-md-2"><div class="relative"><h5>Bathrooms</h5><div class="d-flex justify-content-start align-items-center" style="padding-top:4px;"><img src="/images/bathroom.png" width="40" class="me-3" alt=""><div class="fs-20 fw-600" style="color:#212121;">2</div></div></div></div><div class="col-md-2"><div class="relative"><h5>Guests</h5><div class="d-flex justify-content-start align-items-center" style="padding-top:5px;"><img src="/images/user.png" width="37" class="me-3" alt=""><div class="fs-20 fw-600" style="color:#212121;">8</div></div></div></div></div></div></section><section id="rooms" class="p-0 overflow-hidden"><div class="container-fluid"><div class="row"><div class="col-lg-12"><div class="owl-custom-nav menu-float" data-target="#room-carousel"><a class="btn-next"></a><a class="btn-prev"></a><div id="room-carousel" class="owl-2-cols-center owl-carousel owl-theme"><div class="item"><div class="relative"><div class="overflow-hidden text-light"><div class="abs h-100 start-0 z-2 p-4"><h3 style="color:white;">Living Room</h3></div><img src="/images/salon2.jpeg" class="w-100" alt="Living Room"></div></div></div><div class="item"><div class="relative"><div class="overflow-hidden text-light"><div class="abs h-100 start-1 z-2 p-4"><h3 style="color:white;">Bedroom 1</h3></div><img src="/images/chambre1.jpeg" class="w-100" alt="Bedroom 1"></div></div></div><div class="item"><div class="relative"><div class="overflow-hidden text-light"><div class="abs h-100 start-2 z-2 p-4"><h3 style="color:white;">Bedroom 2</h3></div><img src="/images/chambre2.jpeg" class="w-100" alt="Bedroom 2"></div></div></div><div class="item"><div class="relative"><div class="overflow-hidden text-light"><div class="abs h-100 start-3 z-2 p-4"><h3 style="color:white;">Bedroom 3</h3></div><img src="/images/chambre3.jpeg" class="w-100" alt="Bedroom 3"></div></div></div><div class="item"><div class="relative"><div class="overflow-hidden text-light"><div class="abs h-100 start-4 z-2 p-4"><h3 style="color:white;">Kitchen</h3></div><img src="/images/cuisine.jpeg" class="w-100" alt="Kitchen"></div></div></div><div class="item"><div class="relative"><div class="overflow-hidden text-light"><div class="abs h-100 start-5 z-2 p-4"><h3 style="color:white;">Bathroom</h3></div><img src="/images/salledebain.jpeg" class="w-100" alt="Bathroom 1"></div></div></div><div class="item"><div class="relative"><div class="overflow-hidden text-light"><div class="abs h-100 start-6 z-2 p-4"><h3 style="color:white;">Bathroom 2</h3></div><img src="/images/salledebain2.jpeg" class="w-100" alt="Bathroom 2"></div></div></div></div></div></div></div></div></section><section id="services" class="overlay-dark-1"><div class="container"><div class="row g-4 justify-content-between"><div class="col-lg-5 relative z-3"><div class="me-lg-3"><div class="subtitle wow fadeInUp" data-wow-delay=".0s">Your stay in Strasbourg</div><h2 class="wow fadeInUp" data-wow-delay=".2s">Rates and services</h2><p style="color:#212121; font-size:18px;">An exceptional suite in the heart of Strasbourg, with optionnal dedicated concierge service to assist you throughout your stay.</p><p style="color:#212121; font-size:18px;">Minimum booking of two nights.</p><a href="#reservation" class="btn-main" style="color:white;">Booking</a></div></div><div class="col-lg-6" style="color:black;"><div class="spacer-single spacer-double"></div><div class="row"><div class="col-md-6 wow fadeInUp" data-wow-delay=".2s">{#<h5 class=" mb-3">Peak Season</h5><p class="fs-500"><small>June 1st to September 30th • November 25th to January 5th</small></p><ul class="ul-check fs-500"><li>€960 per night</li><li>10% discount for bookings of 7 nights and up</li></ul><h5 class="mb-3 mt-4">Off-peak Season</h5>#}<ul class="ul-check fs-500"><li>from €350 per night</li><li>10% discount for bookings of 7 nights and up</li></ul></div><div class="col-md-6 wow fadeInUp" data-wow-delay=".4s"><h5 class="mb-3">Optional services</h5><ul class="ul-check fs-500"><li>One parking space: €24/day or €150/week</li><li>Extra cleaning during your stay : 60 euros</li><li>Other Extras : Children's workshop, baby amenities, dog policy on request (other pets are unfortunately not allowed in the appartement), Decoration for special occasions, breakfast, Alsatian delicacies, etc</li></ul><div class="mt-4"><p class="fs-500"><strong>On site assistance</strong> <br /><small>Tuesday to Saturday • 10am-6:45pm</small></p><p class="fs-500"><strong>Private concierge subject to availability</strong><br><small>Quotation on request</small></p></div></div></div></div></div></div></section><section id="section-gallery" class="relative"><div class="container relative z-2" id="photos"><div class="row g-4 gx-5 justify-content-center"><div class="col-lg-6 text-center"><h2 class="wow fadeInUp" data-wow-delay=".2s">Apartment Gallery</h2><p class="wow fadeInUp" data-wow-delay=".3s" style="color:#212121;">Explore our curated images to discover the residence's various spaces — from the bedrooms and living area to the kitchen, bathroom, and outdoor surroundings.</p></div></div><div class="row"><div class="col-md-12 text-center"><ul id="filters" class="wow fadeInUp" data-wow-delay="0s"><li><a href="#" data-filter="*" class="selected" style="color:#212121;">Show All</a></li><li><a href="#" data-filter=".chambre" style="color:#212121;">Bedrooms</a></li><li><a href="#" data-filter=".salon" style="color:#212121;">Living Room</a></li><li><a href="#" data-filter=".cuisine" style="color:#212121;">Kitchen</a></li><li><a href="#" data-filter=".salledebain" style="color:#212121;">Bathroom</a></li><li><a href="#" data-filter=".exterieur" style="color:#212121;">Outdoor surroundings</a></li></ul></div></div><div id="gallery" class="row g-3 wow fadeInUp" data-wow-delay=".3s"><div class="col-md-3 col-sm-6 col-12 item chambre"><a href="images/chambre1.jpeg" class="image-popup d-block hover"><div class="relative overflow-hidden"><div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">View</div><div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div><img src="images/chambre1.jpeg" class="w-100 hover-scale-1-2" alt="Bedroom"></div></a></div><div class="col-md-3 col-sm-6 col-12 item chambre"><a href="images/chambre2.jpeg" class="image-popup d-block hover"><div class="relative overflow-hidden"><div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">View</div><div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div><img src="images/chambre2.jpeg" class="w-100 hover-scale-1-2" alt="Bedroom 2"></div></a></div><div class="col-md-3 col-sm-6 col-12 item chambre"><a href="images/chambre3.jpeg" class="image-popup d-block hover"><div class="relative overflow-hidden"><div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">View</div><div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div><img src="images/chambre3.jpeg" class="w-100 hover-scale-1-2" alt="Bedroom 3"></div></a></div><div class="col-md-3 col-sm-6 col-12 item salon"><a href="images/salon.jpeg" class="image-popup d-block hover"><div class="relative overflow-hidden"><div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">View</div><div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div><img src="images/salon.jpeg" class="w-100 hover-scale-1-2" alt="Living Room"></div></a></div><div class="col-md-3 col-sm-6 col-12 item salon"><a href="images/salon2.jpeg" class="image-popup d-block hover"><div class="relative overflow-hidden"><div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">View</div><div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div><img src="images/salon2.jpeg" class="w-100 hover-scale-1-2" alt="Living Room 2"></div></a></div><div class="col-md-3 col-sm-6 col-12 item salon"><a href="images/salon3.jpeg" class="image-popup d-block hover"><div class="relative overflow-hidden"><div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">View</div><div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div><img src="images/salon3.jpeg" class="w-100 hover-scale-1-2" alt="Living Room 3"></div></a></div><div class="col-md-3 col-sm-6 col-12 item salon"><a href="images/salon4.jpeg" class="image-popup d-block hover"><div class="relative overflow-hidden"><div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">View</div><div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div><img src="images/salon4.jpeg" class="w-100 hover-scale-1-2" alt="Living Room 4"></div></a></div><div class="col-md-3 col-sm-6 col-12 item salon"><a href="images/salon5.jpeg" class="image-popup d-block hover"><div class="relative overflow-hidden"><div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">View</div><div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div><img src="images/salon5.jpeg" class="w-100 hover-scale-1-2" alt="Living Room 5"></div></a></div><div class="col-md-3 col-sm-6 col-12 item cuisine"><a href="images/cuisine.jpeg" class="image-popup d-block hover"><div class="relative overflow-hidden"><div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">View</div><div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div><img src="images/cuisine.jpeg" class="w-100 hover-scale-1-2" alt="Kitchen"></div></a></div><div class="col-md-3 col-sm-6 col-12 item salledebain"><a href="images/salledebain.jpeg" class="image-popup d-block hover"><div class="relative overflow-hidden"><div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">View</div><div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div><img src="images/salledebain.jpeg" class="w-100 hover-scale-1-2" alt="Bathroom"></div></a></div><div class="col-md-3 col-sm-6 col-12 item salledebain"><a href="images/salledebain2.jpeg" class="image-popup d-block hover"><div class="relative overflow-hidden"><div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">View</div><div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div><img src="images/salledebain2.jpeg" class="w-100 hover-scale-1-2" alt="Bathroom 2"></div></a></div><div class="col-md-3 col-sm-6 col-12 item exterieur"><a href="images/exterieur.jpeg" class="image-popup d-block hover"><div class="relative overflow-hidden"><div class="absolute start-0 w-100 hover-op-1 p-5 abs-middle z-2 text-center text-white z-3">View</div><div class="absolute start-0 w-100 h-100 overlay-dark-7 hover-op-1 z-2"></div><img src="images/exterieur.jpeg" class="w-100 hover-scale-1-2" alt="Exterior"></div></a></div></div></div></section>{# =================================================== #}{# ============ BOOKING SECTION (refactored) ========= #}{# =================================================== #}<section id="reservation" class="text-light"><div class="container"><div class="row g-4 justify-content-center"><div class="col-lg-6 text-center"><h2 class="wow fadeInUp" data-wow-delay=".2s">Book your stay</h2></div></div><div class="row g-4 justify-content-center"><div class="col-lg-8"><div class="booking-card">{{ form_start(form) }}{# ----- CALENDAR ----- #}<div class="calendar-container" style="height:300px;"><input type="text" id="date_range_picker"></div>{# ----- DATES RECAP (just below the calendar) ----- #}<div class="row g-3 mt-2 dates-recap"><div class="col-4 text-center"><div class="recap-label">Arrival</div><div class="recap-value" id="info-start">-</div></div><div class="col-4 text-center"><div class="recap-label">Departure</div><div class="recap-value" id="info-end">-</div></div><div class="col-4 text-center"><div class="recap-label">Nights</div><div class="recap-value" id="info-nights">-</div></div></div><hr class="booking-divider">{# ----- COUNTERS ----- #}<h4 class="booking-title">Select rooms and guests</h4><div class="counter-row"><div class="counter-label"><div class="counter-title">Bedrooms</div><div class="counter-sub">Set by guest count</div></div><div class="counter-controls"><button type="button" class="counter-btn" data-action="dec" data-target="rooms">−</button><span class="counter-value" id="cnt-rooms">1</span><button type="button" class="counter-btn" data-action="inc" data-target="rooms">+</button></div></div><div class="counter-row"><div class="counter-label"><div class="counter-title">Adults</div></div><div class="counter-controls"><button type="button" class="counter-btn" data-action="dec" data-target="adults">−</button><span class="counter-value" id="cnt-adults">2</span><button type="button" class="counter-btn" data-action="inc" data-target="adults">+</button></div></div><div class="counter-row"><div class="counter-label"><div class="counter-title">Children</div><div class="counter-sub">1 - 17 years</div></div><div class="counter-controls"><button type="button" class="counter-btn" data-action="dec" data-target="children">−</button><span class="counter-value" id="cnt-children">0</span><button type="button" class="counter-btn" data-action="inc" data-target="children">+</button></div></div><div id="capacity-warning" class="capacity-warning" style="display:none;"></div>{# ----- PRICE RESULT ----- #}<div id="results" class="mt-3"></div><hr class="booking-divider">{# ----- PERSONAL INFO ----- #}<div class="row g-3"><div class="col-md-6"><label class="booking-label">Last name</label>{{ form_widget(form.lastname) }}</div><div class="col-md-6"><label class="booking-label">First name</label>{{ form_widget(form.name) }}</div><div class="col-md-12"><label class="booking-label">Email address</label>{{ form_widget(form.email) }}</div><div class="col-md-12"><label class="booking-label">Message</label>{{ form_widget(form.message) }}</div></div>{# ----- T&C + SUBMIT ----- #}<div class="text-center mt-4 cgv-block"><input type="checkbox" id="acceptCGV" /> I accept the <a href="/terms" target="_blank" style="color:#212121; text-decoration:underline;">terms and conditions of sale</a></div><div class="text-center mt-3"><button type="submit" name="submit" value="1" class="btn-main" style="color:white;">Send booking request</button></div>{# Hidden fields #}{{ form_widget(form.start) }}{{ form_widget(form.end) }}{{ form_widget(form.rooms) }}{{ form_widget(form.adults) }}{{ form_widget(form.children) }}{{ form_widget(form.persons) }}{{ form_rest(form) }}{{ form_end(form) }}</div></div></div></div></section><section id="faq" class="text-light"><div class="container"><div class="row g-4 justify-content-center"><div class="col-lg-6 text-center"><h2 class="wow fadeInUp" data-wow-delay=".2s">FAQ</h2></div></div><div class="row g-4 justify-content-center"><div class="col-lg-6 text-left" style="color:black !important;"><h3 style="margin-top:7px;">How can I book the accommodation?</h3><div>You can book directly on our website and soon via partner platforms. Secure payment immediately confirms your reservation.</div><h3 style="margin-top:7px;">What are the check-in and check-out times?</h3><div><ul><li>Check-in: from 3:00 PM</li><li>Check-out: before 11:00 AM</li></ul></div><h3 style="margin-top:7px;">Is the accommodation fully equipped?</h3><div> Yes, the apartment is fully furnished and equipped: kitchen, bedding, towels, appliances, Wi-Fi, and more.</div><h3 style="margin-top:7px;">Is parking available?</h3><div>Yes, private parking is available as an option at €24 per 24 hours or €150 per week (7 nights).</div><h3 style="margin-top:7px;">Is the accommodation suitable for children?</h3><div>Yes, we offer some baby amenities (baby cot, high chair, child-friendly tableware) upon request.</div><h3 style="margin-top:7px;"> Are pets allowed?</h3><div> Please contact us before booking if you wish to bring a pet. Only dogs are accepted, and prior approval is required.</div><h3 style="margin-top:7px;">Can I cancel or modify my reservation?</h3><div>Yes, our cancellation policy is provided at the time of booking:<ul><li>85% refund if canceled more than 1 month before arrival</li><li>50% refund if canceled between 1 month and 15 days before arrival</li><li>No refund if canceled less than 15 days before arrival</li></ul></div><h3 style="margin-top:7px;">Is the accommodation accessible by public transport?</h3><div>Yes, major transport options are nearby. The tram station "Langstross, Grand'rue" is less than 100 meters from the apartment, and Strasbourg train station is a 10-minute walk.</div><h3 style="margin-top:7px;">Are there shops or restaurants nearby?</h3><div>Yes, you'll find supermarkets, cafés, restaurants, and tourist activities right at the foot of the building.</div><h3 style="margin-top:7px;"> What should I do if there's a problem during my stay?</h3><div> We are available 24/7 by email for emergencies or questions about the apartment. You can also call us from 9:00 AM to 8:00 PM at +33 7 61 05 82 43, and we are available on-site on the ground floor of the building from Tuesday to Saturday, 10:00 AM to 6:45 PM.</div></div></div></div></section>{% endblock body %}{% block footerjs %}<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>{# Pricing matrix + simulation URL exposed to JS #}<script>window.PRICING_MATRIX = {{ pricingMatrix|json_encode|raw }};window.SIMULATION_URL = "{{ path('simulation_pricing') }}";console.log('📋 Off-peak pricing matrix loaded:', window.PRICING_MATRIX);console.log('🔗 Simulation URL:', window.SIMULATION_URL);</script><script>// ===========================================================// Bedrooms / adults / children logic//// Physical layout:// - Bedroom A: double bed → 2 people// - Bedroom B: double bed → 2 people// - Bedroom C: bunk beds → 4 people (adults/children mix)//// The number of bedrooms is DETERMINED automatically (no choice)://// WITHOUT CHILDREN:// 1-2 ad → 1 br// 3-4 ad → 2 br// 5-8 ad → 3 br//// WITH CHILDREN:// 1-2 ad → 2 br (bedroom A + bunk room)// 3+ ad → 3 br (A + B + bunk room)//// Constraints: adults + children ≤ 8, children ≤ 4, adults ≥ 1// ===========================================================function roomsForCombo(adults, children) {if (children > 0) {return adults <= 2 ? 2 : 3;}if (adults <= 2) return 1;if (adults <= 4) return 2;return 3;}function canAddAdult(state) {if (state.adults >= 8) return false;return (state.adults + 1 + state.children) <= 8;}function canAddChild(state) {if (state.children >= 4) return false;return (state.adults + state.children + 1) <= 8;}const state = { rooms: 1, adults: 2, children: 0 };function updateDisplay() {// Bedrooms count is recalculated automatically on each updatestate.rooms = roomsForCombo(state.adults, state.children);$('#cnt-rooms').text(state.rooms);$('#cnt-adults').text(state.adults);$('#cnt-children').text(state.children);$('#reservation_form_rooms').val(state.rooms);$('#reservation_form_adults').val(state.adults);$('#reservation_form_children').val(state.children);$('#reservation_form_persons').val(state.adults + state.children);$('.counter-btn').each(function() {const target = $(this).data('target');const action = $(this).data('action');let disabled = false;if (target === 'rooms') {// Bedrooms = always locked (set by adults/children)disabled = true;}if (target === 'adults') {if (action === 'dec' && state.adults <= 1) disabled = true;if (action === 'inc' && !canAddAdult(state)) disabled = true;}if (target === 'children') {if (action === 'dec' && state.children <= 0) disabled = true;if (action === 'inc' && !canAddChild(state)) disabled = true;}$(this).prop('disabled', disabled).toggleClass('disabled', disabled);});$('#capacity-warning').hide();}$(document).on('click', '.counter-btn', function() {if ($(this).prop('disabled')) return;const target = $(this).data('target');const action = $(this).data('action');// No action on "rooms" (always disabled)if (target === 'adults') {if (action === 'inc' && canAddAdult(state)) state.adults++;if (action === 'dec' && state.adults > 1) state.adults--;}if (target === 'children') {if (action === 'inc' && canAddChild(state)) state.children++;if (action === 'dec' && state.children > 0) state.children--;}updateDisplay();updateSimulation();});function updateSimulation() {const start = $("#reservation_form_start").val();const end = $("#reservation_form_end").val();const persons = state.adults + state.children;console.log('🔄 updateSimulation', { start, end, rooms: state.rooms, adults: state.adults, children: state.children });if (!start || !end || persons < 1) {$("#results").html('');return;}$("#results").html('<div class="loading" style="color:#212121;">Calculating...</div>');$.post(window.SIMULATION_URL,{ start: start, end: end, rooms: state.rooms, adults: state.adults, children: state.children }).done(function(data) {console.log('✅ Simulation OK');$("#results").html(data);}).fail(function(xhr) {console.error('❌ Simulation KO', xhr.status, xhr.responseText);$("#results").html('<div class="error" style="color:#a00;">Error calculating price (' + xhr.status + ')</div>');});}$(document).ready(function() {updateDisplay();$('button[type="submit"]').prop('disabled', true);$('#acceptCGV').change(function() {$('button[type="submit"]').prop('disabled', !$(this).is(':checked'));});});</script><script>// ===========================================================// Flatpickr calendar// ===========================================================$(document).ready(function() {let bookedRanges = [];$.ajax({url: '{{ env('WEBHOOK_CALENDAR_AVAILABILITY') }}',method: 'POST',contentType: 'application/json',data: ''}).done(function(data) {bookedRanges = data.bookings || [];initDatePicker();}).fail(function() { initDatePicker(); });function parseLocalDate(dateStr) {const [year, month, day] = dateStr.split('-').map(Number);return new Date(year, month - 1, day);}const isMobile = window.innerWidth <= 900;function initDatePicker() {flatpickr("#date_range_picker", {inline: true,mode: "range",minDate: new Date(new Date().setDate(new Date().getDate() + 1)),dateFormat: "Y-m-d",showMonths: isMobile ? 1 : 2,disable: [function(date) {const checkDate = new Date(date);checkDate.setHours(0, 0, 0, 0);return bookedRanges.some(range => {const start = parseLocalDate(range.start_date);const end = parseLocalDate(range.end_date);return checkDate >= start && checkDate <= end;});}],onChange: function(selectedDates, dateStr, instance) {if (selectedDates.length === 2) {const start = selectedDates[0];const end = selectedDates[1];if (isRangeAvailable(start, end)) {$('#reservation_form_start').val(formatDate(start)).trigger('change');$('#reservation_form_end').val(formatDate(end)).trigger('change');updateSelectedInfo(start, end);updateSimulation();} else {alert('⚠️ This period contains already booked dates.');instance.clear();clearSymfonyFields();hideSelectedInfo();$("#results").html('');}} else {clearSymfonyFields();hideSelectedInfo();$("#results").html('');}},onDayCreate: function(dObj, dStr, fp, dayElem) {const date = new Date(dayElem.dateObj);date.setHours(0, 0, 0, 0);const isBooked = bookedRanges.some(range => {const start = parseLocalDate(range.start_date);const end = parseLocalDate(range.end_date);return date >= start && date <= end;});if (isBooked) {dayElem.classList.add('booked');dayElem.title = 'Unavailable date (booked)';} else if (date >= new Date()) {dayElem.classList.add('available');}}});}function isRangeAvailable(startDate, endDate) {let currentDate = new Date(startDate);currentDate.setHours(0, 0, 0, 0);const endCheck = new Date(endDate);endCheck.setHours(0, 0, 0, 0);while (currentDate <= endCheck) {const isBooked = bookedRanges.some(range => {const start = parseLocalDate(range.start_date);const end = parseLocalDate(range.end_date);return currentDate >= start && currentDate <= end;});if (isBooked) return false;currentDate.setDate(currentDate.getDate() + 1);}return true;}function updateSelectedInfo(start, end) {const nights = Math.ceil((end - start) / (1000 * 60 * 60 * 24));$('#info-start').text(start.toLocaleDateString('en-GB'));$('#info-end').text(end.toLocaleDateString('en-GB'));$('#info-nights').text(nights + ' night' + (nights > 1 ? 's' : ''));}function hideSelectedInfo() {$('#info-start').text('-');$('#info-end').text('-');$('#info-nights').text('-');}function clearSymfonyFields() {$('#reservation_form_start').val('');$('#reservation_form_end').val('');}function formatDate(date) {return date.getFullYear() + '-' +String(date.getMonth() + 1).padStart(2, '0') + '-' +String(date.getDate()).padStart(2, '0');}});</script>{% endblock footerjs %}{% block css %}<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css"><style>/* ===========================================================Booking card (white border, transparent bg, black text)=========================================================== */.booking-card {background: transparent;border: 2px solid white;border-radius: 12px;padding: 32px;color: #212121;}.booking-title {color: #212121;font-weight: 700;margin-bottom: 24px;}.booking-divider {border-top: 1px solid rgba(0,0,0,0.15);margin: 28px 0;}.booking-label {color: #212121;font-weight: 500;margin-bottom: 6px;display: block;}.booking-card input.form-control,.booking-card textarea.form-control {background: rgba(255,255,255,0.85) !important;border: 1px solid rgba(0,0,0,0.2) !important;color: #212121 !important;}.booking-card input.form-control::placeholder,.booking-card textarea.form-control::placeholder {color: rgba(0,0,0,0.4) !important;}.booking-card input.form-control:focus,.booking-card textarea.form-control:focus {border-color: #212121 !important;box-shadow: 0 0 0 0.2rem rgba(0,0,0,0.08) !important;}.cgv-block { color: #212121; }.cgv-block a { color: #212121; text-decoration: underline; }.dates-recap { color: #212121; }.recap-label {font-size: 13px;text-transform: uppercase;letter-spacing: 0.5px;opacity: 0.7;}.recap-value {font-size: 18px;font-weight: 600;margin-top: 4px;}.counter-row {display: flex;justify-content: space-between;align-items: center;padding: 14px 0;border-bottom: 1px solid rgba(0,0,0,0.1);}.counter-row:last-of-type { border-bottom: none; }.counter-title { font-size: 16px; font-weight: 500; color: #212121; }.counter-sub { font-size: 12px; color: rgba(0,0,0,0.6); margin-top: 2px; }.counter-controls { display: flex; align-items: center; gap: 12px; }.counter-btn {width: 40px;height: 40px;border-radius: 8px;border: 1.5px solid #212121;background: transparent;color: #212121;font-size: 20px;font-weight: 600;line-height: 1;cursor: pointer;transition: all 0.15s;}.counter-btn:hover:not(.disabled) { background: rgba(0,0,0,0.06); }.counter-btn.disabled,.counter-btn:disabled {border-color: rgba(0,0,0,0.2);color: rgba(0,0,0,0.25);cursor: not-allowed;background: transparent;}.counter-value {min-width: 28px;text-align: center;font-size: 16px;font-weight: 500;color: #212121;}.capacity-warning {margin-top: 12px;padding: 10px 14px;background: rgba(255,180,0,0.18);border: 1px solid rgba(180,120,0,0.5);border-radius: 6px;color: #8a4500;font-size: 14px;}.calendar-container {margin: 0 0 8px 0;width: 100%;display: flex;justify-content: center;}#date_range_picker { display: none; }.flatpickr-calendar.inline {box-shadow: 0 4px 12px rgba(0,0,0,0.15);border-radius: 8px;}.flatpickr-day.booked {background-color: #ff4444 !important;color: white !important;cursor: not-allowed !important;position: relative;}.flatpickr-day.booked::after {content: "✕";position: absolute;top: 50%; left: 50%;transform: translate(-50%, -50%);font-size: 20px;font-weight: bold;}.flatpickr-day.booked:hover { background-color: #ff0000 !important; }.flatpickr-day.available:hover { background-color: #28a745; color: white; }@media (max-width: 768px) {.booking-card { padding: 20px; }.calendar-container { margin: 0 0 8px 0; padding: 0; }.flatpickr-calendar.inline { width: 100% !important; max-width: 100% !important; }.flatpickr-months { padding: 8px 10px; }.flatpickr-days { width: 100% !important; }.dayContainer {width: 100% !important;min-width: 100% !important;max-width: 100% !important;}.flatpickr-day {height: 40px !important;line-height: 40px !important;flex-basis: 14.2857% !important;max-width: 14.2857% !important;}}</style>{% endblock css %}