<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Locations de Vacances & Gîtes Ruraux | Séjours Authentiques</title>
<meta name="description" content="Trouvez votre location de vacances ou gîte idéal. Maisons de charme, appartements confortables en zone rurale ou urbaine. Séjour autonome authentique."/>
<meta name="robots" content="index, follow"/>
<link rel="canonical" href="https://bassindarcachon.weetrip.fr/locations-gites"/>
<link rel="alternate" hreflang="fr" href="https://bassindarcachon.weetrip.fr/locations-gites"/>
<link rel="alternate" hreflang="en" href="https://bassindarcachon.weetrip.fr/en/locations-gites"/>
<link rel="alternate" hreflang="de" href="https://bassindarcachon.weetrip.fr/de/locations-gites"/>
<link rel="alternate" hreflang="it" href="https://bassindarcachon.weetrip.fr/it/locations-gites"/>
<link rel="alternate" hreflang="nl" href="https://bassindarcachon.weetrip.fr/nl/locations-gites"/>
<link rel="alternate" hreflang="es" href="https://bassindarcachon.weetrip.fr/es/locations-gites"/>
<link rel="alternate" hreflang="x-default" href="https://bassindarcachon.weetrip.fr/locations-gites"/>
<meta property="og:type" content="website"/>
<meta property="og:title" content="Locations de Vacances & Gîtes Ruraux | Séjours Authentiques"/>
<meta property="og:url" content="https://bassindarcachon.weetrip.fr/locations-gites"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.css"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css"/>
<link rel="stylesheet" href="https://kit-pro.fontawesome.com/releases/v7.2.0/css/pro.min.css"/>
<style>
/* ── Variables partagées ── */
:root {
--night: #08111f;
--deep: #0d1e35;
--ocean: #1a6b8a;
--ocean-lt:#2d8faf;
--gold: #c8a96e;
--gold-lt: #e0c990;
--sand: #f5efe6;
--sand-dk: #e8dfd0;
--foam: #ffffff;
--text: #1e1410;
--muted: #7a6e66;
--radius: 14px;
--shadow: 0 4px 24px rgba(26,107,138,.10);
--accent: #FF385C;
--dark: #222;
--ease-out: cubic-bezier(0.16,1,0.3,1);
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: var(--sand); color: var(--text); overflow-x: hidden; }
/* ══════════════════════════════════════════
CATALOGUE — styles
══════════════════════════════════════════ */
.header-brand {
display:flex; align-items:center; gap:12px; padding:10px 0 0; margin-bottom:4px;
}
.back-home {
display:flex; align-items:center; gap:6px; color:var(--muted);
text-decoration:none; font-size:.8rem; font-weight:600;
padding:5px 12px; border-radius:8px; border:1.5px solid var(--sand-dk);
transition:all .18s;
}
.back-home:hover { border-color:var(--muted); color:var(--text); background:var(--sand); }
.brand-sep { color:var(--sand-dk); font-size:1.2rem; }
.brand-name { font-size:1.15rem; font-style:italic; color:var(--ocean); }
nav { display:flex; gap:2px; flex-wrap:wrap; }
.nav-item {
display:flex; align-items:center; gap:7px; padding:10px 14px;
border:none; background:transparent; font-family:inherit; font-size:.83rem;
font-weight:600; color:var(--muted); cursor:pointer;
border-bottom:3px solid transparent; transition:color .18s,border-color .18s;
white-space:nowrap; text-decoration:none;
}
.nav-item:hover { color:var(--text); }
.nav-item.active { color:var(--ocean); border-bottom-color:var(--ocean); }
.cat-title { font-size:1.15rem; color:var(--ocean); white-space:nowrap; margin-right:4px; }
.search-wrap { position:relative; flex:1; min-width:180px; max-width:360px; }
.search-wrap svg { position:absolute; left:10px; top:50%; transform:translateY(-50%); color:var(--muted); pointer-events:none; }
.search-wrap input {
width:100%; padding:8px 30px 8px 34px; border:1.5px solid var(--sand-dk); border-radius:8px;
font-family:inherit; font-size:.86rem; background:var(--sand); color:var(--text); outline:none;
transition:border-color .2s,background .2s;
}
.search-wrap input:focus { border-color:var(--ocean-lt); background:#fff; }
.clear-btn { position:absolute; right:8px; top:50%; transform:translateY(-50%); background:none; border:none; cursor:pointer; color:var(--muted); font-size:.85rem; display:none; }
.search-wrap:has(input:not(:placeholder-shown)) .clear-btn { display:block; }
.commune-select {
padding:8px 30px 8px 12px; min-width:190px; border:1.5px solid var(--sand-dk);
border-radius:8px; font-family:inherit; font-size:.86rem; color:var(--text); outline:none; cursor:pointer;
background:var(--sand) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='11' viewBox='0 0 24 24' fill='none' stroke='%238a7b72' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") right 10px center/11px no-repeat;
appearance:none; -webkit-appearance:none; transition:border-color .2s;
}
.commune-select:focus { border-color:var(--ocean-lt); background-color:#fff; }
.reset-btn {
display:flex; align-items:center; gap:6px; padding:8px 14px;
background: #fff3f5; border: 1.5px solid var(--accent); border-radius:8px;
font-family:inherit; font-size:.8rem; font-weight:600; color:var(--accent); cursor:pointer;
transition:all .18s; white-space:nowrap;
}
.reset-btn:hover { background:var(--accent); color:#fff; }
.share-btn {
display:flex; align-items:center; gap:6px; padding:8px 14px; margin-left:auto;
background:transparent; border:1.5px solid var(--sand-dk); border-radius:8px;
font-family:inherit; font-size:.8rem; font-weight:500; color:var(--muted); cursor:pointer;
transition:all .18s; white-space:nowrap;
}
.share-btn:hover { border-color:var(--ocean); color:var(--ocean); }
.share-btn.copied { border-color:#2d8a3e; color:#2d8a3e; }
.stats-bar { padding:8px 24px; display:flex; align-items:center; gap:10px; min-height:38px; }
.count { font-size:.84rem; color:var(--muted); }
.count strong { color:var(--ocean); }
.hint { font-size:.78rem; color:var(--accent,#d4763a); }
.container { max-width:1300px; margin:0 auto; padding:0 20px 60px; }
.grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(300px,1fr)); gap:18px; }
.card {
background: #fff; border-radius: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,.05);
overflow: hidden; display: flex; flex-direction: column;
transition: all .6s var(--ease-out);
position: relative; opacity: 0; transform: translateY(30px);
}
.card.visible { opacity: 1; transform: translateY(0); }
.card:hover { transform: translateY(-10px); box-shadow: 0 20px 40px rgba(0,0,0,.1); }
.card-img { height: 240px; background: #f0f0f0; position: relative; overflow: hidden; }
.card-img img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 1s var(--ease-out); }
.card:hover .card-img img { transform: scale(1.1); }
.card-img .no-img { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; background: linear-gradient(135deg, #f0f4f8, #e8ecf0); }
.card-img .no-img i { font-size: 2.5rem; color: #b0b0b0; }
.card-img .no-img p { font-size: .72rem; color: #b0b0b0; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; }
.card-img-link { display: block; }
.card-body { padding: 20px; flex: 1; display: flex; flex-direction: column; }
.card-city { font-size: 12px; color: var(--accent); font-weight: 700; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 4px; }
.card-title { font-size: 22px; font-weight: 800; line-height: 1.2; color: #222; letter-spacing: -.5px; margin: 4px 0 8px; }
.card-title-link { text-decoration: none; color: inherit; }
.card-title-link:hover .card-title { color: var(--accent); }
.card-desc { font-size: 15px; color: #666; line-height: 1.5; flex: 1; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.hotel-meta { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; margin-bottom: 14px; }
.hotel-meta span { background: #f7f7f7; padding: 5px 12px; border-radius: 50px; font-size: 12px; font-weight: 600; color: #555; }
.book-btn {
display: block; padding: 11px 20px; border-radius: 12px;
background: var(--accent); color: #fff; font-weight: 700;
text-align: center; text-decoration: none; font-size: .85rem;
transition: background .25s; margin-top: auto;
}
.book-btn:hover { background: #e0314f; }
.price-badge {
position: absolute; bottom: 15px; right: 15px;
background: var(--dark); color: #fff;
padding: 8px 15px; border-radius: 12px; font-weight: 900; font-size: 14px;
box-shadow: 0 2px 12px rgba(0,0,0,.2); pointer-events: none;
}
.featured-badge {
position: absolute; top: 15px; right: 15px;
background: #f5a623; color: #fff;
padding: 5px 12px; border-radius: 20px; font-weight: 800; font-size: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,.18); pointer-events: none; letter-spacing: .02em;
}
/* WeeBnB */
.weebnb-bar {
display: flex; align-items: center; gap: 8px;
background: var(--sand,#f7f3ee); border-radius: 8px;
padding: 6px 12px; border: 1px solid var(--sand-dk,#e8e0d4);
}
.weebnb-bar-label { font-size: .78rem; font-weight: 700; color: var(--ocean); white-space: nowrap; }
.weebnb-bar.weebnb-active { background: rgba(26,107,138,.07); border-color: var(--ocean); }
.weebnb-clear-btn {
background: none; border: none; cursor: pointer; font-size: 1.2rem; line-height: 1;
color: #888; padding: 0 4px; transition: color .15s;
}
.weebnb-clear-btn:hover { color: #e53e3e; }
.price-badge.weebnb-price {
background: var(--ocean); display: flex; flex-direction: column; align-items: center; gap: 1px;
}
.price-badge.weebnb-na { background: rgba(0,0,0,.5); font-size: 11px; font-weight: 700; }
.price-badge-sub { font-size: 10px; font-weight: 500; opacity: .85; }
.book-btn.weebnb-book-btn { background: var(--ocean); color: #fff; margin-top: 8px; }
.book-btn.weebnb-book-btn:hover { background: #0e4a63; }
/* WeeBnB loading state */
.weebnb-bar.weebnb-loading { opacity: .65; pointer-events: none; }
.weebnb-bar.weebnb-loading .weebnb-bar-label::after { content: ' …'; animation: blink 1s infinite; }
@keyframes blink { 0%,100%{opacity:1}50%{opacity:.3} }
/* Person picker */
.person-btn {
display: flex; align-items: center; gap: 5px; padding: 6px 10px;
background: var(--w); border: 1px solid var(--g200); border-radius: 8px;
font-size: .8rem; font-weight: 600; color: var(--g600); cursor: pointer;
white-space: nowrap; transition: border-color .15s;
}
.person-btn:hover, .person-btn.active { border-color: var(--ocean); color: var(--ocean); }
.person-overlay {
position: fixed; inset: 0; background: rgba(0,0,0,.4); backdrop-filter: blur(4px);
display: none; justify-content: center; align-items: center; z-index: 9999;
opacity: 0; transition: opacity .2s;
}
.person-overlay.show { display: flex; opacity: 1; }
.person-modal {
background: #fff; padding: 28px; border-radius: 24px; width: 300px;
box-shadow: 0 20px 50px rgba(0,0,0,.2);
transform: translateY(16px); transition: transform .2s;
}
.person-overlay.show .person-modal { transform: translateY(0); }
.person-modal-title { text-align: center; font-size: 1rem; font-weight: 700; margin-bottom: 18px; color: #222; }
.person-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; }
.p-cell { display: flex; justify-content: center; align-items: center; height: 42px; position: relative; cursor: pointer; }
.p-cell::before {
content: ""; position: absolute; left: 0; right: 0; height: 36px;
background: #f0f0f0; z-index: 1; opacity: 0;
}
.p-cell.in-range::before { opacity: 1; }
.p-cell.range-start::before { border-top-left-radius: 18px; border-bottom-left-radius: 18px; }
.p-cell.range-end::before { border-top-right-radius: 18px; border-bottom-right-radius: 18px; }
.p-dot {
width: 38px; height: 38px; display: flex; align-items: center; justify-content: center;
border-radius: 50%; z-index: 2; font-weight: 700; font-size: .9rem;
transition: background .15s, color .15s;
}
.p-cell:hover:not(.is-selected) .p-dot { background: #eee; }
.p-cell.is-selected .p-dot { background: var(--ocean); color: #fff; }
.person-footer { margin-top: 18px; display: flex; justify-content: center; gap: 10px; }
.p-btn-cancel {
background: none; border: none; color: #888; cursor: pointer;
font-size: .85rem; padding: 8px 16px; border-radius: 8px; transition: background .15s;
}
.p-btn-cancel:hover { background: #f5f5f5; color: #333; }
@media(max-width:640px) {
.weebnb-bar { display: none; } /* uniquement dans la popup mobile */
}
.state { grid-column: 1/-1; text-align: center; padding: 60px 20px; }
.state .icon { font-size: 3rem; margin-bottom: 12px; }
.state p { color: #717171; font-size: .95rem; line-height: 1.6; }
.state p strong { color: #222; }
.spinner { width: 42px; height: 42px; border: 3px solid #ebebeb; border-top-color: var(--ocean); border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 14px; }
@keyframes spin { to{transform:rotate(360deg)} }
.progress { font-size: .82rem; color: var(--ocean); margin-top: 6px; }
mark { background: rgba(212,118,58,.28); color: inherit; border-radius: 3px; padding: 0 2px; }
/* Badge date sur les cartes event */
.card-date-badge {
position: absolute; top: 15px; left: 15px;
background: rgba(255,255,255,.95); backdrop-filter: blur(5px);
color: #222; padding: 8px 15px; border-radius: 12px;
font-weight: 800; font-size: 13px;
box-shadow: 0 4px 12px rgba(0,0,0,.1); pointer-events: none;
}
.badge-ongoing { background: #008a05; color: #fff; }
.badge-upcoming { background: rgba(255,255,255,.95); }
/* Étoiles sur les cartes */
.card-stars { color: #f5a623; font-size: .82rem; letter-spacing: .5px; white-space: nowrap; font-weight: 700; }
.card-stars .s-empty { color: #dddddd; }
/* Prix sur les cartes */
.card-price { font-size: .8rem; color: #222; font-weight: 800; white-space: nowrap; }
.card-price-from { font-size: .7rem; color: #717171; font-weight: 500; margin-right: 2px; }
/* Filtre dates événements — boutons rapides */
.date-filter { display: flex; gap: 5px; flex-wrap: wrap; align-items: center; }
.date-filter-label { font-size: .75rem; color: #717171; white-space: nowrap; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; }
.date-btn {
padding: 5px 12px; border-radius: 40px; border: 1.5px solid #dddddd;
background: #fff; font-family: inherit; font-size: .78rem; font-weight: 700;
cursor: pointer; color: #484848; transition: all .15s; white-space: nowrap;
}
.date-btn:hover { border-color: #222; color: #222; }
.date-btn.active { border-color: #222; background: #222; color: #fff; }
/* Date range picker — Flatpickr */
.drp-wrap { position: relative; display: flex; align-items: center; }
.drp-trigger {
display: flex; align-items: center; gap: 8px;
padding: 7px 14px; border: 1.5px solid #dddddd; border-radius: 40px;
background: #fff; font-family: inherit; font-size: .78rem; font-weight: 700;
color: #484848; cursor: pointer; transition: all .15s; white-space: nowrap;
outline: none;
}
.drp-trigger:hover { border-color: #222; }
.drp-trigger.has-range { border-color: #222; background: #f7f7f7; }
/* Flatpickr overrides */
.flatpickr-calendar { font-family: inherit; border-radius: 16px; box-shadow: 0 10px 40px rgba(0,0,0,.18); border: 1px solid #dddddd; z-index: 9999 !important; max-width: 100vw; }
@media(max-width:640px) {
.flatpickr-calendar { border-radius: 12px; left: 50% !important; transform: translateX(-50%) !important; right: auto !important; width: calc(100vw - 24px) !important; max-width: 340px; }
.flatpickr-rContainer, .flatpickr-days, .dayContainer { width: 100% !important; min-width: 0 !important; max-width: 100% !important; }
.flatpickr-day { max-width: none; }
}
.flatpickr-day.selected, .flatpickr-day.startRange, .flatpickr-day.endRange { background: #222; border-color: #222; }
.flatpickr-day.selected:hover, .flatpickr-day.startRange:hover, .flatpickr-day.endRange:hover { background: #444; border-color: #444; }
.flatpickr-day.inRange { background: rgba(26,107,138,.12); border-color: rgba(26,107,138,.12); box-shadow: -5px 0 0 rgba(26,107,138,.12), 5px 0 0 rgba(26,107,138,.12); }
.flatpickr-day.today { border-color: #484848; }
.flatpickr-months .flatpickr-month { color: #222; fill: #222; }
.flatpickr-current-month { font-size: .95rem; font-weight: 800; }
/* ── Responsive ── */
@media(max-width:768px) {
.intro { grid-template-columns:1fr; padding:60px 24px; gap:40px; }
.stat-item { min-width:50%; border-bottom:1px solid rgba(255,255,255,.08); }
.highlights,.cat-section { padding:60px 20px; }
}
@media(max-width:640px) {
.toolbar { padding: 10px 14px; gap: 8px; }
.stats-bar { padding: 10px 14px; }
.container { padding: 0 12px 40px; }
header { padding: 14px 0; }
.header-container { width: 96%; }
.menu-trigger { padding: 7px 12px; font-size: .78rem; gap: 7px; }
.grid { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
/* Hide desktop filters, show mobile button */
.toolbar-filters { display: none !important; }
.mobile-filter-btn { display: flex !important; }
}
@media(max-width:400px) {
.grid { grid-template-columns: 1fr; }
}
/* ── City multi-picker ── */
.city-picker { position: relative; }
.city-picker-btn {
display: flex; align-items: center; gap: 6px;
padding: 8px 12px; border: 1.5px solid var(--sand-dk); border-radius: 8px;
background: var(--sand); font-family: inherit; font-size: .86rem;
color: var(--text); cursor: pointer; transition: border-color .2s, background .2s;
min-width: 175px; max-width: 230px; white-space: nowrap; outline: none;
}
.city-picker-btn:hover { border-color: var(--muted); }
.city-picker-btn.has-sel { border-color: var(--ocean); background: rgba(26,107,138,.06); color: var(--ocean); }
.city-picker-label { overflow: hidden; text-overflow: ellipsis; flex: 1; text-align: left; }
.city-picker-chevron { flex-shrink: 0; color: var(--muted); transition: transform .2s; }
.city-picker-btn[aria-expanded="true"] .city-picker-chevron { transform: rotate(180deg); }
.city-picker-drop {
position: absolute; top: calc(100% + 6px); left: 0; z-index: 600;
background: #fff; border: 1.5px solid var(--sand-dk); border-radius: 14px;
box-shadow: 0 8px 28px rgba(0,0,0,.13); min-width: 250px; max-width: 300px;
display: none; flex-direction: column; overflow: hidden;
}
.city-picker-drop.is-open { display: flex; }
.city-search-wrap { padding: 10px 10px 8px; border-bottom: 1px solid var(--sand-dk); position: relative; }
.city-search-wrap svg { position: absolute; left: 20px; top: 50%; transform: translateY(-50%); color: var(--muted); pointer-events: none; }
.city-search-input {
width: 100%; padding: 7px 10px 7px 32px; border: 1.5px solid var(--sand-dk); border-radius: 8px;
font-family: inherit; font-size: .84rem; outline: none;
background: var(--sand); color: var(--text); transition: border-color .2s;
}
.city-search-input:focus { border-color: var(--ocean-lt); background: #fff; }
.city-list { overflow-y: auto; max-height: 220px; }
.city-option {
display: flex; align-items: center; gap: 9px;
padding: 9px 14px; cursor: pointer; transition: background .1s;
font-size: .84rem; color: var(--text);
}
.city-option:hover { background: var(--sand); }
.city-option.checked { background: rgba(26,107,138,.06); }
.city-checkbox { accent-color: var(--ocean); width: 15px; height: 15px; flex-shrink: 0; cursor: pointer; }
.city-option-count { margin-left: auto; font-size: .74rem; color: var(--muted); font-weight: 600; }
.city-option.zero-count { opacity: .45; }
.city-none { padding: 12px 14px; color: var(--muted); font-size: .82rem; }
.city-picker-footer { padding: 8px 12px; border-top: 1px solid var(--sand-dk); display: flex; justify-content: space-between; align-items: center; }
.city-clear-btn {
font-size: .76rem; color: var(--muted); background: none; border: none;
cursor: pointer; font-family: inherit; padding: 0;
text-decoration: underline; text-underline-offset: 2px; transition: color .15s;
}
.city-clear-btn:hover { color: var(--text); }
.city-count-hint { font-size: .74rem; color: var(--ocean); font-weight: 700; }
/* Mobile city list (inside modal - no dropdown) */
.fm-city-list {
border: 1.5px solid var(--sand-dk); border-radius: 10px;
overflow-y: auto; max-height: 200px; margin-top: 8px;
}
.fm-city-list .city-option { padding: 10px 14px; font-size: .88rem; }
/* ── Mobile filter button ── */
.toolbar-filters { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.mobile-filter-btn {
display: none; flex: 1; align-items: center; justify-content: center; gap: 8px;
padding: 11px 18px; border-radius: 12px; border: 1.5px solid var(--sand-dk);
background: #fff; font-family: inherit; font-size: .92rem; font-weight: 700;
color: var(--text); cursor: pointer; transition: all .18s; min-height: 46px;
}
.mobile-filter-btn.has-filters { background: var(--night); color: #fff; border-color: var(--night); }
.filter-badge {
display: none; align-items: center; justify-content: center;
min-width: 20px; height: 20px; padding: 0 5px;
background: var(--accent); color: #fff; border-radius: 20px;
font-size: .72rem; font-weight: 800; line-height: 1;
}
/* ── Filter modal (plein écran mobile) ── */
.filter-modal {
position: fixed; inset: 0; z-index: 3000;
display: flex; flex-direction: column;
pointer-events: none; opacity: 0;
transition: opacity .25s;
}
.filter-modal.is-open { pointer-events: auto; opacity: 1; }
.filter-modal-backdrop { display: none; }
.filter-modal-sheet {
position: relative; z-index: 1; background: #fff;
/* overflow:hidden + flex column = body scrollable, header+footer fixes */
flex: 1; overflow: hidden; display: flex; flex-direction: column;
transform: translateX(100%); transition: transform .32s cubic-bezier(0.16,1,0.3,1);
}
.filter-modal.is-open .filter-modal-sheet { transform: translateX(0); }
.filter-modal-handle { display: none; }
.filter-modal-header {
display: flex; align-items: center; justify-content: space-between;
padding: 16px 20px; border-bottom: 1px solid var(--sand-dk); flex-shrink: 0;
background: #fff;
}
.filter-modal-header h2 { font-size: 1.05rem; font-weight: 800; color: var(--night); }
.filter-modal-close {
width: 36px; height: 36px; border-radius: 50%; border: none;
background: var(--sand); color: var(--text); font-size: 1.3rem;
cursor: pointer; display: flex; align-items: center; justify-content: center;
font-family: inherit; transition: background .15s; flex-shrink: 0;
}
.filter-modal-close:hover { background: var(--sand-dk); }
.filter-modal-reset {
font-size: .8rem; font-weight: 700; color: var(--muted); background: none;
border: none; cursor: pointer; font-family: inherit; padding: 4px 0;
text-decoration: underline; text-underline-offset: 2px; transition: color .15s;
}
.filter-modal-reset:hover { color: var(--text); }
.filter-modal-body {
flex: 1; min-height: 0; overflow-y: auto; padding: 0 20px 8px;
-webkit-overflow-scrolling: touch;
}
.fm-section { padding: 18px 0; border-bottom: 1px solid var(--sand-dk); }
.fm-section:last-child { border-bottom: none; }
.fm-label {
display: block; font-size: .72rem; font-weight: 800;
text-transform: uppercase; letter-spacing: .08em;
color: var(--muted); margin-bottom: 10px;
}
.fm-search-wrap { position: relative; }
.fm-search-wrap svg { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--muted); pointer-events: none; }
.fm-search-input {
width: 100%; padding: 12px 14px 12px 38px; border: 1.5px solid var(--sand-dk);
border-radius: 10px; font-family: inherit; font-size: .9rem;
background: var(--sand); color: var(--text); outline: none;
transition: border-color .2s, background .2s;
}
.fm-search-input:focus { border-color: var(--ocean-lt); background: #fff; }
.fm-select {
width: 100%; padding: 12px 34px 12px 14px; border: 1.5px solid var(--sand-dk);
border-radius: 10px; font-family: inherit; font-size: .9rem;
color: var(--text); outline: none; cursor: pointer; appearance: none; -webkit-appearance: none;
background: var(--sand) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='11' viewBox='0 0 24 24' fill='none' stroke='%238a7b72' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") right 12px center/11px no-repeat;
transition: border-color .2s;
}
.fm-select:focus { border-color: var(--ocean-lt); background-color: #fff; }
.fm-date-btns { display: flex; gap: 6px; flex-wrap: wrap; }
.fm-drp-wrap { position: relative; margin-top: 10px; }
.fm-drp-wrap i { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); color: #484848; pointer-events: none; font-size: .85rem; z-index: 1; }
.fm-drp-input {
width: 100%; padding: 12px 14px 12px 40px; border: 1.5px solid var(--sand-dk);
border-radius: 10px; font-family: inherit; font-size: .88rem; font-weight: 600;
color: var(--text); background: #fff; cursor: pointer; outline: none;
transition: border-color .2s;
}
.fm-drp-input.has-range { border-color: #222; background: #f7f7f7; }
/* Photo filter toggle */
.fm-photo-toggle {
display: flex; align-items: center; gap: 12px; padding: 12px 16px;
background: var(--sand); border-radius: 10px; cursor: pointer;
border: 1.5px solid var(--sand-dk); transition: border-color .2s;
font-size: .88rem; font-weight: 600; color: var(--text); user-select: none;
}
.fm-photo-toggle.active { border-color: var(--ocean); background: rgba(26,107,138,.06); color: var(--ocean); }
.fm-photo-toggle svg { flex-shrink: 0; }
/* Toggle switch */
.fm-switch { position: relative; width: 38px; height: 22px; flex-shrink: 0; margin-left: auto; }
.fm-switch input { opacity: 0; width: 0; height: 0; }
.fm-switch-track { position: absolute; inset: 0; background: var(--sand-dk); border-radius: 20px; transition: background .2s; }
.fm-switch input:checked + .fm-switch-track { background: var(--ocean); }
.fm-switch-track::after { content: ''; position: absolute; width: 16px; height: 16px; border-radius: 50%; background: #fff; top: 3px; left: 3px; transition: transform .2s; box-shadow: 0 1px 3px rgba(0,0,0,.2); }
.fm-switch input:checked + .fm-switch-track::after { transform: translateX(16px); }
.filter-modal-footer {
padding: 14px 20px env(safe-area-inset-bottom, 16px); flex-shrink: 0;
border-top: 1px solid var(--sand-dk); background: #fff;
}
.fm-apply-btn {
width: 100%; padding: 16px; border-radius: 12px; border: none;
background: var(--night); color: #fff; font-family: inherit;
font-size: .95rem; font-weight: 800; cursor: pointer;
display: flex; align-items: center; justify-content: center; gap: 10px;
transition: background .18s; letter-spacing: -.2px;
}
.fm-apply-btn:active { background: #111; }
.fm-apply-count {
background: rgba(255,255,255,.15); padding: 2px 8px;
border-radius: 20px; font-size: .78rem; font-weight: 700;
}
/* ── Header catégorie ── */
.cat-header {
position: relative; overflow: hidden;
height: 220px; background: var(--night);
display: flex; align-items: flex-end;
}
.cat-header-img {
position: absolute; inset: 0;
width: 100%; height: 100%; object-fit: cover; object-position: center;
display: block;
}
.cat-header-overlay {
position: absolute; inset: 0;
background: linear-gradient(to top, rgba(8,17,31,.75) 0%, rgba(8,17,31,.25) 60%, transparent 100%);
}
.cat-header-content {
position: relative; z-index: 2;
padding: 0 28px 22px; width: 100%;
display: flex; align-items: flex-end; justify-content: space-between;
}
.cat-header-icon { font-size: 2.4rem; margin-right: 14px; line-height: 1; }
.cat-header-title {
font-size: clamp(1.6rem, 4vw, 2.4rem); font-weight: 900;
color: #fff; line-height: 1.1; letter-spacing: -1.5px;
}
.cat-header-count { font-size: .8rem; color: rgba(255,255,255,.6); margin-top: 4px; font-weight: 500; }
@media(max-width:640px) { .cat-header { height: 160px; } .cat-header-title { font-size: 1.4rem; } }
/* ── Toolbar sticky ── */
.toolbar {
position: sticky; top: var(--header-h); z-index: 400;
scroll-margin-top: 0;
background: var(--foam); border-bottom: 1px solid var(--sand-dk);
padding: 12px 24px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
}
/* ── Split-view catalogue + carte ── */
:root { --header-h: 72px; --toolbar-h: 56px; }
.catalogue-layout {
display: flex;
height: calc(100dvh - var(--header-h) - var(--toolbar-h));
overflow: hidden;
}
.catalogue-layout.map-hidden .map-panel { display: none; }
.catalogue-layout.map-hidden .cards-panel { width: 100%; }
.cards-panel {
width: 52%;
min-width: 320px;
overflow-y: auto;
flex-shrink: 0;
padding: 0 0 40px;
scrollbar-width: thin;
}
.cards-panel .stats-bar { padding: 8px 20px; }
.cards-panel .grid { padding: 0 16px 20px; }
.map-panel {
flex: 1;
position: relative;
background: #e8e0d5;
border-left: 1px solid var(--sand-dk);
isolation: isolate;
}
#catalogue-map {
width: 100%; height: 100%;
position: absolute; inset: 0;
}
/* Toggle carte */
.map-toggle-btn {
display: flex; align-items: center; gap: 6px;
padding: 8px 14px; border: 1.5px solid var(--sand-dk); border-radius: 8px;
background: #fff; font-family: inherit; font-size: .8rem; font-weight: 700;
color: var(--muted); cursor: pointer; transition: all .18s; white-space: nowrap;
}
.map-toggle-btn:hover { border-color: var(--ocean); color: var(--ocean); }
.map-toggle-btn.active { background: var(--ocean); color: #fff; border-color: var(--ocean); }
/* Popup Leaflet custom */
.map-popup { font-family: inherit; min-width: 140px; }
.map-popup strong { font-size: .9rem; color: #222; display: block; margin-bottom: 4px; }
.map-popup small { font-size: .78rem; color: #717171; }
.map-popup a { display: inline-block; margin-top: 8px; font-size: .78rem; font-weight: 700; color: var(--ocean, #1a6b8a); text-decoration: none; }
.map-popup a:hover { text-decoration: underline; }
/* Marker custom */
.cmap-marker {
width: 34px; height: 34px; border-radius: 50% 50% 50% 0;
transform: rotate(-45deg); display: flex; align-items: center; justify-content: center;
background: var(--ocean, #1a6b8a); border: 2.5px solid #fff;
box-shadow: 0 2px 8px rgba(0,0,0,.25); cursor: pointer; transition: transform .15s;
}
.cmap-marker i {color: white;transform: rotate(45deg);}
.cmap-marker:hover { transform: rotate(-45deg) scale(1.15); }
.cmap-marker:hover i { color: black;}
.cmap-marker span { transform: rotate(45deg); font-size: .9rem; line-height: 1; }
.cmap-marker.highlighted { background: var(--gold, #c8a96e); transform: rotate(-45deg) scale(1.2); z-index: 9999 !important; }
/* Highlight card depuis marker */
.card-flash { outline: 2.5px solid var(--ocean) !important; box-shadow: 0 0 0 4px rgba(26,107,138,.15) !important; transition: box-shadow .2s; }
/* Responsive : carte cachée sur mobile */
@media(max-width:900px) {
.map-toggle-btn { display: none; }
.catalogue-layout { height: auto; flex-direction: column; overflow: visible; }
.cards-panel { width: 100%; min-width: 0; overflow-y: visible; }
.map-panel {
flex: none;
height: 360px; border-left: none; border-top: 1px solid var(--sand-dk);
position: relative; display: block;
}
#catalogue-map { position: absolute; inset: 0; width: 100%; height: 100%; }
.catalogue-layout.map-hidden .map-panel { display: none; }
}
@media(max-width:640px) {
.map-panel { height: 300px; }
}
@media(max-width:640px) {
.cards-panel .grid { padding: 0 10px 20px; }
}
/* Footer */
footer { background:var(--night); padding:48px 32px; text-align:center; }
.footer-logo { font-size:1.2rem; font-weight:900; letter-spacing:-0.5px; color:var(--gold); margin-bottom:12px; }
footer p { font-size:.78rem; color:rgba(255,255,255,.3); line-height:1.8; }
footer a { color:rgba(255,255,255,.45); text-decoration:none; }
footer a:hover { color:var(--gold); }
</style>
<style>
/* ── Header flottant (catalogue) ── */
header{position:fixed;top:0;left:0;width:100%;z-index:1000;padding:25px 0;background:transparent;transition:all .6s var(--ease-out);}
header.scrolled{background:rgba(255,255,255,.85);backdrop-filter:blur(20px);padding:15px 0;border-bottom:1px solid rgba(0,0,0,.05);}
.header-container{width:90%;max-width:1400px;margin:0 auto;display:flex;justify-content:space-between;align-items:center;}
.logo{font-weight:900;font-size:22px;display:flex;align-items:center;gap:10px;color:#fff;letter-spacing:-1px;text-decoration:none;}
header.scrolled .logo{color:var(--dark);}
.logo-dot{width:11px;height:11px;border-radius:50%;background:var(--accent);box-shadow:0 0 14px var(--accent);flex-shrink:0;}
.menu-trigger{display:flex;align-items:center;gap:10px;cursor:pointer;border:none;background:rgba(255,255,255,.2);backdrop-filter:blur(10px);padding:8px 16px;border-radius:40px;font-weight:700;color:#fff;font-family:inherit;font-size:.85rem;transition:all .6s var(--ease-out);}
header.scrolled .menu-trigger{background:var(--dark);color:#fff;}
.burger{width:18px;height:12px;position:relative;}
.burger span{position:absolute;width:100%;height:2px;background:currentColor;left:0;border-radius:2px;}
.burger span:nth-child(1){top:0;}.burger span:nth-child(2){top:5px;width:70%;}.burger span:nth-child(3){bottom:0;}
/* ── Hero catégorie ── */
.hero_cat{position:relative;height:50vh;display:flex;align-items:center;justify-content:center;text-align:center;background:#000;color:#fff;overflow:hidden;}
.hero_cat--no-img{background:linear-gradient(135deg,var(--primary,#1a6b8a) 0%,var(--secondary,#0e4a63) 100%)}
.hero_cat img{position:absolute;width:100%;height:100%;object-fit:cover;opacity:.65;}
.hero-content{position:relative;z-index:2;max-width:1000px;padding:0 20px;}
.hero-badge{background:var(--accent);color:#fff;padding:5px 14px;border-radius:4px;font-weight:700;text-transform:uppercase;margin-bottom:18px;display:inline-block;font-size:11px;letter-spacing:2px;}
.hero-title-cat{font-size:clamp(36px,8vw,90px);font-weight:900;line-height:.9;letter-spacing:-3px;margin:0;}
@media(max-width:640px){.hero_cat{height:40vh;}.hero-title-cat{letter-spacing:-1.5px;}}
/* ── Bloc intro SEO ── */
.seo-intro-block{background:var(--bg,#f8f8f8);border-bottom:1px solid rgba(0,0,0,.07);}
.seo-intro-inner{max-width:1240px;margin:0 auto;padding:32px 24px;font-size:15px;line-height:1.8;color:#444;}
.seo-intro-inner h2,.seo-intro-inner h3{font-size:1.05rem;font-weight:700;color:#222;margin:16px 0 6px;}
.seo-intro-inner p{margin:0 0 12px;}
.seo-intro-inner a{color:var(--primary,#1a6b8a);text-decoration:underline;}
.seo-intro-inner strong{color:#222;}
@media(max-width:640px){.seo-intro-inner{padding:20px 16px;font-size:14px;}}
</style>
</head>
<body>
<header id="catalogueHeader">
<div class="header-container">
<a href="/" class="logo" title="Bassin d'Arcachon - Accueil">
<span class="logo-dot"></span>
Bassin d'Arcachon </a>
<button class="menu-trigger" id="openMenu">
<span class="menu-label">Explorer</span>
<div class="burger"><span></span><span></span><span></span></div>
</button>
</div>
</header>
<style>
/* ═══════════════ BASE ═══════════════ */
:root { --menu-accent: var(--accent, #FF385C); }
.full-menu {
position: fixed; inset: 0;
background: #fff;
z-index: 2000;
display: flex; flex-direction: column;
transform: translateY(-100%);
transition: transform .5s cubic-bezier(0.16,1,0.3,1);
visibility: hidden;
}
.full-menu.is-open { transform: translateY(0); visibility: visible; }
/* ═══════════════ HEADER ═══════════════ */
.full-menu-header {
flex-shrink: 0;
display: flex; align-items: center; gap: 8px;
padding: 0 14px;
height: 52px;
background: #fff;
border-bottom: 1px solid #ebebeb;
z-index: 10;
}
.menu-logo {
display: flex; align-items: center; gap: 8px;
font-weight: 900; font-size: 15px; color: #111;
text-decoration: none; flex: 1; min-width: 0;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.logo-dot {
width: 9px; height: 9px; border-radius: 50%;
background: var(--menu-accent); flex-shrink: 0;
}
.menu-langs {
display: flex; align-items: center; gap: 2px;
overflow-x: auto; scrollbar-width: none; flex-shrink: 0;
}
.menu-langs::-webkit-scrollbar { display: none; }
.menu-lang {
display:flex; align-items:center; justify-content:center;
padding: 4px; border-radius: 4px; line-height: 0; flex-shrink: 0;
border: 2px solid transparent; transition: border-color .15s;
}
.menu-lang.active { border-color: var(--menu-accent); }
.menu-langs a { border-bottom: none; }
.flag { width: 20px; height: 13px; display: block; object-fit: cover; }
.close-menu {
width: 30px; height: 30px; flex-shrink: 0; margin-left: 6px;
display: flex; align-items: center; justify-content: center;
font-size: 18px; background: #f2f2f2; border: none;
border-radius: 50%; cursor: pointer; color: #555; transition: background .15s;
}
.close-menu:hover { background: #e0e0e0; }
/* ═══════════════ CORPS = sidebar + panneau ═══════════════ */
.full-menu-body {
flex: 1; display: flex; overflow: hidden;
}
/* ── SIDEBAR GAUCHE ── */
.menu-sidebar {
width: 220px; flex-shrink: 0;
overflow-y: auto; -webkit-overflow-scrolling: touch;
border-right: 1px solid #ebebeb;
background: #fafafa;
display: block !important;
flex-direction: unset !important;
flex-wrap: unset !important;
align-items: unset !important;
justify-content: unset !important;
gap: unset !important;
padding: 0 !important;
margin: 0 !important;
}
.menu-sidebar-item {
display: flex !important; align-items: center !important; gap: 12px !important;
padding: 0 14px !important;
height: 64px !important;
min-height: unset !important;
max-height: 64px !important;
cursor: pointer;
border-bottom: 1px solid #f0f0f0;
transition: background .15s;
position: relative;
border-left: 3px solid transparent;
box-sizing: border-box;
margin: 0 !important;
flex-direction: row !important;
flex-wrap: nowrap !important;
}
.menu-sidebar-item:hover { background: #f3f3f3; }
.menu-sidebar-item.active {
background: #fff;
border-left-color: var(--menu-accent);
}
.menu-sidebar-thumb {
width: 44px; height: 44px; flex-shrink: 0;
border-radius: 8px; overflow: hidden;
background: var(--grp-color, #1a6b8a);
display: flex; align-items: center; justify-content: center;
}
.menu-sidebar-thumb img {
width: 100%; height: 100%; object-fit: cover; display: block;
}
.menu-sidebar-thumb-icon {
font-size: 20px; color: rgba(255,255,255,.9);
display: flex; align-items: center; justify-content: center;
}
.menu-sidebar-info { flex: 1; min-width: 0; }
.menu-sidebar-name {
font-size: 13px; font-weight: 700; color: #111;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.menu-sidebar-item.active .menu-sidebar-name { color: var(--menu-accent); }
.menu-sidebar-count {
font-size: 10px; color: #aaa; margin-top: 2px;
}
.menu-sidebar-arrow {
font-size: 11px; color: #ccc; flex-shrink: 0;
transition: color .15s;
}
.menu-sidebar-item.active .menu-sidebar-arrow,
.menu-sidebar-item:hover .menu-sidebar-arrow { color: var(--menu-accent); }
/* ── PANNEAU DROIT ── */
.menu-panel {
flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch;
}
.menu-panel-section {
display: none;
padding: 20px 20px 28px;
}
.menu-panel-section.active { display: block; }
/* Titre du panneau */
.menu-panel-title {
display: flex; align-items: center; gap: 10px;
margin-bottom: 16px; padding-bottom: 12px;
border-bottom: 1px solid #f0f0f0;
}
.menu-panel-title-img {
width: 48px; height: 48px; border-radius: 10px; overflow: hidden; flex-shrink: 0;
background: var(--grp-color, #1a6b8a);
display: flex; align-items: center; justify-content: center;
}
.menu-panel-title-img img { width:100%;height:100%;object-fit:cover;display:block; }
.menu-panel-title-icon { font-size: 22px; color: rgba(255,255,255,.9); }
.menu-panel-title-text {}
.menu-panel-title-name {
font-size: 16px; font-weight: 900; color: #111; text-transform: uppercase; letter-spacing: .05em;
}
.menu-panel-title-desc {
font-size: 12px; color: #888; margin-top: 3px; line-height: 1.4;
}
/* Grille de cards */
.menu-cat-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
gap: 12px;
}
.menu-cat-card {
display: flex; flex-direction: column;
text-decoration: none; color: #222;
border-radius: 10px;
overflow: hidden;
border: 1.5px solid #ebebeb;
background: #fff;
transition: border-color .2s, box-shadow .2s, transform .2s;
}
.menu-cat-card:hover {
border-color: var(--menu-accent);
box-shadow: 0 4px 16px rgba(0,0,0,.08);
transform: translateY(-3px);
}
.menu-cat-card.active {
border-color: var(--menu-accent);
box-shadow: 0 2px 10px rgba(0,0,0,.07);
}
/* Image */
.menu-cat-card-img-wrap {
width: 100%; aspect-ratio: 4/3;
overflow: hidden; background: #f0f0f0;
position: relative; flex-shrink: 0;
}
.menu-cat-card-img {
width: 100%; height: 100%;
background-size: cover; background-position: center;
transition: transform .35s ease;
}
.menu-cat-card:hover .menu-cat-card-img { transform: scale(1.06); }
.menu-cat-card-icon {
position: absolute; inset: 0;
display: flex; align-items: center; justify-content: center;
font-size: 32px; color: #ccc;
transition: transform .2s;
}
.menu-cat-card:hover .menu-cat-card-icon { transform: scale(1.1); }
/* Overlay active */
.menu-cat-card.active .menu-cat-card-img-wrap::after {
content: ''; position: absolute; inset: 0;
background: rgba(255,56,92,.15);
}
/* Texte */
.menu-cat-card-name {
padding: 9px 10px 11px;
font-size: 11px; font-weight: 800;
text-align: center; line-height: 1.3;
text-transform: uppercase; letter-spacing: .04em;
color: #222;
}
.menu-cat-card.active .menu-cat-card-name { color: var(--menu-accent); }
/* ═══════════════ FOOTER ═══════════════ */
.full-menu-footer {
flex-shrink: 0; padding: 10px 20px;
background: #fff; border-top: 1px solid #ebebeb; text-align: center;
}
.full-menu-footer a {
font-size: 12px; font-weight: 600; color: #aaa; text-decoration: none;
}
.full-menu-footer a:hover { color: var(--menu-accent); }
/* ═══════════════ MOBILE ═══════════════ */
@media (max-width: 640px) {
/* Corps vertical : sidebar en haut (tabs), panneau en dessous */
.full-menu-body { flex-direction: column !important; }
/* Sidebar = barre de tabs horizontale */
.menu-sidebar {
width: 100% !important; flex-shrink: 0 !important;
display: flex !important; flex-direction: row !important;
align-items: stretch !important;
overflow-x: auto !important; overflow-y: hidden !important;
border-right: none !important; border-bottom: 1px solid #ebebeb !important;
padding: 0 !important; margin: 0 !important;
background: #fafafa !important;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
}
.menu-sidebar::-webkit-scrollbar { display: none; }
/* Chaque tab = vignette + nom empilés */
.menu-sidebar-item {
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
height: auto !important; min-height: 72px !important; max-height: none !important;
padding: 8px 10px !important;
min-width: 68px !important;
border-left: none !important;
border-bottom: 3px solid transparent !important;
gap: 5px !important;
flex-shrink: 0;
}
.menu-sidebar-item.active {
border-left-color: transparent !important;
border-bottom-color: var(--menu-accent) !important;
background: #fff !important;
}
.menu-sidebar-thumb {
width: 38px !important; height: 38px !important;
border-radius: 10px !important;
}
.menu-sidebar-thumb-icon { font-size: 16px !important; }
.menu-sidebar-info { text-align: center; }
.menu-sidebar-name {
font-size: 10px !important;
white-space: normal !important;
text-align: center;
max-width: 64px;
line-height: 1.2;
}
.menu-sidebar-count { display: none !important; }
.menu-sidebar-arrow { display: none !important; }
/* Panneau = zone scrollable en dessous */
.menu-panel { flex: 1; overflow-y: auto; }
.menu-panel-section { padding: 12px 10px 20px; }
.menu-panel-title {
margin-bottom: 10px; padding-bottom: 10px;
gap: 8px;
}
.menu-panel-title-img { width: 36px; height: 36px; border-radius: 8px; }
.menu-panel-title-name { font-size: 14px; }
.menu-panel-title-desc { display: none; }
/* Grille 3 colonnes, cards compactes */
.menu-cat-grid {
grid-template-columns: repeat(3, 1fr) !important;
gap: 8px !important;
}
.menu-cat-card { border-radius: 8px; }
.menu-cat-card-name {
font-size: 9px !important;
padding: 5px 4px 7px !important;
letter-spacing: .02em;
}
}
</style>
<div class="full-menu" id="fullMenu">
<!-- ══ HEADER ══ -->
<div class="full-menu-header">
<div class="menu-logo">
<span class="logo-dot"></span>
Bassin d'Arcachon </div>
<div class="menu-langs">
<a href="/locations-gites"
class="menu-lang active">
<svg viewbox="0 0 3 2" class="flag"><rect width="1" height="2" x="0" fill="#002395"/><rect width="1" height="2" x="1" fill="#ffffff"/><rect width="1" height="2" x="2" fill="#ed2939"/></svg> </a>
<a href="/en/locations-gites"
class="menu-lang">
<svg viewbox="0 0 60 30" class="flag"><clippath id="t"><path d="M30,15h30v15zv15h-30zh-30v-15zv-15h30z"/></clippath><path d="M0,0v30h60v-30z" fill="#012169"/><path d="M0,0L60,30M60,0L0,30" stroke="#fff" stroke-width="6"/><path d="M0,0L60,30M60,0L0,30" stroke="#C8102E" stroke-width="4"/><path d="M30,0v30M0,15h60" stroke="#fff" stroke-width="10"/><path d="M30,0v30M0,15h60" stroke="#C8102E" stroke-width="6"/></svg> </a>
<a href="/de/locations-gites"
class="menu-lang">
<svg viewbox="0 0 3 2" class="flag"><rect width="3" height="0.67" fill="#000"/><rect width="3" height="0.67" y="0.67" fill="#DD0000"/><rect width="3" height="0.66" y="1.34" fill="#FFCE00"/></svg> </a>
<a href="/it/locations-gites"
class="menu-lang">
<svg viewbox="0 0 3 2" class="flag"><rect width="1" height="2" fill="#009246"/><rect width="1" height="2" x="1" fill="#fff"/><rect width="1" height="2" x="2" fill="#ce2b37"/></svg> </a>
<a href="/nl/locations-gites"
class="menu-lang">
<svg viewbox="0 0 3 2" class="flag"><rect width="3" height="0.67" fill="#ae1c28"/><rect width="3" height="0.67" y="0.67" fill="#fff"/><rect width="3" height="0.66" y="1.34" fill="#21468b"/></svg> </a>
<a href="/es/locations-gites"
class="menu-lang">
<svg viewbox="0 0 3 2" class="flag"><rect width="3" height="2" fill="#aa151b"/><rect width="3" height="1" y="0.5" fill="#f1bf00"/></svg> </a>
</div>
<button class="close-menu" id="closeMenu" aria-label="Fermer">×</button>
</div>
<!-- ══ CORPS : sidebar + panneau ══ -->
<div class="full-menu-body">
<!-- SIDEBAR -->
<div class="menu-sidebar" id="menuSidebar">
<div class="menu-sidebar-item active"
style="--grp-color:#2c3e50"
data-panel="panel-1"
onclick="showMenuPanel('panel-1', this)">
<div class="menu-sidebar-thumb">
<div class="menu-sidebar-thumb-icon">
<i class="fa-solid fa-bed" aria-hidden="true"></i> </div>
</div>
<div class="menu-sidebar-info">
<div class="menu-sidebar-name">Séjours & Hébergements</div>
<div class="menu-sidebar-count">6 catégories</div>
</div>
<span class="menu-sidebar-arrow">›</span>
</div>
<div class="menu-sidebar-item"
style="--grp-color:#e67e22"
data-panel="panel-2"
onclick="showMenuPanel('panel-2', this)">
<div class="menu-sidebar-thumb">
<div class="menu-sidebar-thumb-icon">
<i class="fa-solid fa-utensils" aria-hidden="true"></i> </div>
</div>
<div class="menu-sidebar-info">
<div class="menu-sidebar-name">Gastronomie & Terroir</div>
<div class="menu-sidebar-count">4 catégories</div>
</div>
<span class="menu-sidebar-arrow">›</span>
</div>
<div class="menu-sidebar-item"
style="--grp-color:#8e44ad"
data-panel="panel-3"
onclick="showMenuPanel('panel-3', this)">
<div class="menu-sidebar-thumb">
<div class="menu-sidebar-thumb-icon">
<i class="fa-solid fa-landmark" aria-hidden="true"></i> </div>
</div>
<div class="menu-sidebar-info">
<div class="menu-sidebar-name">Culture & Patrimoine</div>
<div class="menu-sidebar-count">5 catégories</div>
</div>
<span class="menu-sidebar-arrow">›</span>
</div>
<div class="menu-sidebar-item"
style="--grp-color:#27ae60"
data-panel="panel-4"
onclick="showMenuPanel('panel-4', this)">
<div class="menu-sidebar-thumb">
<div class="menu-sidebar-thumb-icon">
<i class="fa-solid fa-tree" aria-hidden="true"></i> </div>
</div>
<div class="menu-sidebar-info">
<div class="menu-sidebar-name">Nature & Activités</div>
<div class="menu-sidebar-count">7 catégories</div>
</div>
<span class="menu-sidebar-arrow">›</span>
</div>
<div class="menu-sidebar-item"
style="--grp-color:#f1c40f"
data-panel="panel-5"
onclick="showMenuPanel('panel-5', this)">
<div class="menu-sidebar-thumb">
<div class="menu-sidebar-thumb-icon">
<i class="fa-solid fa-calendar-star" aria-hidden="true"></i> </div>
</div>
<div class="menu-sidebar-info">
<div class="menu-sidebar-name">Sorties & Agenda</div>
<div class="menu-sidebar-count">5 catégories</div>
</div>
<span class="menu-sidebar-arrow">›</span>
</div>
<div class="menu-sidebar-item"
style="--grp-color:#1abc9c"
data-panel="panel-6"
onclick="showMenuPanel('panel-6', this)">
<div class="menu-sidebar-thumb">
<div class="menu-sidebar-thumb-icon">
<i class="fa-solid fa-spa" aria-hidden="true"></i> </div>
</div>
<div class="menu-sidebar-info">
<div class="menu-sidebar-name">Bien-être & Thermalisme</div>
<div class="menu-sidebar-count">3 catégories</div>
</div>
<span class="menu-sidebar-arrow">›</span>
</div>
<div class="menu-sidebar-item"
style="--grp-color:#3498db"
data-panel="panel-7"
onclick="showMenuPanel('panel-7', this)">
<div class="menu-sidebar-thumb">
<div class="menu-sidebar-thumb-icon">
<i class="fa-solid fa-umbrella-beach" aria-hidden="true"></i> </div>
</div>
<div class="menu-sidebar-info">
<div class="menu-sidebar-name">Mer & Littoral</div>
<div class="menu-sidebar-count">4 catégories</div>
</div>
<span class="menu-sidebar-arrow">›</span>
</div>
<div class="menu-sidebar-item"
style="--grp-color:#95a5a6"
data-panel="panel-8"
onclick="showMenuPanel('panel-8', this)">
<div class="menu-sidebar-thumb">
<div class="menu-sidebar-thumb-icon">
<i class="fa-solid fa-mountain-sun" aria-hidden="true"></i> </div>
</div>
<div class="menu-sidebar-info">
<div class="menu-sidebar-name">Montagne & Sommets</div>
<div class="menu-sidebar-count">4 catégories</div>
</div>
<span class="menu-sidebar-arrow">›</span>
</div>
<div class="menu-sidebar-item"
style="--grp-color:#e74c3c"
data-panel="panel-9"
onclick="showMenuPanel('panel-9', this)">
<div class="menu-sidebar-thumb">
<div class="menu-sidebar-thumb-icon">
<i class="fa-solid fa-star" aria-hidden="true"></i> </div>
</div>
<div class="menu-sidebar-info">
<div class="menu-sidebar-name">Sélections Spéciales</div>
<div class="menu-sidebar-count">5 catégories</div>
</div>
<span class="menu-sidebar-arrow">›</span>
</div>
<div class="menu-sidebar-item"
style="--grp-color:#7f8c8d"
data-panel="panel-10"
onclick="showMenuPanel('panel-10', this)">
<div class="menu-sidebar-thumb">
<div class="menu-sidebar-thumb-icon">
<i class="fa-solid fa-circle-info" aria-hidden="true"></i> </div>
</div>
<div class="menu-sidebar-info">
<div class="menu-sidebar-name">Infos Pratiques</div>
<div class="menu-sidebar-count">3 catégories</div>
</div>
<span class="menu-sidebar-arrow">›</span>
</div>
</div>
<!-- PANNEAU DROIT -->
<div class="menu-panel" id="menuPanel">
<div class="menu-panel-section active" id="panel-1">
<!-- Titre -->
<div class="menu-panel-title" style="--grp-color:#2c3e50">
<div class="menu-panel-title-img">
<div class="menu-panel-title-icon">
<i class="fa-solid fa-bed" aria-hidden="true"></i> </div>
</div>
<div class="menu-panel-title-text">
<div class="menu-panel-title-name">Séjours & Hébergements</div>
<div class="menu-panel-title-desc">Trouver l’endroit idéal pour poser ses valises est le premier pas vers un voyage réussi. Que vous recherchiez le luxe feutré d’un établissement de prestige, le charme authentique d’une demeure historique ou la liberté d’un séjour en plein air, l’offre d’accueil se plie à toutes vos envies. Chaque type de logement propose une expérience singulière : l’intimité d’un appartement privé, la convivialité d’une chambre d’hôtes ou l’évasion totale d’un hébergement insolite niché en pleine nature. Dormir ici, c’est s’offrir une parenthèse de repos après une journée d’exploration, tout en profitant de services adaptés à votre rythme. Des équipements modernes des résidences de tourisme aux ambiances rustiques des chalets de montagne, chaque nuit devient une partie intégrante de votre souvenir de vacances. Que vous voyagiez en solo, en couple pour une escapade romantique, ou en tribu pour des moments de partage inoubliables, vous trouverez toujours un refuge hospitalier prêt à vous accueillir. Profitez du confort, de la tranquillité et de l’hospitalité locale pour recharger vos batteries et vivre une immersion totale dans votre destination.</div>
</div>
</div>
<!-- Cards -->
<div class="menu-cat-grid">
<a href="/hotels-prestige"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-hotel" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Hôtels & Prestige</span>
</a>
<a href="/locations-gites"
class="menu-cat-card active">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-house" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Locations & Gîtes</span>
</a>
<a href="/chambres-hotes"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-bed" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Chambres d’Hôtes</span>
</a>
<a href="/campings-insolite"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-tent" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Campings & Insolite</span>
</a>
<a href="/camping-car-van"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-caravan" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Aires Camping-Car</span>
</a>
<a href="/groupe-jeunesse"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-users-rectangle" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Groupes & Jeunesse</span>
</a>
</div>
</div>
<div class="menu-panel-section" id="panel-2">
<!-- Titre -->
<div class="menu-panel-title" style="--grp-color:#e67e22">
<div class="menu-panel-title-img">
<div class="menu-panel-title-icon">
<i class="fa-solid fa-utensils" aria-hidden="true"></i> </div>
</div>
<div class="menu-panel-title-text">
<div class="menu-panel-title-name">Gastronomie & Terroir</div>
<div class="menu-panel-title-desc">La table est le reflet d’une culture, un voyage sensoriel qui raconte l’histoire d’un territoire à travers ses saveurs. Explorer la gastronomie locale, c’est partir à la rencontre de producteurs passionnés, de vignerons au savoir-faire ancestral et de chefs qui subliment les produits de saison. Des brasseries animées aux tables étoilées, chaque repas est une célébration du goût et du partage. Laissez-vous tenter par la découverte des marchés colorés où les parfums des produits frais éveillent les sens, ou poussez la porte d’une cave pour une dégustation commentée. Ici, le terroir s’exprime avec générosité : fromages de caractère, vins d’exception, spécialités artisanales et douceurs sucrées composent une mosaïque culinaire unique. La gastronomie ne se limite pas au contenu de l’assiette, c’est aussi l’atmosphère d’un bistrot de quartier, le sourire d’un artisan fier de son travail et le plaisir de découvrir des recettes transmises de génération en génération. Que vous soyez un fin gourmet en quête de raffinement ou un amateur de simplicité authentique, chaque escale gourmande promet une rencontre inoubliable avec l’âme du pays et ses traditions les plus vivantes.</div>
</div>
</div>
<!-- Cards -->
<div class="menu-cat-grid">
<a href="/restaurants-tables"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-utensils" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Restaurants</span>
</a>
<a href="/brasseries-cafes"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-mug-hot" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Brasseries & Cafés</span>
</a>
<a href="/vins-distilleries"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-wine-glass" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Vins & Caves</span>
</a>
<a href="/producteurs-marches"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-basket-shopping" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Marchés & Producteurs</span>
</a>
</div>
</div>
<div class="menu-panel-section" id="panel-3">
<!-- Titre -->
<div class="menu-panel-title" style="--grp-color:#8e44ad">
<div class="menu-panel-title-img">
<div class="menu-panel-title-icon">
<i class="fa-solid fa-landmark" aria-hidden="true"></i> </div>
</div>
<div class="menu-panel-title-text">
<div class="menu-panel-title-name">Culture & Patrimoine</div>
<div class="menu-panel-title-desc">Plongez au cœur de l’histoire en explorant les trésors architecturaux et artistiques qui façonnent l’identité de nos paysages. Des châteaux majestueux aux églises séculaires, chaque pierre raconte une épopée, chaque monument est le témoin d’un passé riche et complexe. Le patrimoine se décline sous toutes ses formes : édifices militaires imposants, abbayes silencieuses, musées foisonnants d’art ou sites archéologiques révélant des secrets enfouis depuis des millénaires. Mais la culture ne s’arrête pas aux monuments historiques ; elle vit également à travers l’art contemporain, les galeries indépendantes et les centres d’interprétation modernes qui nous aident à comprendre le monde d’aujourd’hui. Déambuler dans une cité ancienne, admirer la finesse d’une sculpture ou comprendre le fonctionnement d’un ancien moulin industriel, c’est se connecter à l’ingéniosité humaine à travers les âges. Ce parcours culturel est une invitation à la curiosité et à l’émerveillement, offrant un regard profond sur les racines d’une société tout en célébrant sa créativité actuelle. Laissez-vous guider par les récits des guides passionnés et la beauté des lieux préservés pour une immersion totale dans l’héritage universel qui nous entoure.</div>
</div>
</div>
<!-- Cards -->
<div class="menu-cat-grid">
<a href="/chateaux-forts"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-fort-awesome" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Châteaux & Forts</span>
</a>
<a href="/edifices-religieux"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-church" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Patrimoine religieux</span>
</a>
<a href="/musees-arts"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-building-columns" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Musées & Arts</span>
</a>
<a href="/archeologie-grottes"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-hill-rockslide" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Archéologie & Grottes</span>
</a>
<a href="/patrimoine-industriel"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-gears" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Industrie & Artisanat</span>
</a>
</div>
</div>
<div class="menu-panel-section" id="panel-4">
<!-- Titre -->
<div class="menu-panel-title" style="--grp-color:#27ae60">
<div class="menu-panel-title-img">
<div class="menu-panel-title-icon">
<i class="fa-solid fa-tree" aria-hidden="true"></i> </div>
</div>
<div class="menu-panel-title-text">
<div class="menu-panel-title-name">Nature & Activités</div>
<div class="menu-panel-title-desc">Le grand air vous appelle pour une aventure sans limites au sein d’espaces naturels préservés. Que vous soyez amateur de calme contemplatif ou mordu d’adrénaline, la nature offre un terrain de jeu inépuisable pour tous les âges et toutes les envies. Des forêts denses aux sommets enneigés, des lacs miroirs aux rivières tumultueuses, chaque paysage invite à la déconnexion et au ressourcement. Parcourez des sentiers de randonnée sinueux, relevez des défis sportifs en escalade, ou profitez d’une balade tranquille à vélo au fil de l’eau. Les activités de loisirs se déclinent pour tous : parcs animaliers pour s’émerveiller en famille, parcours d’aventure dans les arbres pour tester son équilibre, ou encore golfs verdoyants pour parfaire son swing. C’est ici que l’on retrouve le plaisir simple d’observer la faune sauvage, de respirer l’air pur des sous-bois et d’admirer des panoramas à couper le souffle. La nature est aussi un lieu d’apprentissage et de respect, où chaque sentier pédagogique permet de mieux comprendre la fragilité de notre environnement. Quelle que soit votre passion, l’évasion est garantie au rythme des saisons, offrant des couleurs et des sensations renouvelées à chaque visite.</div>
</div>
</div>
<!-- Cards -->
<div class="menu-cat-grid">
<a href="/parcs-jardins"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-leaf" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Parcs & Jardins</span>
</a>
<a href="/ski-sports-hiver"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-snowflake" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Ski & Hiver</span>
</a>
<a href="/eau-nature"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-droplet" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Eau & Nature</span>
</a>
<a href="/sommets-panoramas"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-mountain" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Sommets</span>
</a>
<a href="/balades-itineraires"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-person-walking" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Rando & Vélo</span>
</a>
<a href="/aventure-loisirs"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-mountain-climbing" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Aventure & Sport</span>
</a>
<a href="/faune-animaliers"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-hippo" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Zoos & Animaux</span>
</a>
</div>
</div>
<div class="menu-panel-section" id="panel-5">
<!-- Titre -->
<div class="menu-panel-title" style="--grp-color:#f1c40f">
<div class="menu-panel-title-img">
<div class="menu-panel-title-icon">
<i class="fa-solid fa-calendar-star" aria-hidden="true"></i> </div>
</div>
<div class="menu-panel-title-text">
<div class="menu-panel-title-name">Sorties & Agenda</div>
<div class="menu-panel-title-desc">Vivez au rythme des célébrations et profitez d’une vie locale vibrante d’énergie. Tout au long de l’année, une programmation riche et variée anime les lieux de rencontre, transformant chaque séjour en une expérience festive unique. Des festivals de musique aux représentations théâtrales, des concerts intimistes aux grandes expositions artistiques, l’offre culturelle et événementielle est une porte ouverte sur le divertissement et la découverte. Ne manquez pas les moments forts de la vie traditionnelle, comme les brocantes où l’on déniche des trésors oubliés, les foires artisanales ou les fêtes populaires qui rassemblent toutes les générations. Pour ceux qui aiment prolonger la soirée, les lieux de vie nocturne, bars à thèmes et casinos offrent une ambiance chaleureuse et décontractée. Les sorties sont l’occasion parfaite de rencontrer les habitants, de partager leur joie de vivre et de découvrir des talents locaux ou internationaux. Que vous cherchiez un spectacle familial, une conférence passionnante ou une soirée dansante, l’agenda s’adapte à tous les goûts et toutes les curiosités. Laissez-vous porter par l’effervescence des événements locaux pour créer des souvenirs mémorables et vivre des instants de pur plaisir.</div>
</div>
</div>
<!-- Cards -->
<div class="menu-cat-grid">
<a href="/evenements-festivals"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-masks-theater" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Spectacles</span>
</a>
<a href="/spectacles-cinema"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-film" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Foires & Shopping</span>
</a>
<a href="/foires-shopping"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-bag-shopping" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Nuit & Bars</span>
</a>
<a href="/nuit-casinos"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-glass-cheers" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Nuit & Bars</span>
</a>
<a href="/agenda-manifestations"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-calendar-days" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Festivals</span>
</a>
</div>
</div>
<div class="menu-panel-section" id="panel-6">
<!-- Titre -->
<div class="menu-panel-title" style="--grp-color:#1abc9c">
<div class="menu-panel-title-img">
<div class="menu-panel-title-icon">
<i class="fa-solid fa-spa" aria-hidden="true"></i> </div>
</div>
<div class="menu-panel-title-text">
<div class="menu-panel-title-name">Bien-être & Thermalisme</div>
<div class="menu-panel-title-desc">Accordez-vous une pause salvatrice et plongez dans un univers dédié à la relaxation absolue et à la santé. Le bien-être est ici élevé au rang d’art de vivre, s’appuyant sur les bienfaits millénaires de l’eau et des soins du corps. Dans des cadres d’exception, profitez de centres de thermalisme et de balnéothérapie où l’expertise des professionnels se conjugue à la pureté des sources naturelles. Que vous veniez pour une cure thérapeutique ciblée ou simplement pour une escapade détente, les installations modernes comme les hammams, les saunas et les spas vous enveloppent d’une chaleur apaisante. Imaginez-vous flotter dans une eau chauffée, recevoir un massage relaxant ou profiter des vertus minérales d’une source naturelle jaillissant au cœur du territoire. C’est une invitation à ralentir le rythme, à écouter son corps et à libérer son esprit des tensions quotidiennes. Au-delà des soins, c’est toute une atmosphère de sérénité qui vous attend, entre jardins de repos et espaces de remise en forme. Retrouvez votre vitalité et votre équilibre intérieur grâce à ces havres de paix où chaque détail est pensé pour votre confort. Une expérience sensorielle unique pour ressortir régénéré, l’esprit léger et le corps tonifié.</div>
</div>
</div>
<!-- Cards -->
<div class="menu-cat-grid">
<a href="/cures-thermes"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-spa" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Thermes & Spa</span>
</a>
<a href="/detente-fitness"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-person-running" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Détente & Sport</span>
</a>
<a href="/sources-fontaines"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-faucet" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Sources</span>
</a>
</div>
</div>
<div class="menu-panel-section" id="panel-7">
<!-- Titre -->
<div class="menu-panel-title" style="--grp-color:#3498db">
<div class="menu-panel-title-img">
<div class="menu-panel-title-icon">
<i class="fa-solid fa-umbrella-beach" aria-hidden="true"></i> </div>
</div>
<div class="menu-panel-title-text">
<div class="menu-panel-title-name">Mer & Littoral</div>
<div class="menu-panel-title-desc">L’appel du large et l’air iodé offrent une promesse d’évasion immédiate. Le littoral est un espace de liberté où l’horizon semble infini, invitant aussi bien à la contemplation qu’à l’action. Que vous soyez attiré par les vastes plages de sable fin pour de longs moments de détente au soleil, ou par les côtes découpées et sauvages propices à l’exploration, l’univers marin déploie des paysages d’une beauté fascinante. Les ports de plaisance et les marinas s’animent au rythme des marées, offrant un spectacle permanent où se mêlent bateaux de pêche traditionnels et voiliers modernes. C’est le terrain de jeu idéal pour les passionnés de sports nautiques : voile, plongée sous-marine à la découverte de fonds mystérieux, ou glisse sur les vagues pour les amateurs de sensations. Mais la mer, c’est aussi un patrimoine vivant, fait de phares solitaires, de ports historiques et de sentiers côtiers qui serpentent entre ciel et eau. Profiter du littoral, c’est savourer la fraîcheur des produits de la mer tout juste débarqués, admirer des couchers de soleil flamboyants sur l’eau et se laisser bercer par le ressac. Une parenthèse tonique et ressourçante où chaque balade en mer devient une expédition mémorable pour toute la famille.</div>
</div>
</div>
<!-- Cards -->
<div class="menu-cat-grid">
<a href="/plages-clubs"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-umbrella-beach" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Plages</span>
</a>
<a href="/ports-marinas"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-anchor" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Ports</span>
</a>
<a href="/nautisme-plongee"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-person-swimming" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Sports Nautiques</span>
</a>
<a href="/balades-mer"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-ship" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Bateau</span>
</a>
</div>
</div>
<div class="menu-panel-section" id="panel-8">
<!-- Titre -->
<div class="menu-panel-title" style="--grp-color:#95a5a6">
<div class="menu-panel-title-img">
<div class="menu-panel-title-icon">
<i class="fa-solid fa-mountain-sun" aria-hidden="true"></i> </div>
</div>
<div class="menu-panel-title-text">
<div class="menu-panel-title-name">Montagne & Sommets</div>
<div class="menu-panel-title-desc">Prenez de la hauteur et laissez-vous séduire par la majesté des sommets qui dominent le paysage. La montagne est une destination aux multiples visages, capable de se métamorphoser au fil des saisons pour offrir des expériences radicalement différentes. En hiver, les domaines se parent de leur manteau blanc, transformant les pentes en terrains de glisse d’exception pour le ski, le snowboard ou les balades en raquettes dans un silence feutré. Dès les beaux jours, les alpages verdoyants reprennent vie, parsemés de fleurs sauvages et animés par les troupeaux en estive. C’est le paradis des randonneurs et des grimpeurs qui cherchent à conquérir les cimes ou à franchir les cols mythiques pour admirer des panoramas à couper le souffle. Les stations de montagne sont aussi des lieux de convivialité et de refuge, où l’architecture de bois et de pierre crée une ambiance chaleureuse. Entre descentes de luge d’été, via ferrata audacieuses et ascensions en téléphérique pour toucher les nuages, l’altitude offre un sentiment de liberté pure. Séjourner en montagne, c’est choisir de ralentir le rythme, de respirer un air d’une pureté rare et de se confronter à la puissance tranquille d’une nature sauvage et indomptable.</div>
</div>
</div>
<!-- Cards -->
<div class="menu-cat-grid">
<a href="/ski-sports-hiver"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-snowflake" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Ski & Hiver</span>
</a>
<a href="/sommets-panoramas"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-mountain" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Sommets</span>
</a>
<a href="/refuges-chalets"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-house-chimney-window" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Refuges</span>
</a>
<a href="/teleferiques-acces"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-cable-car" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Téléphériques</span>
</a>
</div>
</div>
<div class="menu-panel-section" id="panel-9">
<!-- Titre -->
<div class="menu-panel-title" style="--grp-color:#e74c3c">
<div class="menu-panel-title-img">
<div class="menu-panel-title-icon">
<i class="fa-solid fa-star" aria-hidden="true"></i> </div>
</div>
<div class="menu-panel-title-text">
<div class="menu-panel-title-name">Sélections Spéciales</div>
<div class="menu-panel-title-desc">Parce que chaque voyageur est unique et que chaque journée de vacances apporte son lot de surprises, nous avons conçu des parcours thématiques pour répondre à toutes vos envies spécifiques. Parfois, la météo changeante nous incite à chercher des refuges créatifs : découvrez nos suggestions pour sortir et s’amuser quand la pluie s’invite, entre musées captivants, cinémas et espaces de détente couverts. Pour les familles, nous avons regroupé les lieux où l’émerveillement des enfants est garanti, des parcs de jeux aux fermes pédagogiques. Les passionnés d’histoire trouveront des itinéraires dédiés au tourisme de mémoire, pour rendre hommage et comprendre les événements qui ont marqué notre passé. Ces sélections spéciales sont des guides précieux pour ceux qui cherchent l’insolite, le tourisme éco-responsable ou les expériences à sensations fortes. Que vous disposiez d’un petit budget ou que vous soyez en quête de lieux secrets hors des sentiers battus, ces compilations intelligentes mixent les meilleures adresses pour vous offrir une expérience sur mesure. Simplifiez votre organisation et laissez-vous guider par nos thématiques pour ne rien manquer des incontournables et des pépites cachées, quelles que soient les circonstances de votre séjour.</div>
</div>
</div>
<!-- Cards -->
<div class="menu-cat-grid">
<a href="/sortir-pluie"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-cloud-showers-heavy" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Pluie</span>
</a>
<a href="/activites-enfants"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-children" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Enfants</span>
</a>
<a href="/tourisme-memoire"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-monument" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Mémoire</span>
</a>
<a href="/tourisme-eco"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-seedling" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Éco-tourisme</span>
</a>
<a href="/sensation-adrenaline"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-bolt" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Adrénaline</span>
</a>
</div>
</div>
<div class="menu-panel-section" id="panel-10">
<!-- Titre -->
<div class="menu-panel-title" style="--grp-color:#7f8c8d">
<div class="menu-panel-title-img">
<div class="menu-panel-title-icon">
<i class="fa-solid fa-circle-info" aria-hidden="true"></i> </div>
</div>
<div class="menu-panel-title-text">
<div class="menu-panel-title-name">Infos Pratiques</div>
<div class="menu-panel-title-desc">Pour que votre séjour se déroule en toute sérénité, l’accès à une information claire et fiable est essentiel. Cette section regroupe tous les services indispensables qui facilitent votre quotidien de voyageur. Vous y trouverez les points d’accueil des offices de tourisme où des experts locaux sont prêts à vous conseiller pour personnaliser votre itinéraire. Côté mobilité, tout est prévu pour simplifier vos déplacements : gares, aéroports, stations de taxi, aires de covoiturage et bornes de recharge pour véhicules électriques assurent une connexion fluide avec l’ensemble du territoire. Parce que votre confort et votre sécurité sont des priorités, nous répertorions également les services de santé, les pharmacies, ainsi que les commodités pratiques comme les points d’accès WiFi public, les consignes et les parkings. Que vous ayez besoin de planifier votre arrivée, de trouver un transport local ou de résoudre un petit imprévu logistique, ces ressources sont là pour vous accompagner. Bien s’informer, c’est s’offrir la liberté de profiter pleinement de chaque instant sans se soucier de l’organisation technique. Retrouvez ici les clés pour une escale réussie, des conseils de stationnement aux solutions de mobilité douce pour découvrir la destination à votre rythme et en toute tranquillité.</div>
</div>
</div>
<!-- Cards -->
<div class="menu-cat-grid">
<a href="/offices-tourisme"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-circle-info" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Offices de Tourisme</span>
</a>
<a href="/transport-mobilite"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-train-subway" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Transports</span>
</a>
<a href="/services-sante-wifi"
class="menu-cat-card">
<div class="menu-cat-card-img-wrap">
<span class="menu-cat-card-icon"><i class="fa-solid fa-kit-medical" aria-hidden="true"></i></span>
</div>
<span class="menu-cat-card-name">Services</span>
</a>
</div>
</div>
</div><!-- /.menu-panel -->
</div><!-- /.full-menu-body -->
<!-- ══ FOOTER ══ -->
<div class="full-menu-footer">
<a href="https://weetrip.fr" target="_blank" rel="noopener">
🌐 Choisir une autre destination →
</a>
</div>
</div>
<script>
function showMenuPanel(panelId, sidebarItem) {
// Sidebar : retirer active, ajouter sur le cliqué
document.querySelectorAll('.menu-sidebar-item').forEach(function(el) {
el.classList.remove('active');
});
if (sidebarItem) sidebarItem.classList.add('active');
// Panneau : masquer tous, afficher le bon
document.querySelectorAll('.menu-panel-section').forEach(function(el) {
el.classList.remove('active');
});
var panel = document.getElementById(panelId);
if (panel) panel.classList.add('active');
// Sur mobile : scroll le panneau en haut
var mp = document.getElementById('menuPanel');
if (mp) mp.scrollTop = 0;
}
// Sur mobile, scroller la sidebar sur l'item actif au chargement
document.addEventListener('DOMContentLoaded', function() {
var activeItem = document.querySelector('.menu-sidebar-item.active');
if (activeItem && window.innerWidth <= 640) {
activeItem.scrollIntoView({ inline: 'center', behavior: 'smooth' });
}
});
</script>
<section class="hero_cat hero_cat--no-img" id="hero">
<div class="hero-content">
<span class="hero-badge">Expérience Locale</span>
<h1 class="hero-title-cat">Locations & Gîtes</h1>
<!-- <p class="hero-subtitle">Tous les types de cartes sont représentés ici.</p> -->
</div>
</section>
<div class="seo-intro-block">
<div class="seo-intro-inner"><h2>Locations de Vacances & Gîtes : S'Approprier l'Âme d'une Région</h2><p>Louer un gîte ou une maison de vacances offre bien plus qu'un simple hébergement : c'est l'opportunité de vivre comme un habitant, de découvrir les rythmes authentiques d'une région et de tisser une véritable connexion avec le territoire. Contrairement aux hôtels, ces demeures vous permettent d'explorer à votre rythme, de cuisiner vos propres repas, de vous imprégner de la culture locale et de créer des souvenirs intimes en famille ou entre amis.</p><h3>Diversité d'Habitats pour Tous les Goûts</h3><p>Notre catalogue propose une variété incomparable de locations : du gîte rural traditionnel en pierre au cœur de villages pittoresques, à l'appartement urbain dans les quartiers branchés des villes, en passant par les maisons de caractère avec piscine privée. Chaque logement est sélectionné pour son authenticité, son confort et sa capacité à offrir une expérience mémorable. Qu'il s'agisse d'une demeure vigneronne en Bourgogne, d'un cottage normand ou d'un loft parisien, vous découvrirez des propriétés décorées avec soin reflétant l'âme locale.</p><h3>Autonomie et Flexibilité sans Compromis</h3><p>En choisissant une location, vous retrouvez la liberté totale. Horaires flexibles, possibilité de cuisiner à votre convenance, espace privatif 24h/24, aménagement des lieux selon vos préférences : aucune contrainte hôtelière. Cette autonomie est particulièrement appréciée des familles avec enfants, des groupes d'amis souhaitant convivialité, ou des télétravailleurs cherchant un espace de travail confortable. Les cuisines équipées permettent de préparer des repas à base de produits locaux, renforçant l'immersion culturelle.</p><h3>Équipements Modernes & Confort Garanti</h3><p>Malgré leur charme authentique, nos locations bénéficient d'équipements contemporains essentiels : chauffage performant, cuisine moderne, salle de bain rénovée, accès WiFi, télévision, machines à laver. Certaines propriétés premium proposent même piscine intérieure, sauna, home cinéma ou espace bureautique. La qualité de l'isolation phonique et thermique garantit un confort optimal quelle que soit la saison.</p><h3>Immersion Culturelle et Découvertes Régionales</h3><p>Séjourner dans un gîte vous positionne au cœur des attractions authentiques : marchés locaux, vignobles, patrimoine architectural méconnu, festivals régionaux, restaurants de village tenus par des générations de familles. Les propriétaires, souvent locaux, partagent volontiers leurs meilleures adresses et anecdotes historiques. Cette proximité avec la réalité régionale transforme votre séjour en véritable voyage d'exploration.</p><h3>Rapport Qualité-Prix Inégalé</h3><p>Les locations de vacances offrent un excellent rapport qualité-prix, particulièrement pour les séjours prolongés ou les groupes. Les tarifs dégressifs pour les semaines ou les mois, l'absence de frais de service, et la possibilité de préparer vos repas permettent des économies substantielles comparé aux hôtels. Vous bénéficiez ainsi d'un cadre d'exception sans excès de dépenses.</p><p>Choisir une location, c'est opter pour une immersion authentique où chaque moment du séjour vous appartient entièrement.</div>
</div>
<div class="toolbar">
<!-- Filtres desktop (masqués sur mobile) -->
<div class="toolbar-filters">
<span class="cat-title"><i class="fa-solid fa-house" aria-hidden="true"></i> Locations & Gîtes</span>
<div class="search-wrap">
<svg width="14" height="14" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>
<input type="search" id="searchInput" placeholder="Rechercher…" autocomplete="off"/>
<button class="clear-btn" id="clearSearch">✕</button>
</div>
<div class="city-picker" id="cityPicker">
<button class="city-picker-btn" id="cityPickerBtn" type="button" onclick="openCityPicker()" aria-haspopup="listbox" aria-expanded="false">
<svg width="12" height="12" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg>
<span class="city-picker-label" id="cityPickerLabel">Toutes les communes</span>
<svg class="city-picker-chevron" width="11" height="11" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="6 9 12 15 18 9"/></svg>
</button>
<div class="city-picker-drop" id="cityPickerDrop">
<div class="city-search-wrap">
<svg width="13" height="13" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="search" id="citySearch" class="city-search-input"
placeholder="Rechercher…"
oninput="renderCityList('cityDrop','citySearch',communes,false)"
autocomplete="off"/>
</div>
<div class="city-list" id="cityDrop"></div>
<div class="city-picker-footer">
<button class="city-clear-btn" type="button" onclick="clearCities()">Réinitialiser</button>
<span class="city-count-hint" id="cityCountHint"></span>
</div>
</div>
</div>
<button class="reset-btn" id="resetBtn" onclick="resetFilters()" style="display:none">
<svg width="13" height="13" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/>
</svg>Réinitialiser </button>
<button class="share-btn" id="shareBtn" onclick="copyShareUrl()">
<svg width="13" height="13" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/>
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/>
</svg>Partager </button>
</div>
<div class="weebnb-bar" id="weebnbBar">
<i class="fa-solid fa-moon" style="color:var(--accent);font-size:.8rem"></i>
<span class="weebnb-bar-label">Choisir un séjour</span>
<div class="drp-wrap" style="position:relative;flex:1">
<i class="fa-regular fa-calendar" style="position:absolute;left:10px;top:50%;transform:translateY(-50%);color:#888;pointer-events:none;font-size:.8rem;z-index:1"></i>
<input type="text" id="weebnbPicker" class="drp-trigger" placeholder="Choisir les dates" readonly style="padding-left:28px;min-width:200px;width:100%"/>
</div>
<button class="person-btn" id="personBtn" onclick="togglePersonPicker()" title="Capacité">
<i class="fa-solid fa-person" style="font-size:.75rem"></i>
<span id="personBtnLabel">Personnes</span>
</button>
<button class="weebnb-clear-btn" id="weebnbClearBtn" onclick="clearWeebnb()" style="display:none" title="Effacer les dates">×</button>
</div>
<div class="person-overlay" id="personOverlay" onclick="if(event.target===this)closePersonPicker()">
<div class="person-modal">
<div class="person-modal-title" id="personModalTitle">Combien de personnes ?</div>
<div class="person-grid" id="personGrid"></div>
<div class="person-footer">
<button class="p-btn-cancel" onclick="resetPersons()">Annuler la sélection</button>
</div>
</div>
</div>
<!-- Bouton Filtres mobile (masqué sur desktop) -->
<button class="mobile-filter-btn" id="mobileFilterBtn" onclick="openFilterModal()">
<svg width="16" height="16" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<line x1="4" y1="6" x2="20" y2="6"/><line x1="8" y1="12" x2="16" y2="12"/><line x1="11" y1="18" x2="13" y2="18"/>
</svg>
Filtres <span class="filter-badge" id="filterBadge"></span>
</button>
<!-- Carte : visible desktop + mobile -->
<button class="map-toggle-btn active" id="mapToggleBtn" onclick="toggleMap()">
<svg width="13" height="13" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"/>
<line x1="8" y1="2" x2="8" y2="18"/><line x1="16" y1="6" x2="16" y2="22"/>
</svg>Carte </button>
</div>
<!-- ══ FILTER MODAL (mobile bottom sheet) ══════════════════════════════════════ -->
<div class="filter-modal" id="filterModal" role="dialog" aria-modal="true">
<div class="filter-modal-backdrop" id="filterModalBackdrop"></div>
<div class="filter-modal-sheet">
<div class="filter-modal-handle"></div>
<div class="filter-modal-header">
<button class="filter-modal-close" onclick="closeFilterModal()" aria-label="Fermer">×</button>
<h2>Filtres</h2>
<button class="filter-modal-reset" onclick="resetFilterModal()">Réinitialiser</button>
</div>
<div class="filter-modal-body">
<div class="fm-section">
<label class="fm-label">
<i class="fa-solid fa-moon" style="color:var(--accent)"></i>
Choisir un séjour </label>
<div class="fm-drp-wrap">
<i class="fa-regular fa-calendar"></i>
<input type="text" id="mWeebnbPicker" class="fm-drp-input"
placeholder="Choisir les dates" readonly>
</div>
<button class="weebnb-clear-btn" id="mWeebnbClearBtn" onclick="clearWeebnb()" style="display:none;margin-top:8px;width:100%;text-align:center;font-size:.85rem">
Effacer les dates ×
</button>
<div style="margin-top:12px">
<button class="person-btn" id="mPersonBtn" onclick="togglePersonPicker()" style="width:100%;justify-content:center;padding:12px">
<i class="fa-solid fa-person" style="font-size:.8rem"></i>
<span id="mPersonBtnLabel">Personnes</span>
</button>
</div>
</div>
<div class="fm-section">
<label class="fm-label" for="mSearch">Recherche</label>
<div class="fm-search-wrap">
<svg width="15" height="15" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>
<input type="search" id="mSearch" class="fm-search-input"
placeholder="Rechercher…" autocomplete="off"
oninput="applyFromModal()"/>
</div>
</div>
<div class="fm-section">
<label class="fm-label">Commune</label>
<div class="fm-search-wrap">
<svg width="15" height="15" viewbox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="search" id="mCitySearch" class="fm-search-input"
placeholder="Rechercher…"
oninput="renderCityList('mCityDrop','mCitySearch',modalCommunes,true)"
autocomplete="off"/>
</div>
<div class="fm-city-list" id="mCityDrop"></div>
</div>
</div>
<div class="filter-modal-footer">
<button class="fm-apply-btn" onclick="closeFilterModal()">
Voir les résultats <span class="fm-apply-count" id="fmCount"></span>
</button>
</div>
</div>
</div>
<div class="catalogue-layout" id="catalogueLayout">
<div class="cards-panel" id="cardsPanel">
<div class="stats-bar" id="statsBar"></div>
<div class="grid" id="grid">
<div class="state"><div class="spinner"></div><p>Chargement…</p><p class="progress" id="progressMsg"></p></div>
</div>
</div>
<div class="map-panel" id="mapPanel">
<div id="catalogue-map"></div>
</div>
</div>
<style>
/* ══ FOOTER COMPACT ══════════════════════════════════════════════════════════ */
footer.site-footer {
background: #fff;
color: #444;
padding: 30px 0 15px; /* Padding réduit */
border-top: 1px solid #eee;
font-family: system-ui, -apple-system, sans-serif;
font-size: 0.85rem;
}
.f-container { max-width: 1100px; margin: 0 auto; padding: 0 20px; }
/* --- TOP : Plus discret --- */
.f-top { padding-bottom: 20px; border-bottom: 1px solid #f5f5f5; }
.f-logo {
font-weight: 800; font-size: 1.1rem; color: #000;
display: flex; align-items: center; gap: 7px; margin-bottom: 8px;
}
.f-logo .logo-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--menu-accent, #FF385C); }
.f-desc { color: #777; line-height: 1.4; font-size: 0.8rem; max-width: 600px; }
/* --- GRID : Plus serrée --- */
.f-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); /* Colonnes plus étroites */
gap: 20px;
padding: 25px 0;
}
.f-group h4 {
font-size: 0.7rem; font-weight: 700; text-transform: uppercase;
letter-spacing: 0.03em; color: #999; margin-bottom: 12px;
}
.f-nav { display: flex; flex-direction: column; gap: 6px; }
.f-nav a {
color: #555; text-decoration: none; font-size: 0.8rem;
display: flex; align-items: center; gap: 6px; transition: 0.15s;
}
.f-nav a:hover { color: var(--menu-accent, #FF385C); }
.f-nav a span { font-size: 0.9rem; width: 18px; }
/* --- TRUST : Ultra minimal --- */
.f-trust { border-top: 1px solid #f5f5f5; padding: 15px 0; font-size: 0.75rem; color: #bbb; }
.f-trust-list { display: flex; justify-content: center; gap: 30px; }
/* --- BOTTOM : Compact --- */
.f-bottom { padding: 20px 0 10px; border-top: 1px solid #eee; }
.f-bottom-inner { display: flex; flex-direction: column; align-items: center; gap: 15px; }
.f-official-btn {
font-size: 0.75rem; font-weight: 700; color: #444; background: #f5f5f5;
padding: 6px 16px; border-radius: 20px; text-decoration: none;
}
.f-official-btn:hover { background: #000; color: #fff; }
.f-copyright-row { display: flex; gap: 15px; color: #999; font-size: 0.75rem; flex-wrap: wrap; justify-content: center; }
.f-copyright-row a { color: inherit; text-decoration: none; }
.f-copyright-row a:hover { text-decoration: underline; }
@media (max-width: 600px) {
.f-grid { grid-template-columns: repeat(2, 1fr); gap: 15px; }
}
</style>
<footer class="site-footer">
<div class="f-container">
<div class="f-top">
<div class="f-logo"><span class="logo-dot"></span>Bassin d'Arcachon</div>
<p class="f-desc">Un écrin d'eau entre dunes, forêts et ostréiculture sur la côte atlantique girondine.</p>
</div>
<div class="f-grid">
<div class="f-group">
<h4>Séjours & Hébergements</h4>
<nav class="f-nav">
<a href="/hotels-prestige">
<span><i class="fa-solid fa-hotel" aria-hidden="true"></i></span>
Hôtels & Prestige </a>
<a href="/locations-gites">
<span><i class="fa-solid fa-house" aria-hidden="true"></i></span>
Locations & Gîtes </a>
<a href="/chambres-hotes">
<span><i class="fa-solid fa-bed" aria-hidden="true"></i></span>
Chambres d’Hôtes </a>
<a href="/campings-insolite">
<span><i class="fa-solid fa-tent" aria-hidden="true"></i></span>
Campings & Insolite </a>
<a href="/camping-car-van">
<span><i class="fa-solid fa-caravan" aria-hidden="true"></i></span>
Aires Camping-Car </a>
<a href="/groupe-jeunesse">
<span><i class="fa-solid fa-users-rectangle" aria-hidden="true"></i></span>
Groupes & Jeunesse </a>
</nav>
</div>
<div class="f-group">
<h4>Gastronomie & Terroir</h4>
<nav class="f-nav">
<a href="/restaurants-tables">
<span><i class="fa-solid fa-utensils" aria-hidden="true"></i></span>
Restaurants </a>
<a href="/brasseries-cafes">
<span><i class="fa-solid fa-mug-hot" aria-hidden="true"></i></span>
Brasseries & Cafés </a>
<a href="/vins-distilleries">
<span><i class="fa-solid fa-wine-glass" aria-hidden="true"></i></span>
Vins & Caves </a>
<a href="/producteurs-marches">
<span><i class="fa-solid fa-basket-shopping" aria-hidden="true"></i></span>
Marchés & Producteurs </a>
</nav>
</div>
<div class="f-group">
<h4>Culture & Patrimoine</h4>
<nav class="f-nav">
<a href="/chateaux-forts">
<span><i class="fa-solid fa-fort-awesome" aria-hidden="true"></i></span>
Châteaux & Forts </a>
<a href="/edifices-religieux">
<span><i class="fa-solid fa-church" aria-hidden="true"></i></span>
Patrimoine religieux </a>
<a href="/musees-arts">
<span><i class="fa-solid fa-building-columns" aria-hidden="true"></i></span>
Musées & Arts </a>
<a href="/archeologie-grottes">
<span><i class="fa-solid fa-hill-rockslide" aria-hidden="true"></i></span>
Archéologie & Grottes </a>
<a href="/patrimoine-industriel">
<span><i class="fa-solid fa-gears" aria-hidden="true"></i></span>
Industrie & Artisanat </a>
</nav>
</div>
<div class="f-group">
<h4>Nature & Activités</h4>
<nav class="f-nav">
<a href="/parcs-jardins">
<span><i class="fa-solid fa-leaf" aria-hidden="true"></i></span>
Parcs & Jardins </a>
<a href="/ski-sports-hiver">
<span><i class="fa-solid fa-snowflake" aria-hidden="true"></i></span>
Ski & Hiver </a>
<a href="/eau-nature">
<span><i class="fa-solid fa-droplet" aria-hidden="true"></i></span>
Eau & Nature </a>
<a href="/sommets-panoramas">
<span><i class="fa-solid fa-mountain" aria-hidden="true"></i></span>
Sommets </a>
<a href="/balades-itineraires">
<span><i class="fa-solid fa-person-walking" aria-hidden="true"></i></span>
Rando & Vélo </a>
<a href="/aventure-loisirs">
<span><i class="fa-solid fa-mountain-climbing" aria-hidden="true"></i></span>
Aventure & Sport </a>
<a href="/faune-animaliers">
<span><i class="fa-solid fa-hippo" aria-hidden="true"></i></span>
Zoos & Animaux </a>
</nav>
</div>
<div class="f-group">
<h4>Sorties & Agenda</h4>
<nav class="f-nav">
<a href="/evenements-festivals">
<span><i class="fa-solid fa-masks-theater" aria-hidden="true"></i></span>
Spectacles </a>
<a href="/spectacles-cinema">
<span><i class="fa-solid fa-film" aria-hidden="true"></i></span>
Foires & Shopping </a>
<a href="/foires-shopping">
<span><i class="fa-solid fa-bag-shopping" aria-hidden="true"></i></span>
Nuit & Bars </a>
<a href="/nuit-casinos">
<span><i class="fa-solid fa-glass-cheers" aria-hidden="true"></i></span>
Nuit & Bars </a>
<a href="/agenda-manifestations">
<span><i class="fa-solid fa-calendar-days" aria-hidden="true"></i></span>
Festivals </a>
</nav>
</div>
<div class="f-group">
<h4>Bien-être & Thermalisme</h4>
<nav class="f-nav">
<a href="/cures-thermes">
<span><i class="fa-solid fa-spa" aria-hidden="true"></i></span>
Thermes & Spa </a>
<a href="/detente-fitness">
<span><i class="fa-solid fa-person-running" aria-hidden="true"></i></span>
Détente & Sport </a>
<a href="/sources-fontaines">
<span><i class="fa-solid fa-faucet" aria-hidden="true"></i></span>
Sources </a>
</nav>
</div>
<div class="f-group">
<h4>Mer & Littoral</h4>
<nav class="f-nav">
<a href="/plages-clubs">
<span><i class="fa-solid fa-umbrella-beach" aria-hidden="true"></i></span>
Plages </a>
<a href="/ports-marinas">
<span><i class="fa-solid fa-anchor" aria-hidden="true"></i></span>
Ports </a>
<a href="/nautisme-plongee">
<span><i class="fa-solid fa-person-swimming" aria-hidden="true"></i></span>
Sports Nautiques </a>
<a href="/balades-mer">
<span><i class="fa-solid fa-ship" aria-hidden="true"></i></span>
Bateau </a>
</nav>
</div>
<div class="f-group">
<h4>Montagne & Sommets</h4>
<nav class="f-nav">
<a href="/ski-sports-hiver">
<span><i class="fa-solid fa-snowflake" aria-hidden="true"></i></span>
Ski & Hiver </a>
<a href="/sommets-panoramas">
<span><i class="fa-solid fa-mountain" aria-hidden="true"></i></span>
Sommets </a>
<a href="/refuges-chalets">
<span><i class="fa-solid fa-house-chimney-window" aria-hidden="true"></i></span>
Refuges </a>
<a href="/teleferiques-acces">
<span><i class="fa-solid fa-cable-car" aria-hidden="true"></i></span>
Téléphériques </a>
</nav>
</div>
<div class="f-group">
<h4>Sélections Spéciales</h4>
<nav class="f-nav">
<a href="/sortir-pluie">
<span><i class="fa-solid fa-cloud-showers-heavy" aria-hidden="true"></i></span>
Pluie </a>
<a href="/activites-enfants">
<span><i class="fa-solid fa-children" aria-hidden="true"></i></span>
Enfants </a>
<a href="/tourisme-memoire">
<span><i class="fa-solid fa-monument" aria-hidden="true"></i></span>
Mémoire </a>
<a href="/tourisme-eco">
<span><i class="fa-solid fa-seedling" aria-hidden="true"></i></span>
Éco-tourisme </a>
<a href="/sensation-adrenaline">
<span><i class="fa-solid fa-bolt" aria-hidden="true"></i></span>
Adrénaline </a>
</nav>
</div>
<div class="f-group">
<h4>Infos Pratiques</h4>
<nav class="f-nav">
<a href="/offices-tourisme">
<span><i class="fa-solid fa-circle-info" aria-hidden="true"></i></span>
Offices de Tourisme </a>
<a href="/transport-mobilite">
<span><i class="fa-solid fa-train-subway" aria-hidden="true"></i></span>
Transports </a>
<a href="/services-sante-wifi">
<span><i class="fa-solid fa-kit-medical" aria-hidden="true"></i></span>
Services </a>
</nav>
</div>
</div>
</div>
<div class="f-trust">
<div class="f-trust-list">
<span>Source : DATAtourisme</span>
<span>Mise à jour régulière</span>
</div>
</div>
<div class="f-bottom">
<div class="f-container">
<div class="f-bottom-inner">
<a href="https://weetrip.fr" target="_blank" rel="noopener" class="f-official-btn">
🌐 Site officiel
</a>
<div class="f-copyright-row">
<span>© 2026 Bassin d'Arcachon</span>
<a href="/mentions-legales">Mentions légales</a>
<a href="/confidentialite">Confidentialité</a>
<a href="/plan-du-site">Plan du site</a>
</div>
</div>
</div>
</div>
</footer>
<!-- JSON-LD WebSite -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Bassin d'Arcachon",
"url": "https://bassindarcachon.weetrip.fr",
"description": "Découvrez les meilleurs restaurants, activités, hébergements et lieux incontournables",
"potentialAction": {
"@type": "SearchAction",
"target": {
"@type": "EntryPoint",
"urlTemplate": "https://bassindarcachon.weetrip.fr/offices-tourisme?q={search_term_string}"
},
"query-input": "required name=search_term_string"
}
}</script>
<script>
(function(){
const quality = 85;
const crop = 1; // Valeur par défaut
// Transforme les URL relatives en URL absolue
function toAbsoluteUrl(url) {
if(!url) return '';
if(url.startsWith('http') || url.startsWith('data:')) return url;
return window.location.origin + url;
}
// Génère l'URL vers resize.php
function resizeUrl(url, width, height, customCrop, customQuality, customFit) {
// Utiliser les valeurs personnalisées si fournies, sinon utiliser les valeurs par défaut
const finalCrop = customCrop !== undefined ? customCrop : crop;
const finalQuality = customQuality !== undefined ? customQuality : quality;
let params = "url=" + encodeURIComponent(url)
+ "&width=" + width
+ "&height=" + height
+ "&crop=" + finalCrop
+ "&quality=" + finalQuality;
// Ajouter le paramètre fit si spécifié
if(customFit) {
params += "&fit=" + customFit;
}
return "/img/resize.php?" + params;
}
// Met à jour le background d'un div
function updateBackground(el) {
const url = toAbsoluteUrl(el.dataset.bg);
if(!url) return;
// ⭐ CORRECTION : Attendre que l'élément ait des dimensions
const w = el.clientWidth || el.offsetWidth;
const h = el.clientHeight || el.offsetHeight;
if(w && h) {
// ⭐ NOUVEAU : Récupérer les paramètres personnalisés
const customCrop = el.dataset.crop !== undefined ? parseInt(el.dataset.crop) : undefined;
const customQuality = el.dataset.quality !== undefined ? parseInt(el.dataset.quality) : undefined;
const customFit = el.dataset.fit || undefined;
el.style.backgroundImage = "url('" + resizeUrl(url, w, h, customCrop, customQuality, customFit) + "')";
//console.log('✅ Background updated:', url, w + 'x' + h, 'crop:', customCrop ?? crop);
} else {
// console.log('⏭️ Background element has no dimensions, skipping');
return;
}
}
// Met à jour le src d'une image <img>
function updateImage(el) {
// ⭐ CORRECTION : Prioriser data-src pour éviter le chargement de l'image originale
let src = el.dataset.src || el.getAttribute('data-src') || el.src;
// Si data-src existe mais que src ne pointe pas encore vers resize.php
// alors on sauvegarde data-src et on vide src temporairement
if(el.dataset.src && !el.src.includes('/img/resize.php')) {
// Mettre un placeholder transparent si src n'en est pas déjà un
if(!el.src.startsWith('data:image')) {
el.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
}
}
src = toAbsoluteUrl(src);
// ⭐ NOUVEAU : Calculer les dimensions en tenant compte de max-width/max-height
let w = el.clientWidth || el.offsetWidth;
let h = el.clientHeight || el.offsetHeight;
// Si l'élément a max-width/max-height, utiliser ces valeurs
const style = window.getComputedStyle(el);
const maxWidth = parseInt(style.maxWidth);
const maxHeight = parseInt(style.maxHeight);
// Si max-width est défini et plus grand que la largeur actuelle, l'utiliser
if(maxWidth && !isNaN(maxWidth) && maxWidth > w && maxWidth < 9999) {
// console.log('📏 Using max-width:', maxWidth, 'instead of current width:', w);
w = maxWidth;
}
// Si max-height est défini et plus grand que la hauteur actuelle, l'utiliser
if(maxHeight && !isNaN(maxHeight) && maxHeight > h && maxHeight < 9999) {
// console.log('📏 Using max-height:', maxHeight, 'instead of current height:', h);
h = maxHeight;
}
// Si aspect-ratio est défini, recalculer h basé sur w
const aspectRatio = style.aspectRatio;
if(aspectRatio && aspectRatio !== 'auto') {
const ratio = aspectRatio.split('/');
if(ratio.length === 2) {
const ratioValue = parseFloat(ratio[0]) / parseFloat(ratio[1]);
h = Math.round(w / ratioValue);
// console.log('📐 Calculated height from aspect-ratio:', h);
}
}
// ⭐ NOUVEAU : Vérifier que les dimensions sont réalistes (pas 1x1 ou 0x0)
if(!w || !h || w < 10 || h < 10) {
// console.log('⏭️ Image has no valid dimensions, skipping');
return;
}
// ⭐ NOUVEAU : Récupérer les paramètres personnalisés de l'élément
const customCrop = el.dataset.crop !== undefined ? parseInt(el.dataset.crop) : undefined;
const customQuality = el.dataset.quality !== undefined ? parseInt(el.dataset.quality) : undefined;
const customFit = el.dataset.fit || undefined;
const newSrc = resizeUrl(src, w, h, customCrop, customQuality, customFit);
// ⭐ CORRECTION : Vérifier si l'image a déjà été redimensionnée
const currentSrc = el.getAttribute('src') || '';
const alreadyResized = currentSrc.includes('/img/resize.php');
// console.log('🔍 Debug info:', {
// originalSrc: src,
// currentSrc: currentSrc,
// newSrc: newSrc,
// dimensions: w + 'x' + h,
// crop: customCrop ?? crop,
// quality: customQuality ?? quality,
// fit: customFit || 'default',
// alreadyResized: alreadyResized,
// willUpdate: !alreadyResized || currentSrc !== newSrc
// });
// Ne mettre à jour que si ce n'est pas déjà fait
if(!alreadyResized || currentSrc !== newSrc) {
//console.log('🔄 Updating image src from:', currentSrc, 'to:', newSrc);
// ⭐ Masquer pendant le chargement
el.style.opacity = '0';
el.style.transition = 'opacity 0.3s ease';
// Sauvegarder l'URL originale si ce n'est pas déjà fait
if(!el.dataset.src) el.dataset.src = src;
// Mettre à jour le src avec les deux méthodes pour être sûr
el.setAttribute('src', newSrc);
el.src = newSrc;
//console.log('✏️ Src updated. Verification:', el.getAttribute('src'));
// ⭐ NOUVEAU : Protéger le src contre les modifications
protectSrc(el, newSrc);
// ⭐ Afficher une fois chargée
el.onload = function() {
el.style.opacity = '1';
// console.log('✅ Image loaded and displayed:', newSrc, w + 'x' + h);
// console.log('📸 Final src in DOM:', el.getAttribute('src'));
};
// Fallback au cas où onload ne se déclenche pas
el.onerror = function() {
console.error('❌ Error loading resized image:', newSrc);
// Retour à l'image originale en cas d'erreur
el.setAttribute('src', src);
el.src = src;
el.style.opacity = '1';
};
} else {
// console.log('✅ Image already resized:', currentSrc, w + 'x' + h);
}
}
// ⭐ NOUVEAU : Protège le src d'une image contre les modifications
function protectSrc(el, correctSrc) {
if(el.dataset.srcProtected) return; // Déjà protégé
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if(mutation.type === 'attributes' && mutation.attributeName === 'src') {
const currentSrc = el.getAttribute('src');
if(currentSrc !== correctSrc && !currentSrc.includes('/img/resize.php')) {
console.warn('⚠️ src has been changed by another script! Restoring:', correctSrc);
el.setAttribute('src', correctSrc);
el.src = correctSrc;
}
}
});
});
observer.observe(el, {
attributes: true,
attributeFilter: ['src']
});
el.dataset.srcProtected = 'true';
// console.log('🛡️ Src protection enabled for:', el);
}
// Initialise un élément <div> ou <img>
function initElement(el) {
// console.log('🔄 Init element:', el);
if(el.dataset.bg) {
updateBackground(el);
// ⭐ OPTIMISATION : Éviter de créer plusieurs listeners
if(!el.dataset.resizeListenerAdded) {
window.addEventListener('resize', () => updateBackground(el));
el.dataset.resizeListenerAdded = 'true';
}
}
if(el.dataset.resize !== undefined || el.hasAttribute('data-resize')) {
// ⭐ NOUVEAU : Cacher l'image dès le départ
if(!el.dataset.initialized) {
el.style.opacity = '0';
el.dataset.initialized = 'true';
}
if(!el.dataset.src && el.src && !el.src.startsWith('data:image')) {
el.dataset.src = el.src;
}
// ⭐ FIX : Ne pas appeler updateImage directement, laisser l'IntersectionObserver gérer
// Les images seront traitées quand elles seront visibles
// ⭐ OPTIMISATION : Éviter de créer plusieurs listeners
if(!el.dataset.resizeListenerAdded) {
window.addEventListener('resize', () => updateImage(el));
el.dataset.resizeListenerAdded = 'true';
}
}
}
// Initialise tous les éléments existants
function initAll() {
// console.log('🚀 Init all elements');
document.querySelectorAll('[data-bg], img[data-resize], [data-resize]').forEach(initElement);
}
// Surveille le DOM pour les éléments dynamiques
function observeDOM() {
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if(node.nodeType !== 1) return; // ignorer non-element
// ⭐ CORRECTION : Vérifier l'élément lui-même ET ses enfants
if(node.matches && node.matches('[data-bg], img[data-resize], [data-resize]')) {
// console.log('🆕 New element detected:', node);
// ⭐ Attendre un peu que l'élément soit rendu
setTimeout(() => initElement(node), 50);
}
// Chercher dans les enfants
if(node.querySelectorAll) {
node.querySelectorAll('[data-bg], img[data-resize], [data-resize]').forEach(child => {
//console.log('🆕 New child detected:', child);
setTimeout(() => initElement(child), 50);
});
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
// console.log('👀 DOM Observer started');
}
// ⭐ NOUVEAU : Observer les changements de visibilité (utile pour les éléments cachés/affichés)
function observeVisibility() {
if('IntersectionObserver' in window) {
const io = new IntersectionObserver(entries => {
entries.forEach(entry => {
if(entry.isIntersecting) {
const el = entry.target;
if(el.dataset.bg) updateBackground(el);
if(el.dataset.resize !== undefined) updateImage(el);
}
});
});
// Observer tous les éléments concernés
document.querySelectorAll('[data-bg], img[data-resize], [data-resize]').forEach(el => {
io.observe(el);
});
}
}
// Lancement après le DOM complet
if(document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
initAll();
observeDOM();
observeVisibility();
});
} else {
// Le DOM est déjà chargé
initAll();
observeDOM();
observeVisibility();
}
//console.log('📦 Resize script loaded');
})();
</script>
<script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/fr.js"></script>
<script>
// ─── Config PHP → JS ─────────────────────────────────────────────────────────
const API_BASE = "/api";
const TERRITORY_SLUG = "bassin-arcachon";
const COMMUNES = {"33009":"Arcachon","33529":"La Teste-de-Buch","33199":"Gujan-Mestras","33527":"Le Teich","33051":"Biganos","33019":"Audenge","33229":"Lanton","33005":"Andernos-les-Bains","33011":"Ar\u00e8s","33236":"L\u00e8ge-Cap-Ferret","33284":"Mios","33498":"Salles"};
const CATEGORIES = {"offices-tourisme":{"icon":"fa-solid fa-circle-info","label":"Offices de Tourisme","labels":{"fr":"Offices de Tourisme"},"types":["TouristInformationCenter","LocalTouristOffice"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Bureaux d'Information et Offices de Tourisme : \u00c0 votre Service\",\"en\":\"Tourist Information Centers & Offices: At your Service\"}","seo_description":"{\"fr\":\"Retrouvez nos conseillers en s\u00e9jour. Documentation, conseils personnalis\u00e9s et billetterie.\",\"en\":\"Meet our travel advisors. Documentation, personalized advice, and ticketing.\"}","seo_intro":"{\"fr\":\"<h2>Offices de Tourisme : Vos Meilleurs Alli\u00e9s<\/h2><p>Pour ne rien manquer de votre s\u00e9jour, poussez la porte d\u2019un <strong>Office de Tourisme<\/strong>. Nos conseillers en s\u00e9jour sont des experts du territoire, pr\u00eats \u00e0 vous livrer leurs \\\"coups de c\u0153ur\\\" et leurs conseils personnalis\u00e9s. Que vous cherchiez un plan de ville, le programme des animations ou une r\u00e9servation de derni\u00e8re minute, ils sont l\u00e0 pour vous simplifier la vie.<\/p><h3>Un service de proximit\u00e9<\/h3><p>En plus de la documentation gratuite, les <strong>bureaux d'information<\/strong> proposent souvent des services de billetterie pour les sites touristiques ou les spectacles locaux. C\u2019est aussi l\u2019endroit id\u00e9al pour acheter des produits locaux ou des souvenirs artisanaux. Un passage par l'Office de Tourisme, c'est l'assurance d'un voyage r\u00e9ussi et optimis\u00e9.<\/p>\",\"en\":\"<h2>Tourist Offices: Your Best Allies<\/h2><p>To make the most of your stay, visit a <strong>Tourist Office<\/strong>. Our advisors are local experts ready to share their top tips and personalized advice.<\/p><h3>Local Service<\/h3><p>In addition to free documentation, <strong>information centers<\/strong> often provide ticketing services for local attractions and shows. It's the best place to start a successful trip.<\/p>\"}","group_id":10,"group_ids":[10]},"chateaux-forts":{"icon":"fa-solid fa-fort-awesome","label":"Ch\u00e2teaux & Forts","labels":{"fr":"Ch\u00e2teaux & Forts"},"types":["Castle","FortifiedCastle","Fort","Citadel","Tower"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Mus\u00e9es, Expositions et Galeries d'Art : Culture & Art\",\"en\":\"Museums, Exhibitions & Art Galleries\"}","seo_description":"{\"fr\":\"Plongez dans l'art et l'histoire. Mus\u00e9es nationaux, expositions temporaires et galeries d'art contemporain.\",\"en\":\"Dive into art and history. National museums, temporary exhibitions, and contemporary art galleries.\"}","seo_intro":"{\"fr\":\"<h2>Mus\u00e9es et Galeries : Un Voyage au C\u0153ur de la Cr\u00e9ation<\/h2><p>La richesse culturelle d\u2019une destination se mesure souvent \u00e0 la diversit\u00e9 de ses <strong>mus\u00e9es<\/strong> et de ses espaces d\u2019exposition. De l\u2019arch\u00e9ologie \u00e0 l\u2019art contemporain, en passant par les mus\u00e9es techniques ou ethnographiques, notre s\u00e9lection vous ouvre les portes de lieux o\u00f9 le savoir et l\u2019esth\u00e9tique se rencontrent pour \u00e9merveiller petits et grands.<\/p><h3>L\u2019Histoire et les Beaux-Arts<\/h3><p>Les <strong>mus\u00e9es des Beaux-Arts<\/strong> abritent des collections permanentes qui traversent les si\u00e8cles. Peintures classiques, sculptures monumentales et objets d\u2019art pr\u00e9cieux vous permettent de comprendre l\u2019\u00e9volution des courants artistiques. Pour les passionn\u00e9s d\u2019histoire, les mus\u00e9es th\u00e9matiques retracent l\u2019\u00e9pop\u00e9e d\u2019une ville, d\u2019une industrie ou d\u2019une tradition locale, offrant une perspective unique sur l\u2019identit\u00e9 du territoire.<\/p><h3>Art Contemporain et Galeries priv\u00e9es<\/h3><p>Si vous pr\u00e9f\u00e9rez la cr\u00e9ation actuelle, explorez les <strong>galeries d\u2019art<\/strong> et les centres d\u2019art contemporain. Ces lieux, souvent install\u00e9s dans des architectures audacieuses ou des sites industriels r\u00e9habilit\u00e9s, mettent en avant les artistes d\u2019aujourd\u2019hui. Les vernissages sont des moments privil\u00e9gi\u00e9s pour rencontrer les cr\u00e9ateurs et \u00e9changer sur leurs \u0153uvres. Les <strong>expositions temporaires<\/strong>, quant \u00e0 elles, renouvellent sans cesse l\u2019int\u00e9r\u00eat culturel en proposant des r\u00e9trospectives in\u00e9dites ou des focus sur des th\u00e9matiques modernes.<\/p><h3>Une culture accessible \u00e0 tous<\/h3><p>De nombreux mus\u00e9es proposent des parcours ludiques pour les enfants, des audioguides multilingues et des ateliers interactifs. Que vous soyez un sp\u00e9cialiste ou un n\u00e9ophyte, pousser la porte d\u2019une galerie ou d\u2019un mus\u00e9e est la promesse d\u2019une pause enrichissante, \u00e0 l\u2019abri du temps. <strong>Astuce :<\/strong> V\u00e9rifiez les jours de gratuit\u00e9 (souvent le premier dimanche du mois) pour profiter pleinement de l\u2019offre culturelle.<\/p>\",\"en\":\"<h2>Museums and Galleries: A Journey into Creativity<\/h2><p>The cultural richness of a destination is measured by the diversity of its <strong>museums<\/strong> and exhibition spaces. From archaeology to contemporary art, our selection opens the doors to places where knowledge and aesthetics meet.<\/p><h3>History and Fine Arts<\/h3><p><strong>Fine Arts museums<\/strong> house permanent collections spanning centuries. For history buffs, thematic museums trace the epic story of a city or a tradition, offering a unique perspective on regional identity.<\/p><h3>Contemporary Art and Galleries<\/h3><p>If you prefer current creation, explore <strong>art galleries<\/strong> and contemporary art centers. These venues showcase today's artists through innovative exhibitions. Many museums offer interactive workshops for children, making culture accessible to all.<\/p>\"}","group_id":3,"group_ids":[3]},"cures-thermes":{"icon":"fa-solid fa-spa","label":"Thermes & Spa","labels":{"fr":"Thermes & Spa"},"types":["BalneotherapyCentre","ThalassotherapyCentre","Spa"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Cures Thermales et Centres de Soins : Sant\u00e9 et Bien-\u00eatre par l'Eau\",\"en\":\"Thermal Spas & Care Centers: Health and Wellness through Water\"}","seo_description":"{\"fr\":\"Profitez des bienfaits des eaux thermales : cures, soins de sant\u00e9 et relaxation en centre de cure.\",\"en\":\"Enjoy the benefits of thermal waters: health treatments and relaxation in spa centers.\"}","seo_intro":"{\"fr\":\"<h2>Le Thermalisme : Une Tradition de Sant\u00e9<\/h2><p>Depuis l'Antiquit\u00e9, les eaux de notre r\u00e9gion sont reconnues pour leurs vertus th\u00e9rapeutiques. Les <strong>centres de cures thermales<\/strong> accueillent les curistes pour des protocoles m\u00e9dicaux ou des s\u00e9jours de remise en forme. C'est l'alliance parfaite entre la m\u00e9decine naturelle et le confort moderne pour traiter diverses pathologies ou simplement \u00e9liminer le stress accumul\u00e9.<\/p><h3>Soins et R\u00e9g\u00e9n\u00e9ration<\/h3><p>L'eau thermale, riche en min\u00e9raux, est utilis\u00e9e sous forme de bains, de douches \u00e0 jets ou de vapeurs. Encadr\u00e9s par des professionnels de sant\u00e9, les soins en <strong>centre de cure<\/strong> permettent une r\u00e9g\u00e9n\u00e9ration profonde du corps. Au-del\u00e0 des cures m\u00e9dicalis\u00e9es, ces \u00e9tablissements proposent souvent des forfaits \\\"d\u00e9couverte\\\" pour profiter des bassins et des bienfaits de l'eau min\u00e9rale sur une courte dur\u00e9e.<\/p>\",\"en\":\"<h2>Thermalism: A Tradition of Health<\/h2><p>Since antiquity, our waters have been recognized for their therapeutic virtues. <strong>Thermal spa centers<\/strong> welcome guests for medical treatments or fitness stays.<\/p><h3>Care and Regeneration<\/h3><p>Mineral-rich thermal water is used in baths and jet showers. Supervised by health professionals, these treatments allow for deep regeneration of the body.<\/p>\"}","group_id":6,"group_ids":[6]},"evenements-festivals":{"icon":"fa-solid fa-masks-theater","label":"Spectacles","labels":{"fr":"Spectacles"},"types":["Festival","Concert","MusicEvent","TraditionalCelebration"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Boutiques et Commerces : Shopping et Vie Locale\",\"en\":\"Shops & Local Business: Shopping and Local Life\"}","seo_description":"{\"fr\":\"Faites votre shopping chez nos commer\u00e7ants locaux : mode, souvenirs, d\u00e9coration et produits r\u00e9gionaux.\",\"en\":\"Shop at local businesses: fashion, souvenirs, decor, and regional products.\"}","seo_intro":"{\"fr\":\"<h2>Shopping et Commerces : Le C\u0153ur Battant de nos Villes<\/h2><p>Faire ses courses dans les <strong>commerces de proximit\u00e9<\/strong>, c\u2019est participer \u00e0 la vie sociale d\u2019une commune tout en d\u00e9couvrant des produits s\u00e9lectionn\u00e9s avec soin. Des boutiques de mode ind\u00e9pendantes aux concept-stores branch\u00e9s, en passant par les \u00e9piceries fines, l\u2019offre commerciale de notre territoire est riche et vari\u00e9e, privil\u00e9giant souvent la qualit\u00e9 et le conseil personnalis\u00e9.<\/p><h3>Boutiques de mode et de d\u00e9coration<\/h3><p>Loin des grandes enseignes uniformis\u00e9es, nos <strong>boutiques ind\u00e9pendantes<\/strong> proposent des collections de v\u00eatements, d\u2019accessoires et d\u2019objets de d\u00e9coration qui sortent de l\u2019ordinaire. Vous y trouverez des cr\u00e9ateurs locaux, des produits \u00e9co-responsables et des pi\u00e8ces uniques pour affirmer votre style ou embellir votre int\u00e9rieur. Fl\u00e2ner dans les rues commer\u00e7antes est un plaisir en soi, ponctu\u00e9 de d\u00e9couvertes surprenantes dans des vitrines d\u00e9cor\u00e9es avec go\u00fbt.<\/p><h3>Souvenirs et Produits R\u00e9gionaux<\/h3><p>Ne repartez pas sans un morceau de notre terroir. Les <strong>commerces de bouche<\/strong> et boutiques de souvenirs regorgent de tr\u00e9sors : sp\u00e9cialit\u00e9s culinaires, spiritueux locaux, ou artisanat typique. Les commer\u00e7ants, fiers de leurs racines, sont les meilleurs ambassadeurs pour vous conseiller le produit authentique qui ravira vos proches. Soutenir le commerce de proximit\u00e9, c\u2019est garantir la diversit\u00e9 et le dynamisme de nos centres-villes et villages.<\/p>\",\"en\":\"<h2>Shopping and Businesses: The Beating Heart of Our Towns<\/h2><p>Shopping at <strong>local businesses<\/strong> means participating in social life while discovering carefully selected products. From independent fashion boutiques to specialty food shops, the local offer is rich and varied.<\/p><h3>Fashion and Decor Boutiques<\/h3><p>Our <strong>independent shops<\/strong> offer unique clothing and home decor collections far from standardized brands. You will find local designers and eco-friendly products. Strolling through shopping streets is a pleasure in itself.<\/p><h3>Souvenirs and Regional Products<\/h3><p>Don't leave without a piece of the local land. <strong>Local food shops<\/strong> and souvenir stores are full of treasures: culinary specialties and authentic crafts.<\/p>\"}","group_id":5,"group_ids":[5]},"hotels-prestige":{"icon":"fa-solid fa-hotel","label":"H\u00f4tels & Prestige","labels":{"fr":"H\u00f4tels & Prestige"},"types":["Hotel","Palace","HotelSuite","CastleAndPrestigeMansion"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"H\u00f4tels de Prestige & Palais Luxueux | S\u00e9jours Haut de Gamme\",\"en\":\"Luxury Hotels & Palace Stays | Premium Accommodation\"}","seo_description":"{\"fr\":\"D\u00e9couvrez nos h\u00f4tels et palais de prestige pour un s\u00e9jour d'exception. Suites de luxe, spas, services concierge 5 \u00e9toiles. R\u00e9servez votre nuit de r\u00eave.\",\"en\":\"Explore luxury hotels and palace accommodations for exceptional stays. Premium suites, world-class spas, and concierge services. Book your dream night.\"}","seo_intro":"{\"fr\":\"<h2>H\u00f4tels de Prestige & Palais : L'Incarnation du Luxe Absolu<\/h2><p>S\u00e9journer dans un h\u00f4tel de prestige n'est pas simplement une question d'h\u00e9bergement ; c'est une exp\u00e9rience de vie, un voyage dans l'univers du luxe et de l'excellence. Que vous recherchiez une escapade romantique, une c\u00e9l\u00e9bration exceptionnelle ou un s\u00e9jour professionnel m\u00e9morable, nos s\u00e9lections de palais et h\u00f4tels haut de gamme incarnent le summum du raffinement fran\u00e7ais et international.<\/p><h3>L'Excellence Architecturale et Historique<\/h3><p>Nos palais et ch\u00e2teaux reconvertis en h\u00f4tels de prestige offrent bien plus qu'un simple toit : ils racontent l'histoire de la grandeur fran\u00e7aise. Fa\u00e7ades majestueuses du XVIIIe si\u00e8cle, salons aux d\u00e9cors originaux, escaliers monumentaux et jardins \u00e0 la fran\u00e7aise : chaque d\u00e9tail a \u00e9t\u00e9 pr\u00e9serv\u00e9 pour offrir une authentique immersion dans le patrimoine. Ces demeure d'exception combinent l'h\u00e9ritage historique avec les commodit\u00e9s modernes, cr\u00e9ant une atmosph\u00e8re intemporelle o\u00f9 le pass\u00e9 dialoguerait avec le pr\u00e9sent.<\/p><h3>Suites Royales et Prestations de Luxe Incomparable<\/h3><p>Les suites de nos \u00e9tablissements de prestige ne sont pas de simples chambres, mais des sanctuaires priv\u00e9s meubl\u00e9s d'antiquit\u00e9s, de tissus nobles et d'\u00e9quipements haute technologie discrets. Lit \u00e0 baldaquin, salles de marbre blanc, baignoires creus\u00e9es dans la pierre : chaque \u00e9l\u00e9ment est pens\u00e9 pour le bien-\u00eatre absolu. Les services incluent le turndown service, le butler personnalis\u00e9, le service d'\u00e9tage 24h\/24, et souvent un acc\u00e8s \u00e0 des spas avec soins de marques prestigieuses comme Clarins ou Guerlain.<\/p><h3>Gastronomie \u00c9toil\u00e9e et Exp\u00e9riences Culinaires<\/h3><p>Les restaurants de nos h\u00f4tels de prestige sont dirig\u00e9s par des chefs de renomm\u00e9e mondiale, souvent d\u00e9cor\u00e9s d'\u00e9toiles Michelin. De la gastronomie fran\u00e7aise traditionnelle aux cr\u00e9ations fusion contemporaines, chaque repas devient un \u00e9v\u00e9nement. Les cave \u00e0 vins proposent des mill\u00e9simes rares, et les sommeliers offrent un service d'expertise incomparable. Les petits-d\u00e9jeuners gourmands, les d\u00e9jeuners raffin\u00e9s et les d\u00eeners gastronomiques constituent l'apoth\u00e9ose du s\u00e9jour.<\/p><h3>Spas et Wellness de Classe Mondiale<\/h3><p>Au c\u0153ur de ces palais, les spas repr\u00e9sentent des oasis de d\u00e9tente absolue. Piscines chauff\u00e9es, hammams, saunas, jacuzzis et salles de soin priv\u00e9es proposent des rituels de beaut\u00e9 et de bien-\u00eatre issus des traditions les plus anciennes combin\u00e9es aux techniques les plus innovantes. Massoth\u00e9rapeutes internationaux, soins personnalis\u00e9s et programmes d\u00e9tox compl\u00e8tent l'offre wellness.<\/p><h3>Services Concierge et Exp\u00e9riences Personnalis\u00e9es<\/h3><p>Un concierge de haut niveau se tient \u00e0 votre disposition pour organiser chaque d\u00e9tail : r\u00e9servations au restaurant \u00e9toil\u00e9 convoit\u00e9, arrangements de transport en voiture priv\u00e9e, organisation d'excursions priv\u00e9es, acc\u00e8s \u00e0 des \u00e9v\u00e9nements exclusifs. Chaque demande, m\u00eame la plus insolite, est trait\u00e9e avec discr\u00e9tion et efficacit\u00e9.<\/p><p>Choisir un h\u00f4tel de prestige, c'est opter pour une exp\u00e9rience o\u00f9 chaque instant devient souvenir d'excellence.\",\"en\":\"<h2>Luxury Hotels & Palaces: The Ultimate Expression of Opulence<\/h2><p>Staying at a luxury hotel transcends mere accommodation; it is a lifestyle experience, a journey into the realm of refinement and excellence. Whether seeking a romantic escape, celebrating a milestone, or attending an exclusive event, our curated selection of palaces and five-star hotels represents the pinnacle of French and international luxury.<\/p><h3>Architectural Grandeur and Historic Heritage<\/h3><p>Our palatial estates and historic ch\u00e2teaux converted into luxury hotels offer far more than shelter\u2014they narrate the story of French grandeur. 18th-century fa\u00e7ades, original period salons, monumental staircases, and manicured gardens: every detail preserves authenticity while embracing modern convenience. These exceptional residences fuse historical legacy with contemporary amenities, creating a timeless atmosphere where past and present dialogue seamlessly.<\/p><h3>Royal Suites and Uncompromising Luxury<\/h3><p>The suites in our prestige establishments are private sanctuaries, furnished with antiques, noble textiles, and discreetly integrated technology. Four-poster beds, marble bathrooms, stone-carved bathtubs: every element prioritizes absolute well-being. Services include personalized turndown, dedicated butler service, 24-hour room service, and access to spas featuring renowned brands such as Clarins or Guerlain.<\/p><h3>Michelin-Starred Dining Experiences<\/h3><p>Our hotel restaurants are helmed by world-renowned chefs, often bearing Michelin stars. From classical French gastronomy to contemporary fusion cuisine, every meal becomes an event. Prestigious wine cellars and expert sommeliers provide unparalleled service. Gourmet breakfasts, refined lunches, and gastronomic dinners epitomize the stay.<\/p><h3>World-Class Spas and Wellness Retreats<\/h3><p>Within these palaces, spas serve as sanctuaries of absolute serenity. Heated pools, hammams, saunas, jacuzzis, and private treatment rooms offer beauty and wellness rituals combining ancient traditions with cutting-edge techniques. International massage therapists and personalized treatments complete the wellness spectrum.<\/p><h3>Concierge Excellence and Personalized Experiences<\/h3><p>A world-class concierge team attends to your every wish: securing reservations at coveted Michelin-starred restaurants, arranging private transportation, organizing exclusive excursions, accessing rare events. Every request, however unique, is handled with discretion and expertise.<\/p><p>Selecting a luxury hotel means choosing an experience where every moment becomes an unforgettable memory of excellence.\"}","group_id":1,"group_ids":[1]},"sortir-pluie":{"icon":"fa-solid fa-cloud-showers-heavy","label":"Pluie","labels":{"fr":"Pluie"},"types":["Cinema","Museum","Spa","Bowling","Aquarium"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Que faire quand il pleut\"}","seo_description":"{\"fr\":\"Activit\u00e9s \u00e0 l abri.\"}","seo_intro":"{\"fr\":\"Restez au sec.\"}","group_id":9,"group_ids":[9]},"parcs-jardins":{"icon":"fa-solid fa-leaf","label":"Parcs & Jardins","labels":{"fr":"Parcs & Jardins"},"types":["NaturalPark","Forest","ParkAndGarden","OutstandingTree"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Parcs Naturels, For\u00eats et Jardins : \u00c9vasion au Vert\",\"en\":\"Natural Parks, Forests & Gardens: Green Escapes\"}","seo_description":"{\"fr\":\"Besoin de nature ? Explorez nos parcs naturels r\u00e9gionaux, for\u00eats domaniales et jardins botaniques.\",\"en\":\"Need nature? Explore our regional natural parks, state forests, and botanical gardens.\"}","seo_intro":"{\"fr\":\"<h2>La Nature en Majest\u00e9 : Parcs, For\u00eats et Jardins<\/h2><p>Le territoire offre une biodiversit\u00e9 exceptionnelle que vous pouvez d\u00e9couvrir \u00e0 travers ses <strong>parcs naturels r\u00e9gionaux<\/strong> et ses vastes <strong>for\u00eats<\/strong>. Que vous soyez un randonneur chevronn\u00e9 \u00e0 la recherche de sentiers bois\u00e9s ou un amateur de botanique, ces espaces sont des poumons verts indispensables pour se ressourcer loin du tumulte urbain.<\/p><h3>Jardins Remarquables et Biodiversit\u00e9<\/h3><p>Les <strong>jardins botaniques<\/strong> et parcs paysagers sont des havres de paix o\u00f9 l\u2019on peut admirer des essences rares et des compositions florales saisonni\u00e8res. La for\u00eat, quant \u00e0 elle, invite \u00e0 l\u2019observation de la faune sauvage et \u00e0 la pratique de la sylvoth\u00e9rapie. En parcourant ces sites, vous participez \u00e0 la pr\u00e9servation d\u2019\u00e9cosyst\u00e8mes fragiles. Respectez les sentiers balis\u00e9s et laissez-vous porter par le chant des oiseaux et le murmure du vent dans les feuilles.<\/p>\",\"en\":\"<h2>Nature in Majesty: Parks, Forests, and Gardens<\/h2><p>The territory offers exceptional biodiversity through its <strong>regional natural parks<\/strong> and vast <strong>forests<\/strong>. Whether a hiker or a botany enthusiast, these green lungs are essential for recharging.<\/p><h3>Remarkable Gardens and Biodiversity<\/h3><p><strong>Botanical gardens<\/strong> are havens of peace for admiring rare species. Forests invite wildlife observation and forest bathing. By visiting these sites, you help preserve fragile ecosystems.<\/p>\"}","group_id":4,"group_ids":[4]},"plages-clubs":{"icon":"fa-solid fa-umbrella-beach","label":"Plages","labels":{"fr":"Plages"},"types":["Beach","BeachClub"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Plages\"}","seo_description":"{\"fr\":\"D\u00e9tente au bord de l eau.\"}","seo_intro":"{\"fr\":\"Sable et soleil.\"}","group_id":7,"group_ids":[7]},"restaurants-tables":{"icon":"fa-solid fa-utensils","label":"Restaurants","labels":{"fr":"Restaurants"},"types":["Restaurant","GourmetRestaurant","BistroOrWineBar"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Restaurants & Tables Gourmandes | Gastronomie Authentique\",\"en\":\"Restaurants & Gourmet Tables | Authentic Gastronomy\"}","seo_description":"{\"fr\":\"D\u00e9couvrez nos restaurants et tables gourmandes. Cuisine raffin\u00e9e, chefs talentueux, ambiances \u00e9l\u00e9gantes. R\u00e9servez votre d\u00eener d'exception.\",\"en\":\"Explore our restaurants and gourmet tables. Refined cuisine, talented chefs, elegant settings. Reserve your exceptional dining.\"}","seo_intro":"{\"fr\":\"<h2>Restaurants & Tables Gourmandes : l'Art de Vivre \u00e0 Table<\/h2><p>La gastronomie fran\u00e7aise repr\u00e9sente bien plus qu'une simple satisfaction des besoins nutritionnels : elle incarne une philosophie de vie, une c\u00e9l\u00e9bration des saveurs, et une transmission de patrimoine culinaire s\u00e9culaire. Nos restaurants et tables gourmandes s\u00e9lectionn\u00e9es proposent loin des cuisines uniformis\u00e9es de la restauration rapide, des exp\u00e9riences authentiques o\u00f9 chaque plat raconte histoire du territoire, o\u00f9 chaque saveur r\u00e9v\u00e8le passion du chef, et o\u00f9 atmosph\u00e8re devient complice de votre moment.<\/p><h3>Cuisines R\u00e9gionales Authentiques & Terroir<\/h3><p>Chaque r\u00e9gion fran\u00e7aise poss\u00e8de identit\u00e9 culinaire distincte, fruit de l'histoire, du climat, et des ressources locales. Nos restaurants mettent \u00e0 l'honneur ces traditions : cuisine bourguignonne avec ses vins prestigieux et pi\u00e8ces viande brais\u00e9es, gastronomie proven\u00e7ale explosant d'herbes aromatiques et d'huile d'olive dor\u00e9e. Les chefs que nous s\u00e9lectionnons n'imitent pas les traditions ; ils les v\u00e9n\u00e8rent, les comprennent, et les r\u00e9interpr\u00e8tent avec respect et cr\u00e9ativit\u00e9.<\/p><h3>Ingr\u00e9dients d'Exception & Circuits Courts<\/h3><p>La qualit\u00e9 gastronomique repose sur qualit\u00e9 des mati\u00e8res premi\u00e8res. Nos restaurants privil\u00e9gient circuits courts : producteurs locaux, agriculteurs biologiques, p\u00eacheries durables, artisans fromagers. Viandes s\u00e9lectionn\u00e9es pour tendret\u00e9 et saveur, poissons frais du march\u00e9 du matin, l\u00e9gumes de saison cueillis \u00e0 proximit\u00e9 : cette exigence garantit fra\u00eecheur incomparable.<\/p><h3>Chefs Talentueux & Cr\u00e9ativit\u00e9 Ma\u00eetris\u00e9e<\/h3><p>Derri\u00e8re chaque grand restaurant se trouvent chefs ayant g\u00e9n\u00e9ralement pass\u00e9 apprentissages chez les ma\u00eetres, travaill\u00e9 dans cuisines prestigieuses, et d\u00e9velopp\u00e9 signature personnelle. Leur cr\u00e9ativit\u00e9 ne signifie pas destruction des classiques, mais leur r\u00e9interpr\u00e9tation intelligente. \u00c9toiles Michelin et reconnaissance pairs t\u00e9moignent de leur excellence.<\/p><h3>Ambiances \u00c9l\u00e9gantes & Services Impeccables<\/h3><p>L'exp\u00e9rience gastronomique transcende nourriture seule. D\u00e9coration soign\u00e9e refl\u00e9tant l'identit\u00e9 du restaurant, \u00e9clairage tamis\u00e9 cr\u00e9ant intimit\u00e9, nappes blanches exigeant respect, et service attentif sans \u00eatre envahissant : chaque d\u00e9tail contribue \u00e0 orchestration parfaite. Sommeliers experts proposent accords vins guidant voyage gustatif.<\/p><p>Choisir un restaurant c'est investir dans moment de pur plaisir, o\u00f9 l'art culinaire c\u00e9l\u00e8bre ce que la vie offre de plus beau : la convivialit\u00e9.\",\"en\":\"<h2>Restaurants & Gourmet Tables: The Art of Living at Table<\/h2><p>French gastronomy represents far more than nutritional satisfaction: it embodies a lifestyle philosophy, celebration of flavors, and transmission of centuries-old culinary heritage. Our selected restaurants and gourmet tables offer experiences far removed from standardized fast-food cuisines\u2014authentic experiences where every dish narrates territorial history, every flavor reveals the chef's passion, and atmosphere becomes your moment's accomplice.<\/p><h3>Authentic Regional Cuisines & Terroir<\/h3><p>Each French region possesses distinct culinary identity, fruit of history, climate, and local resources. Our restaurants honor these traditions: Burgundian cuisine with prestigious wines and braised meats, Proven\u00e7al gastronomy exploding with aromatic herbs and golden olive oil. The chefs we select don't imitate traditions; they revere, understand, and reinterpret them with respect and creativity.<\/p><h3>Exceptional Ingredients & Short Supply Chains<\/h3><p>Gastronomic quality rests on ingredient quality. Our restaurants prioritize short supply chains: local producers, organic farmers, sustainable fisheries, artisanal cheese makers. Meats selected for tenderness and flavor, fresh morning market fish, seasonally harvested nearby vegetables: this commitment guarantees incomparable freshness.<\/p><h3>Talented Chefs & Controlled Creativity<\/h3><p>Behind every great restaurant stand chefs typically having apprenticed with masters, worked in prestigious kitchens, and developed personal signature. Their creativity doesn't mean destroying classics, but intelligently reinterpreting them. Michelin stars and peer recognition witness their excellence.<\/p><h3>Elegant Ambiances & Impeccable Service<\/h3><p>The gastronomic experience transcends food alone. Thoughtful d\u00e9cor reflecting restaurant identity, soft lighting creating intimacy, white tablecloths demanding respect, and attentive yet unobtrusive service: every detail orchestrates perfection. Expert sommeliers propose wine pairings guiding gustatory journeys.<\/p><p>Choosing a restaurant means investing in pure pleasure moment, where culinary art celebrates life's finest offering: conviviality.\"}","group_id":2,"group_ids":[2]},"ski-sports-hiver":{"icon":"fa-solid fa-snowflake","label":"Ski & Hiver","labels":{"fr":"Ski & Hiver"},"types":["CrossCountrySkiResort","DownhillSkiRun","TobogganBobsleigh"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Ski & Hiver\"}","seo_description":"{\"fr\":\"Joies de la neige.\"}","seo_intro":"{\"fr\":\"Glisse.\"}","group_id":8,"group_ids":[4,8]},"brasseries-cafes":{"icon":"fa-solid fa-mug-hot","label":"Brasseries & Caf\u00e9s","labels":{"fr":"Brasseries & Caf\u00e9s"},"types":["BrasserieOrTavern","CafeOrCoffeeShop","FastFood"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Brasseries, Caf\u00e9s & Cuisine Rapide | Pause Gourmande\",\"en\":\"Brasseries, Cafes & Fast Food | Gourmet Break\"}","seo_description":"{\"fr\":\"D\u00e9couvrez nos brasseries et caf\u00e9s conviviaux. Cuisine savoureuse, ambiance d\u00e9contract\u00e9e, service rapide. Pause gourmande parfaite.\",\"en\":\"Explore our friendly brasseries and cafes. Tasty cuisine, relaxed atmosphere, quick service. Perfect gourmet break.\"}","seo_intro":"{\"fr\":\"<h2>Brasseries & Caf\u00e9s : C\u0153ur Social de la Vie Quotidienne<\/h2><p>Les brasseries et caf\u00e9s incarnent l'\u00e2me des villes et villages fran\u00e7ais : lieux de vie sociale o\u00f9 rituel du caf\u00e9 matinal se transforme en moment de connexion humaine. Au-del\u00e0 de simple restauration rapide, ces \u00e9tablissements perp\u00e9tuent traditions fran\u00e7aises de fl\u00e2nerie consciente, de libert\u00e9 de rester assis des heures avec consommation minimum, et de proximit\u00e9 humaine authentique.<\/p><h3>Caf\u00e9s : Lieux de Rituel & de Convivialit\u00e9<\/h3><p>Le caf\u00e9 fran\u00e7ais n'est pas simple boisson, mais moment : celui du r\u00e9veil en siroter un espresso serr\u00e9, celui de la pause professionnelle autour d'un cr\u00e8me, celui de l'apr\u00e8s-midi en se posant terrasse pour regarder passer monde. Les caf\u00e9s que nous recommandons offrent excellente qualit\u00e9 caf\u00e9i\u00e8re, petits pains frais, croissants beurr\u00e9s artisanaux. Baristas comp\u00e9tents pr\u00e9parent boissons avec soin. Mobilier accueillant, atmosph\u00e8re d\u00e9contract\u00e9e, et personnel amical transforment visite simple en moment apais\u00e9.<\/p><h3>Brasseries : Cuisine G\u00e9n\u00e9reuse & Service Efficace<\/h3><p>Les brasseries repr\u00e9sentent niveau sup\u00e9rieur : restauration rapide sans renoncer qualit\u00e9 gastronomique. Proposant menu vari\u00e9 matin, midi, soir, ces \u00e9tablissements satisfont app\u00e9tits tous niveaux. Omelettes copieuses, steaks frites croustillants, poissons grill\u00e9s savoureux, salades compos\u00e9es g\u00e9n\u00e9reuses : chaque plat respecte standards qualit\u00e9 tout en permettant consommation rapide.<\/p><h3>Terrasses : Extension Naturelle & Art de Vivre<\/h3><p>Caract\u00e9ristique distinctive fran\u00e7aise : la terrasse de caf\u00e9. En saison, ces extensions en plein air deviennent c\u0153ur battant de sociabilit\u00e9. Assis terrasse, observant vie urbaine, on retrouve caract\u00e8re authentique fran\u00e7ais disparu ailleurs. Terrasses hiver, chauff\u00e9es lampadaires modernes, transforment rigueur climatique en confort cosy.<\/p><h3>Cuisine Rapide : Qualit\u00e9 sans Compromis<\/h3><p>Nos \u00e9tablissements proposent cuisine rapide respectant qualit\u00e9. Sandwichs garnis g\u00e9n\u00e9reusement, cr\u00eapes pr\u00e9par\u00e9es \u00e0 commande, burgers faits maison, pizzas napolitaines cuites au feu de bois : rapidit\u00e9 service n'implique sacrifice quality.<\/p><p>Choisir brasserie ou caf\u00e9, c'est participer \u00e0 tradition fran\u00e7aise vivante o\u00f9 pauses consommation deviennent rituel social.\",\"en\":\"<h2>Brasseries & Cafes: Heart of Daily Social Life<\/h2><p>Brasseries and cafes embody the soul of French towns and villages: social spaces where morning coffee ritual transforms into human connection. Beyond simple fast food, these establishments perpetuate French traditions of conscious wandering, freedom to sit hours with minimal purchase, and authentic human proximity.<\/p><h3>Cafes: Places of Ritual & Conviviality<\/h3><p>French coffee isn't simply beverage, but moment: morning awakening sipping tight espresso, work break around a caf\u00e9 cr\u00e8me, afternoon pause sitting terraces watching world pass. The cafes we recommend offer excellent coffee quality, fresh rolls, artisanal buttered croissants. Competent baristas prepare drinks with care. Welcoming furniture, relaxed atmosphere, and friendly staff transform simple visits into peaceful moments.<\/p><h3>Brasseries: Generous Cuisine & Efficient Service<\/h3><p>Brasseries represent the next level: quick service without sacrificing gastronomic quality. Offering varied menus morning, noon, evening, these establishments satisfy all appetites. Hearty omelets, crispy steak-fries, flavorful grilled fish, generous composed salads: every dish respects quality standards while enabling quick consumption.<\/p><h3>Terraces: Natural Extension & Art of Living<\/h3><p>Distinctive French characteristic: the cafe terrace. In season, these outdoor extensions become sociability's beating heart. Seated terrace-side, observing urban life, one retrieves authentic French character disappeared elsewhere. Winter terraces, heated by modern lamps, transform climate rigor into cozy comfort.<\/p><h3>Quick Cuisine: Quality Without Compromise<\/h3><p>Our establishments offer quick cuisine respecting quality. Generously filled sandwiches, made-to-order crepes, homemade burgers, wood-fired Neapolitan pizzas: service speed doesn't imply quality sacrifice.<\/p><p>Choosing a brasserie or cafe means participating in living French tradition where consumption pauses become social ritual.\"}","group_id":2,"group_ids":[2]},"detente-fitness":{"icon":"fa-solid fa-person-running","label":"D\u00e9tente & Sport","labels":{"fr":"D\u00e9tente & Sport"},"types":["Hammam","FitnessCenter","SwimmingPool"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Services Utiles, Sant\u00e9 et Informations Pratiques\",\"en\":\"Useful Services, Health & Practical Information\"}","seo_description":"{\"fr\":\"Toutes les infos pratiques pour votre s\u00e9jour : num\u00e9ros d'urgence, sant\u00e9, banques et services publics.\",\"en\":\"All practical info for your stay: emergency numbers, health, banks, and public services.\"}","seo_intro":"{\"fr\":\"<h2>Services et Informations Pratiques : Voyagez l\u2019Esprit L\u00e9ger<\/h2><p>Pour que vos vacances restent un moment de d\u00e9tente absolue, il est essentiel d\u2019avoir acc\u00e8s rapidement aux <strong>services de proximit\u00e9<\/strong> et aux informations de sant\u00e9. Cette cat\u00e9gorie regroupe tout ce dont vous pourriez avoir besoin pour g\u00e9rer le quotidien ou faire face \u00e0 un impr\u00e9vu. Un voyageur bien inform\u00e9 est un voyageur serein.<\/p><h3>Sant\u00e9, Urgences et Bien-\u00eatre<\/h3><p>En cas de besoin m\u00e9dical, nous r\u00e9pertorions les <strong>pharmacies de garde<\/strong>, les centres m\u00e9dicaux, les h\u00f4pitaux et les cabinets de sant\u00e9 (m\u00e9decins g\u00e9n\u00e9ralistes, dentistes, infirmiers). Il est rassurant de savoir o\u00f9 se trouve le centre de soins le plus proche. N\u2019oubliez pas de garder \u00e0 port\u00e9e de main les num\u00e9ros d\u2019urgence nationaux. Pour les petits bobos ou les besoins courants, nos commerces de sant\u00e9 sont l\u00e0 pour vous conseiller avec professionnalisme.<\/p><h3>Services Bancaires et Administratifs<\/h3><p>Vous trouverez \u00e9galement ici les emplacements des <strong>distributeurs automatiques de billets (DAB)<\/strong>, les bureaux de change et les agences bancaires. Pour vos besoins postaux (envoi de cartes postales, colis), les bureaux de poste et points relais sont \u00e0 votre disposition. Enfin, pour toute question sp\u00e9cifique, les accueils de mairie et les services publics locaux peuvent vous renseigner sur la r\u00e9glementation (stationnement, gestion des d\u00e9chets, zones de baignade). Anticiper ces d\u00e9tails logistiques vous permet de profiter pleinement de chaque instant de votre s\u00e9jour.<\/p>\",\"en\":\"<h2>Services and Practical Information: Travel Light<\/h2><p>To keep your vacation stress-free, access to <strong>local services<\/strong> and health information is essential. This category includes everything you might need for daily management or emergencies.<\/p><h3>Health, Emergencies, and Wellness<\/h3><p>In case of medical needs, we list <strong>on-call pharmacies<\/strong>, medical centers, and hospitals. It is reassuring to know the location of the nearest healthcare facility. Keep national emergency numbers handy.<\/p><h3>Banking and Administrative Services<\/h3><p>You will also find <strong>ATMs<\/strong>, currency exchange offices, and bank branches here. For postal needs, post offices and relay points are available. Finally, local public services can provide information on regulations like parking or waste management.<\/p>\"}","group_id":6,"group_ids":[6]},"edifices-religieux":{"icon":"fa-solid fa-church","label":"Patrimoine religieux","labels":{"fr":"Patrimoine religieux"},"types":["Abbey","Church","Cathedral","Chapel","Cloister","Monastery"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Monuments Historiques, Ch\u00e2teaux et Patrimoine Class\u00e9\",\"en\":\"Historical Monuments, Castles & Heritage Sites\"}","seo_description":"{\"fr\":\"D\u00e9couvrez les joyaux de notre patrimoine : ch\u00e2teaux m\u00e9di\u00e9vaux, abbayes, cath\u00e9drales et monuments class\u00e9s.\",\"en\":\"Discover the jewels of our heritage: medieval castles, abbeys, cathedrals, and listed monuments.\"}","seo_intro":"{\"fr\":\"<h2>Monuments et Ch\u00e2teaux : Les T\u00e9moins de l\u2019Histoire<\/h2><p>Le patrimoine b\u00e2ti est le livre ouvert de notre pass\u00e9. Les <strong>ch\u00e2teaux, abbayes et monuments historiques<\/strong> qui jalonnent nos paysages sont autant de t\u00e9moignages de la grandeur architecturale et des p\u00e9rip\u00e9ties historiques de notre r\u00e9gion. Chaque pierre, chaque donjon et chaque vitrail a une histoire \u00e0 raconter \u00e0 ceux qui prennent le temps de les observer.<\/p><h3>La vie de ch\u00e2teau, du Moyen-\u00c2ge \u00e0 la Renaissance<\/h3><p>Partez \u00e0 l\u2019assaut des <strong>ch\u00e2teaux forts<\/strong> m\u00e9di\u00e9vaux avec leurs remparts imposants et leurs douves profondes. Ces forteresses racontent une \u00e9poque de chevalerie et de d\u00e9fense territoriale. \u00c0 l\u2019oppos\u00e9, les ch\u00e2teaux de la Renaissance, avec leurs jardins \u00e0 la fran\u00e7aise et leurs fa\u00e7ades richement orn\u00e9es, t\u00e9moignent d\u2019un art de vivre raffin\u00e9. Les visites guid\u00e9es vous permettent souvent d\u2019acc\u00e9der \u00e0 des salles priv\u00e9es, des cuisines d\u2019\u00e9poque ou des biblioth\u00e8ques cach\u00e9es, offrant une immersion totale dans le quotidien des anciens seigneurs.<\/p><h3>Patrimoine religieux et architecture civile<\/h3><p>Le patrimoine, c\u2019est aussi la majest\u00e9 des <strong>cath\u00e9drales gothiques<\/strong>, le calme des clo\u00eetres romans et l\u2019\u00e9l\u00e9gance des h\u00f4tels particuliers en centre-ville. Ces monuments ne sont pas seulement des lieux de m\u00e9moire, ce sont des chefs-d\u2019\u0153uvre d\u2019ing\u00e9nierie et d\u2019artisanat. Les vitraux, les charpentes et les sculptures de fa\u00e7ade r\u00e9v\u00e8lent le g\u00e9nie des b\u00e2tisseurs de jadis. Ne manquez pas non plus le patrimoine industriel et les petits monuments ruraux (lavoirs, fontaines, moulins) qui font tout le charme de nos campagnes.<\/p><h3>Pr\u00e9server pour l\u2019avenir<\/h3><p>En visitant ces sites, souvent class\u00e9s aux <strong>Monuments Historiques<\/strong> ou \u00e0 l\u2019UNESCO, vous contribuez \u00e0 leur restauration et \u00e0 leur p\u00e9rennit\u00e9. De nombreux monuments proposent aujourd\u2019hui des exp\u00e9riences immersives : spectacles de fauconnerie, visites nocturnes aux flambeaux ou escape games historiques. C\u2019est une mani\u00e8re ludique et vivante de red\u00e9couvrir notre h\u00e9ritage commun.<\/p>\",\"en\":\"<h2>Monuments and Castles: Witnesses of History<\/h2><p>Our built heritage is an open book to the past. The <strong>castles, abbeys, and historical monuments<\/strong> scattered across our landscapes testify to the architectural grandeur and history of our region.<\/p><h3>Castle Life from the Middle Ages to the Renaissance<\/h3><p>Storm the medieval <strong>fortresses<\/strong> with their imposing ramparts or explore Renaissance castles with their French-style gardens. Guided tours often provide access to private rooms and historic kitchens, offering a total immersion into the lives of lords of the past.<\/p><h3>Religious and Civil Architecture<\/h3><p>Heritage also includes the majesty of <strong>Gothic cathedrals<\/strong>, the calm of Romanesque cloisters, and the elegance of city mansions. These sites are masterpieces of engineering and craftsmanship. By visiting these UNESCO or listed sites, you contribute to their preservation.<\/p>\"}","group_id":3,"group_ids":[3]},"transport-mobilite":{"icon":"fa-solid fa-train-subway","label":"Transports","labels":{"fr":"Transports"},"types":["TrainStation","Airport","BusStation","TaxiStation","CarpoolArea"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Transports\"}","seo_description":"{\"fr\":\"Venir et bouger.\"}","seo_intro":"{\"fr\":\"En route.\"}","group_id":10,"group_ids":[10]},"eau-nature":{"icon":"fa-solid fa-droplet","label":"Eau & Nature","labels":{"fr":"Eau & Nature"},"types":["Lake","River","Waterfall","Stream","Pond"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Lacs, Rivi\u00e8res et Cascades : Les Plus Beaux Sites Aquatiques\",\"en\":\"Lakes, Rivers & Waterfalls: Beautiful Aquatic Sites\"}","seo_description":"{\"fr\":\"D\u00e9couvrez la fra\u00eecheur de nos lacs, rivi\u00e8res et cascades. Id\u00e9al pour la baignade, la p\u00eache et la d\u00e9tente.\",\"en\":\"Discover the freshness of our lakes, rivers, and waterfalls. Perfect for swimming, fishing, and relaxing.\"}","seo_intro":"{\"fr\":\"<h2>L\u2019Eau dans tous ses \u00e9tats : Fra\u00eecheur et S\u00e9r\u00e9nit\u00e9<\/h2><p>Rien n\u2019est plus apaisant que le bruit de l\u2019eau. Nos <strong>lacs et rivi\u00e8res<\/strong> sont des destinations privil\u00e9gi\u00e9es pour les journ\u00e9es d\u2019\u00e9t\u00e9. Que ce soit pour une baignade rafra\u00eechissante, une partie de p\u00eache ou une balade contemplative sur les berges, les sites aquatiques du territoire offrent des paysages vari\u00e9s, de la cascade bouillonnante au lac de montagne miroitant.<\/p><h3>Activit\u00e9s et D\u00e9tente au bord de l\u2019eau<\/h3><p>Profitez des am\u00e9nagements tels que les plages de lac surveill\u00e9es, les pontons de p\u00eache ou les sentiers de randonn\u00e9e qui longent les cours d\u2019eau. Les <strong>cascades<\/strong>, souvent cach\u00e9es au c\u0153ur des for\u00eats, sont des buts de promenade magiques qui r\u00e9compensent l\u2019effort par un spectacle naturel saisissant. L\u2019eau est une ressource pr\u00e9cieuse ; veillez \u00e0 respecter la propret\u00e9 des berges pour pr\u00e9server ces paradis aquatiques.<\/p>\",\"en\":\"<h2>Water in Every Form: Freshness and Serenity<\/h2><p>Nothing is more soothing than the sound of water. Our <strong>lakes and rivers<\/strong> are favorite destinations for summer days, offering everything from refreshing swims to peaceful fishing spots.<\/p><h3>Activities and Relaxation by the Water<\/h3><p>Enjoy facilities such as monitored lake beaches, fishing piers, or hiking trails along the riverbanks. <strong>Waterfalls<\/strong> hidden in forests are magical destinations for nature lovers.<\/p>\"}","group_id":4,"group_ids":[4]},"locations-gites":{"icon":"fa-solid fa-house","label":"Locations & G\u00eetes","labels":{"fr":"Locations & G\u00eetes"},"types":["Apartment","House","Gite","SelfCateringAccommodation"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Locations de Vacances & G\u00eetes Ruraux | S\u00e9jours Authentiques\",\"en\":\"Vacation Rentals & Rural Gites | Authentic Stays\"}","seo_description":"{\"fr\":\"Trouvez votre location de vacances ou g\u00eete id\u00e9al. Maisons de charme, appartements confortables en zone rurale ou urbaine. S\u00e9jour autonome authentique.\",\"en\":\"Find your perfect vacation rental or rural gite. Charming houses and comfortable apartments in countryside or city. Authentic self-catering stays.\"}","seo_intro":"{\"fr\":\"<h2>Locations de Vacances & G\u00eetes : S'Approprier l'\u00c2me d'une R\u00e9gion<\/h2><p>Louer un g\u00eete ou une maison de vacances offre bien plus qu'un simple h\u00e9bergement : c'est l'opportunit\u00e9 de vivre comme un habitant, de d\u00e9couvrir les rythmes authentiques d'une r\u00e9gion et de tisser une v\u00e9ritable connexion avec le territoire. Contrairement aux h\u00f4tels, ces demeures vous permettent d'explorer \u00e0 votre rythme, de cuisiner vos propres repas, de vous impr\u00e9gner de la culture locale et de cr\u00e9er des souvenirs intimes en famille ou entre amis.<\/p><h3>Diversit\u00e9 d'Habitats pour Tous les Go\u00fbts<\/h3><p>Notre catalogue propose une vari\u00e9t\u00e9 incomparable de locations : du g\u00eete rural traditionnel en pierre au c\u0153ur de villages pittoresques, \u00e0 l'appartement urbain dans les quartiers branch\u00e9s des villes, en passant par les maisons de caract\u00e8re avec piscine priv\u00e9e. Chaque logement est s\u00e9lectionn\u00e9 pour son authenticit\u00e9, son confort et sa capacit\u00e9 \u00e0 offrir une exp\u00e9rience m\u00e9morable. Qu'il s'agisse d'une demeure vigneronne en Bourgogne, d'un cottage normand ou d'un loft parisien, vous d\u00e9couvrirez des propri\u00e9t\u00e9s d\u00e9cor\u00e9es avec soin refl\u00e9tant l'\u00e2me locale.<\/p><h3>Autonomie et Flexibilit\u00e9 sans Compromis<\/h3><p>En choisissant une location, vous retrouvez la libert\u00e9 totale. Horaires flexibles, possibilit\u00e9 de cuisiner \u00e0 votre convenance, espace privatif 24h\/24, am\u00e9nagement des lieux selon vos pr\u00e9f\u00e9rences : aucune contrainte h\u00f4teli\u00e8re. Cette autonomie est particuli\u00e8rement appr\u00e9ci\u00e9e des familles avec enfants, des groupes d'amis souhaitant convivialit\u00e9, ou des t\u00e9l\u00e9travailleurs cherchant un espace de travail confortable. Les cuisines \u00e9quip\u00e9es permettent de pr\u00e9parer des repas \u00e0 base de produits locaux, renfor\u00e7ant l'immersion culturelle.<\/p><h3>\u00c9quipements Modernes & Confort Garanti<\/h3><p>Malgr\u00e9 leur charme authentique, nos locations b\u00e9n\u00e9ficient d'\u00e9quipements contemporains essentiels : chauffage performant, cuisine moderne, salle de bain r\u00e9nov\u00e9e, acc\u00e8s WiFi, t\u00e9l\u00e9vision, machines \u00e0 laver. Certaines propri\u00e9t\u00e9s premium proposent m\u00eame piscine int\u00e9rieure, sauna, home cin\u00e9ma ou espace bureautique. La qualit\u00e9 de l'isolation phonique et thermique garantit un confort optimal quelle que soit la saison.<\/p><h3>Immersion Culturelle et D\u00e9couvertes R\u00e9gionales<\/h3><p>S\u00e9journer dans un g\u00eete vous positionne au c\u0153ur des attractions authentiques : march\u00e9s locaux, vignobles, patrimoine architectural m\u00e9connu, festivals r\u00e9gionaux, restaurants de village tenus par des g\u00e9n\u00e9rations de familles. Les propri\u00e9taires, souvent locaux, partagent volontiers leurs meilleures adresses et anecdotes historiques. Cette proximit\u00e9 avec la r\u00e9alit\u00e9 r\u00e9gionale transforme votre s\u00e9jour en v\u00e9ritable voyage d'exploration.<\/p><h3>Rapport Qualit\u00e9-Prix In\u00e9gal\u00e9<\/h3><p>Les locations de vacances offrent un excellent rapport qualit\u00e9-prix, particuli\u00e8rement pour les s\u00e9jours prolong\u00e9s ou les groupes. Les tarifs d\u00e9gressifs pour les semaines ou les mois, l'absence de frais de service, et la possibilit\u00e9 de pr\u00e9parer vos repas permettent des \u00e9conomies substantielles compar\u00e9 aux h\u00f4tels. Vous b\u00e9n\u00e9ficiez ainsi d'un cadre d'exception sans exc\u00e8s de d\u00e9penses.<\/p><p>Choisir une location, c'est opter pour une immersion authentique o\u00f9 chaque moment du s\u00e9jour vous appartient enti\u00e8rement.\",\"en\":\"<h2>Vacation Rentals & Gites: Living Like a Local<\/h2><p>Renting a gite or vacation home offers far more than basic accommodation: it's the opportunity to live as a resident, discover a region's authentic rhythms, and forge a genuine connection with the territory. Unlike hotels, these homes allow you to explore at your own pace, prepare your own meals, absorb local culture, and create intimate memories with family or friends.<\/p><h3>Diverse Accommodations for Every Preference<\/h3><p>Our catalog showcases an incomparable range: from traditional stone gites in picturesque villages to urban apartments in trendy neighborhoods, alongside characterful homes with private pools. Each property is selected for authenticity, comfort, and its capacity to deliver memorable experiences. Whether a Burgundy wine-keeper's house, a Norman cottage, or a Parisian loft, you'll discover thoughtfully decorated properties reflecting local character.<\/p><h3>Complete Autonomy and Flexibility<\/h3><p>Choosing a rental grants total freedom. Flexible schedules, the ability to cook as you wish, private space 24\/7, and personalized arrangements: no hotel constraints. This autonomy appeals especially to families with children, friend groups seeking togetherness, or remote workers needing comfortable workspaces. Well-equipped kitchens enable preparing meals with local ingredients, deepening cultural immersion.<\/p><h3>Modern Amenities & Assured Comfort<\/h3><p>Despite their authentic charm, our rentals feature essential contemporary conveniences: efficient heating, modern kitchens, renovated bathrooms, WiFi access, television, and laundry facilities. Premium properties may offer heated pools, saunas, home cinemas, or dedicated workspaces. Quality soundproofing and insulation ensure optimal comfort regardless of season.<\/p><h3>Cultural Immersion and Regional Exploration<\/h3><p>Staying in a gite positions you within authentic attractions: local markets, vineyards, undiscovered architectural heritage, regional festivals, village restaurants run by generations of families. Local owners gladly share insider recommendations and historical anecdotes. This proximity to regional reality transforms your stay into genuine exploration.<\/p><h3>Unbeatable Value for Money<\/h3><p>Vacation rentals offer exceptional value, especially for extended stays or groups. Sliding-scale pricing for longer rentals, absence of service fees, and the ability to prepare your own meals yield substantial savings compared to hotels. You gain exceptional accommodations without extravagant spending.<\/p><p>Choosing a rental means opting for authentic immersion where every moment of your stay truly belongs to you.\"}","group_id":1,"group_ids":[1]},"ports-marinas":{"icon":"fa-solid fa-anchor","label":"Ports","labels":{"fr":"Ports"},"types":["Marina","Seaport","RiverPort"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Ports\"}","seo_description":"{\"fr\":\"Ambiance portuaire.\"}","seo_intro":"{\"fr\":\"Bateaux.\"}","group_id":7,"group_ids":[7]},"sommets-panoramas":{"icon":"fa-solid fa-mountain","label":"Sommets","labels":{"fr":"Sommets"},"types":["Summit","Peak","Col","Crest","PointOfView"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Sommets\"}","seo_description":"{\"fr\":\"Vues imprenables.\"}","seo_intro":"{\"fr\":\"Prendre de la hauteur.\"}","group_id":8,"group_ids":[4,8]},"spectacles-cinema":{"icon":"fa-solid fa-film","label":"Foires & Shopping","labels":{"fr":"Foires & Shopping"},"types":["TheaterEvent","ShowEvent","Cinema","Opera","Cabaret"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Agences de Voyage et Guides : Confiez votre S\u00e9jour \u00e0 des Experts\",\"en\":\"Travel Agencies & Guides: Expert Planning for Your Stay\"}","seo_description":"{\"fr\":\"Optimisez votre s\u00e9jour avec nos guides et agences : visites guid\u00e9es, circuits sur-mesure et conseils d'experts.\",\"en\":\"Optimize your stay with our guides and agencies: guided tours, tailor-made circuits, and expert advice.\"}","seo_intro":"{\"fr\":\"<h2>Agences et Guides : L\u2019Expertise Locale au Service de vos \u00c9motions<\/h2><p>Partir \u00e0 la d\u00e9couverte d\u2019un territoire est une aventure, mais la vivre aux c\u00f4t\u00e9s d\u2019experts change radicalement l\u2019exp\u00e9rience. Les <strong>agences de voyage locales<\/strong> et les <strong>guides conf\u00e9renciers<\/strong> sont les passerelles indispensables pour acc\u00e9der aux secrets les mieux gard\u00e9s d\u2019une r\u00e9gion. Que vous soyez un voyageur solitaire en qu\u00eate de sens ou un groupe organis\u00e9, faire appel \u00e0 des professionnels garantit un s\u00e9jour fluide, riche et authentique.<\/p><h3>Des circuits sur-mesure et th\u00e9matiques<\/h3><p>Les agences r\u00e9ceptives cr\u00e9ent pour vous des itin\u00e9raires personnalis\u00e9s. Vous r\u00eavez d\u2019un circuit gastronomique, d\u2019une \u00e9pop\u00e9e historique ou d\u2019une randonn\u00e9e hors des sentiers battus ? Elles s\u2019occupent de la logistique, des r\u00e9servations et des transports, vous laissant le seul plaisir de la d\u00e9couverte. Leur connaissance du terrain permet d\u2019\u00e9viter les pi\u00e8ges \u00e0 touristes et de privil\u00e9gier des adresses confidentielles, garantissant un rapport qualit\u00e9-prix optimal.<\/p><h3>La plus-value du guide professionnel<\/h3><p>Rien ne remplace la narration d\u2019un <strong>guide passionn\u00e9<\/strong>. Lors d\u2019une visite guid\u00e9e, les pierres des monuments se mettent \u00e0 parler, les paysages r\u00e9v\u00e8lent leur g\u00e9ologie et les anecdotes historiques redonnent vie au pass\u00e9. Les guides accompagnateurs, sp\u00e9cialistes de la faune, de la flore ou du patrimoine b\u00e2ti, enrichissent votre regard et vous font gagner un temps pr\u00e9cieux. Ils sont aussi les garants de votre s\u00e9curit\u00e9 lors d\u2019activit\u00e9s sp\u00e9cifiques en montagne ou en mer. En choisissant un guide certifi\u00e9, vous soutenez un m\u00e9tier de passion et de transmission culturelle.<\/p>\",\"en\":\"<h2>Travel Agencies and Guides: Local Expertise at Your Service<\/h2><p>Exploring a territory is an adventure, but living it alongside experts changes the experience. <strong>Local travel agencies<\/strong> and <strong>professional guides<\/strong> are essential for accessing the best-kept secrets of a region.<\/p><h3>Tailor-made and Thematic Tours<\/h3><p>Receptive agencies create personalized itineraries for you. Whether you dream of a gourmet tour or a historical epic, they handle the logistics, allowing you to focus on the joy of discovery.<\/p><h3>The Value of a Professional Guide<\/h3><p>Nothing replaces the storytelling of a <strong>passionate guide<\/strong>. During a guided tour, monuments come to life with historical anecdotes. Guides specializing in wildlife or heritage enrich your perspective and ensure your safety during specific activities.<\/p>\"}","group_id":5,"group_ids":[5]},"activites-enfants":{"icon":"fa-solid fa-children","label":"Enfants","labels":{"fr":"Enfants"},"types":["AmusementPark","TeachingFarm","PlayArea","Zoo","MiniGolf"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Activit\u00e9s en Famille : Que faire avec les enfants ?\",\"en\":\"Family Activities: What to do with kids?\"}","seo_description":"{\"fr\":\"D\u00e9couvrez les meilleures sorties famille : parcs d'attractions, fermes p\u00e9dagogiques et aires de jeux.\",\"en\":\"Discover the best family outings: amusement parks, educational farms, and playgrounds.\"}","seo_intro":"{\"fr\":\"<h2>Sorties en Famille : Le Bonheur des Petits et des Grands<\/h2><p>Organiser des vacances avec des enfants demande de l'imagination ! Nous avons s\u00e9lectionn\u00e9 les meilleures <strong>activit\u00e9s famille<\/strong> pour garantir des sourires tout au long du s\u00e9jour. Des parcs de loisirs aux <strong>fermes p\u00e9dagogiques<\/strong>, le territoire est un immense terrain de jeu o\u00f9 l'apprentissage se m\u00eale au divertissement.<\/p><h3>S'amuser et Apprendre ensemble<\/h3><p>Les <strong>parcs d'attractions<\/strong> offrent des sensations pour tous les \u00e2ges, tandis que les mus\u00e9es interactifs permettent d'apprendre l'histoire ou les sciences en s'amusant. Pour un contact direct avec la nature, les fermes p\u00e9dagogiques proposent aux enfants de nourrir les animaux et de d\u00e9couvrir la vie \u00e0 la campagne. N'oubliez pas les aires de jeux et les parcours d'accrobranche pour se d\u00e9penser en toute s\u00e9curit\u00e9.<\/p>\",\"en\":\"<h2>Family Outings: Fun for Kids and Adults<\/h2><p>Organizing a trip with children requires imagination! We have selected the best <strong>family activities<\/strong> to ensure smiles throughout your stay.<\/p><h3>Play and Learn Together<\/h3><p><strong>Amusement parks<\/strong> offer thrills for all ages, while interactive museums make learning fun. Educational farms allow children to meet animals and discover countryside life.<\/p>\"}","group_id":9,"group_ids":[9]},"chambres-hotes":{"icon":"fa-solid fa-bed","label":"Chambres d\u2019H\u00f4tes","labels":{"fr":"Chambres d\u2019H\u00f4tes"},"types":["BedAndBreakfast","TableHoteGuesthouse"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Chambres d'H\u00f4tes & Tables d'H\u00f4tes | Accueil Convivial\",\"en\":\"Bed & Breakfast & Guest Tables | Warm Hospitality\"}","seo_description":"{\"fr\":\"D\u00e9couvrez nos chambres d'h\u00f4tes charmantes. Accueil chaleureux, petit-d\u00e9jeuner fait maison, tables d'h\u00f4tes authentiques. S\u00e9jours intimistes en famille.\",\"en\":\"Explore charming bed & breakfast accommodations. Warm welcomes, homemade breakfasts, authentic guest tables. Intimate stays with local hosts.\"}","seo_intro":"{\"fr\":\"<h2>Chambres d'H\u00f4tes & Tables d'H\u00f4tes : l'Essence de l'Hospitalit\u00e9 Fran\u00e7aise<\/h2><p>Les chambres d'h\u00f4tes incarnent la tradition fran\u00e7aise d'accueil chaleureux et sinc\u00e8re. Bien au-del\u00e0 d'un simple g\u00eete, elles offrent une exp\u00e9rience d'\u00e9change humain v\u00e9ritable o\u00f9 l'h\u00f4te devient ami, o\u00f9 l'habitation devient foyer temporaire, et o\u00f9 chaque d\u00e9tail r\u00e9v\u00e8le l'amour du terroir. Cette formule incontournable de tourisme rural fran\u00e7ais permet une immersion totale dans l'authenticit\u00e9 locale, loin du froid standardis\u00e9 des grandes cha\u00eenes h\u00f4teli\u00e8res.<\/p><h3>Un Accueil Personnel et Authentique<\/h3><p>Contrairement aux h\u00f4tels o\u00f9 vous \u00eates un num\u00e9ro, dans une chambre d'h\u00f4tes vous \u00eates un invit\u00e9. L'h\u00f4te prend le temps de faire connaissance, partage ses recommandations personnelles, ses secrets locaux, ses anecdotes sur la r\u00e9gion. Cet accueil bienveillant cr\u00e9e une ambiance incontournable : conversations au coin du feu, conseils avis\u00e9s sur les meilleures tables, indications sur les sentiers de randonn\u00e9e cach\u00e9s. La chaleur humaine demeure au c\u0153ur de cette exp\u00e9rience unique.<\/p><h3>Petits-D\u00e9jeuners Gourmands & Produits Locaux<\/h3><p>Le petit-d\u00e9jeuner inclus n'est pas une simple formalit\u00e9, mais une v\u00e9ritable c\u00e9l\u00e9bration des saveurs r\u00e9gionales. Pains et viennoiseries du boulanger local, confitures faites maison, miel de l'apiculteur du village, fromages r\u00e9gionaux, charcuteries artisanales : chaque morceau raconte l'histoire du territoire. Certaines propri\u00e9taires font elles-m\u00eames leurs p\u00e2tisseries, leurs confitures et leurs yaourts. Ce petit-d\u00e9jeuner g\u00e9n\u00e9reux offre bien plus qu'une simple nutrition : c'est une introduction savoureuse aux richesses gastronomiques locales.<\/p><h3>Tables d'H\u00f4tes : Repas en Famille<\/h3><p>La table d'h\u00f4tes repr\u00e9sente l'apoth\u00e9ose de l'hospitalit\u00e9 conviviale. Vous vous asseyez \u00e0 la table de l'h\u00f4te, c\u00f4toyant d'autres voyageurs venus d'horizons divers, partageant les plats pr\u00e9par\u00e9s avec soin par le ma\u00eetre de maison. Souvent cuisin\u00e9e \u00e0 partir de produits du jardin, de la basse-cour ou achet\u00e9s chez les producteurs locaux, cette cuisine authentique r\u00e9v\u00e8le l'identit\u00e9 culinaire du territoire. Vins r\u00e9gionaux, fruits de la r\u00e9gion, recettes transmises de g\u00e9n\u00e9rations en g\u00e9n\u00e9rations : la convivialit\u00e9 s'\u00e9change \u00e0 chaque bouch\u00e9e.<\/p><h3>D\u00e9coration Raffin\u00e9e & Atmosph\u00e8re Intimiste<\/h3><p>Les chambres d'h\u00f4tes sont g\u00e9n\u00e9ralement d\u00e9cor\u00e9es avec soin, refl\u00e9tant la personnalit\u00e9 de leurs propri\u00e9taires. Meubles anciens, tissus nobles, objets d'art, chemin\u00e9es : chaque d\u00e9tail cr\u00e9e une atmosph\u00e8re intime et raffin\u00e9e, loin du design h\u00f4telier impersonnel. Certaines propri\u00e9t\u00e9s offrent m\u00eame vue sur les vignobles, jardins fleuris ou perspectives bucoliques. Cette attention \u00e0 l'esth\u00e9tique cr\u00e9e un environnement propice \u00e0 la d\u00e9tente et \u00e0 la contemplation.<\/p><h3>Id\u00e9al pour Voyageurs en Qu\u00eate d'Authenticit\u00e9<\/h3><p>Les chambres d'h\u00f4tes s\u00e9duisent particuli\u00e8rement les voyageurs souhaitant d\u00e9passer le tourisme de masse : couples en lune de miel, familles interg\u00e9n\u00e9rationnelles, retrait\u00e9s curieux, professionnels cherchant d\u00e9tente. Cette formule offre un juste \u00e9quilibre entre l'intimit\u00e9 d'une location et les services d'un h\u00f4tel, avec l'humanit\u00e9 en plus. Pour les voyages de d\u00e9couverte r\u00e9gionale, aucune alternative ne surpasse l'immersion offerte par une vraie chambre d'h\u00f4tes.<\/p><p>Choisir une chambre d'h\u00f4tes, c'est accepter l'invitation \u00e0 partager, pendant quelques nuits, la vie d'une famille qui vous ouvre son c\u0153ur.\",\"en\":\"<h2>Bed & Breakfast & Guest Tables: The Essence of French Hospitality<\/h2><p>Bed & breakfast accommodations embody the French tradition of warm, genuine welcome. Far beyond a simple gite, they offer authentic human exchange where the host becomes a friend, the residence becomes a temporary home, and every detail reveals deep affection for the land. This quintessential French rural tourism formula delivers total immersion in local authenticity, far removed from the cold standardization of large hotel chains.<\/p><h3>Personalized and Authentic Welcome<\/h3><p>Unlike hotels where you're a number, in a bed & breakfast you're a guest. The host takes time to get acquainted, shares personal recommendations, local secrets, regional anecdotes. This warm reception creates an irreplaceable atmosphere: fireside conversations, expert dining suggestions, directions to hidden hiking trails. Human warmth remains central to this unique experience.<\/p><h3>Gourmet Breakfasts & Local Produce<\/h3><p>The included breakfast transcends mere formality; it's a genuine celebration of regional flavors. Local bakery breads and pastries, homemade jams, village beekeeper honey, regional cheeses, artisanal charcuterie: each item narrates the territory's story. Many hosts prepare their own pastries, jams, and yogurts. This generous breakfast offers far more than nutrition: it's a delicious introduction to local gastronomic riches.<\/p><h3>Guest Tables: Family-Style Dining<\/h3><p>The guest table represents the pinnacle of convivial hospitality. You dine at your host's table, alongside travelers from diverse backgrounds, sharing dishes prepared with care by the household. Often featuring garden produce, homegrown poultry, or items from local producers, this authentic cuisine reveals the territory's culinary identity. Regional wines, local fruits, recipes passed through generations: conviviality is exchanged with every bite.<\/p><h3>Refined Decor & Intimate Atmosphere<\/h3><p>Bed & breakfasts are typically decorated with care, reflecting their owners' personalities. Antique furnishings, noble fabrics, artworks, fireplaces: every detail creates an intimate, refined atmosphere far from impersonal hotel design. Some properties offer vineyard views, flowering gardens, or pastoral perspectives. This aesthetic attention creates an environment conducive to relaxation and contemplation.<\/p><h3>Perfect for Authenticity-Seeking Travelers<\/h3><p>Bed & breakfasts particularly appeal to travelers seeking to transcend mass tourism: honeymoon couples, multigenerational families, curious retirees, professionals seeking respite. This format offers the perfect balance between rental privacy and hotel services, with added humanity. For regional discovery travels, no alternative matches the immersion offered by genuine bed & breakfast stays.<\/p><p>Choosing a bed & breakfast means accepting an invitation to share, for several nights, the life of a family opening their heart to you.\"}","group_id":1,"group_ids":[1]},"foires-shopping":{"icon":"fa-solid fa-bag-shopping","label":"Nuit & Bars","labels":{"fr":"Nuit & Bars"},"types":["FairOrShow","BricABrac","GarageSale","ShoppingCentreAndGallery"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Foires et shopping\"}","seo_description":"{\"fr\":\"Chiner et acheter.\"}","seo_intro":"{\"fr\":\"Ambiance.\"}","group_id":5,"group_ids":[5]},"musees-arts":{"icon":"fa-solid fa-building-columns","label":"Mus\u00e9es & Arts","labels":{"fr":"Mus\u00e9es & Arts"},"types":["Museum","ArtGalleryOrExhibitionGallery","Cinematheque"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"\u00c9difices Religieux, Cath\u00e9drales et Abbayes : Patrimoine Sacr\u00e9\",\"en\":\"Religious Buildings, Cathedrals & Abbeys: Sacred Heritage\"}","seo_description":"{\"fr\":\"Explorez le patrimoine religieux : \u00e9glises romanes, cath\u00e9drales gothiques et monast\u00e8res silencieux.\",\"en\":\"Explore religious heritage: Romanesque churches, Gothic cathedrals, and silent monasteries.\"}","seo_intro":"{\"fr\":\"<h2>Le Patrimoine Sacr\u00e9 : Un Voyage au C\u0153ur du Spirituel et de l\u2019Art<\/h2><p>Le patrimoine religieux constitue l\u2019une des facettes les plus impressionnantes de notre architecture. Des <strong>cath\u00e9drales gothiques<\/strong> qui d\u00e9fient le ciel aux petites chapelles de campagne nich\u00e9es au creux des vall\u00e9es, ces \u00e9difices sont les gardiens d\u2019une histoire mill\u00e9naire, de traditions vivaces et d\u2019un artisanat d\u2019art hors du commun. Pousser la porte d\u2019un lieu de culte, c\u2019est s\u2019offrir une parenth\u00e8se de calme et de contemplation.<\/p><h3>La splendeur de l\u2019architecture gothique et romane<\/h3><p>La r\u00e9gion regorge de tr\u00e9sors architecturaux. Les <strong>abbayes et monast\u00e8res<\/strong>, souvent situ\u00e9s dans des sites naturels d\u2019une grande beaut\u00e9, t\u00e9moignent de la vie monastique et du rayonnement intellectuel de jadis. On y admire des clo\u00eetres aux sculptures d\u00e9licates, des cryptes myst\u00e9rieuses et des charpentes monumentales. Les grandes cath\u00e9drales, quant \u00e0 elles, impressionnent par leurs vitraux color\u00e9s qui filtrent la lumi\u00e8re, cr\u00e9ant une atmosph\u00e8re unique propice \u00e0 la r\u00e9flexion. Ces \u00e9difices ne sont pas seulement des lieux de pri\u00e8re, mais de v\u00e9ritables mus\u00e9es \u00e0 ciel ouvert o\u00f9 le g\u00e9nie des b\u00e2tisseurs s\u2019exprime pleinement.<\/p><h3>Un art sacr\u00e9 aux mille visages<\/h3><p>Au-del\u00e0 de l\u2019architecture, le patrimoine sacr\u00e9 abrite des tr\u00e9sors artistiques : retables sculpt\u00e9s, orgues monumentaux, peintures murales et tr\u00e9sors d\u2019orf\u00e8vrerie. De nombreuses \u00e9glises proposent des concerts de musique sacr\u00e9e ou classique, profitant d\u2019une acoustique exceptionnelle. Que vous soyez passionn\u00e9 d\u2019histoire de l\u2019art ou en qu\u00eate de s\u00e9r\u00e9nit\u00e9, la visite de ces <strong>lieux de culte<\/strong> est une exp\u00e9rience enrichissante. Nous vous invitons \u00e0 respecter la tranquillit\u00e9 des lieux et \u00e0 d\u00e9couvrir ces sentiers de p\u00e8lerinage qui, aujourd\u2019hui encore, attirent les marcheurs du monde entier.<\/p>\",\"en\":\"<h2>Sacred Heritage: A Journey into Spirituality and Art<\/h2><p>Religious heritage is one of the most impressive aspects of our architecture. From <strong>Gothic cathedrals<\/strong> to small country chapels, these buildings are guardians of a thousand-year-old history and extraordinary craftsmanship.<\/p><h3>Splendor of Gothic and Romanesque Architecture<\/h3><p>The region is full of architectural treasures. <strong>Abbeys and monasteries<\/strong>, often located in beautiful natural sites, testify to monastic life. Visitors can admire delicately carved cloisters and monumental frames. Large cathedrals impress with their stained glass windows that filter light, creating a unique atmosphere.<\/p>\"}","group_id":3,"group_ids":[3]},"balades-itineraires":{"icon":"fa-solid fa-person-walking","label":"Rando & V\u00e9lo","labels":{"fr":"Rando & V\u00e9lo"},"types":["Rambling","CyclingTour","HorseTour","FitnessPath"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Loisirs M\u00e9caniques, Sports A\u00e9riens et Sensations Fortes\",\"en\":\"Motor Sports, Aerial Activities & Extreme Sports\"}","seo_description":"{\"fr\":\"Faites le plein d'adr\u00e9naline : bapt\u00eames de l'air, karting, montgolfi\u00e8re et sports m\u00e9caniques.\",\"en\":\"Get your adrenaline fix: flying lessons, karting, hot air ballooning, and motorsports.\"}","seo_intro":"{\"fr\":\"<h2>Loisirs \u00e0 Sensations : Prenez de la Hauteur et de la Vitesse<\/h2><p>Pour ceux qui cherchent \u00e0 pimenter leur s\u00e9jour avec une dose d\u2019adr\u00e9naline, notre s\u00e9lection de <strong>loisirs m\u00e9caniques et a\u00e9riens<\/strong> offre des exp\u00e9riences inoubliables. Que ce soit sur terre ou dans les airs, ces activit\u00e9s sont encadr\u00e9es par des professionnels passionn\u00e9s qui placent la s\u00e9curit\u00e9 au sommet de leurs priorit\u00e9s tout en vous garantissant des \u00e9motions fortes.<\/p><h3>Le ciel comme terrain de jeu<\/h3><p>Prendre de la hauteur permet de d\u00e9couvrir les paysages sous un angle totalement in\u00e9dit. Un vol en <strong>montgolfi\u00e8re<\/strong> au lever du soleil offre un moment de pl\u00e9nitude absolue, glissant au gr\u00e9 des vents. Pour plus de dynamisme, laissez-vous tenter par un bapt\u00eame en <strong>ULM<\/strong>, en parapente ou m\u00eame un saut en parachute pour les plus t\u00e9m\u00e9raires. Ces exp\u00e9riences a\u00e9riennes offrent des panoramas \u00e0 couper le souffle et un sentiment de libert\u00e9 incomparable, marquant souvent le point d'orgue d'un voyage.<\/p><h3>Vitesse et ma\u00eetrise au sol<\/h3><p>Sur la terre ferme, les <strong>sports m\u00e9caniques<\/strong> permettent de tester ses r\u00e9flexes et sa ma\u00eetrise. Le <strong>karting<\/strong> est l\u2019activit\u00e9 familiale ou entre amis par excellence, id\u00e9ale pour se d\u00e9fier sur des circuits techniques. Pour les amateurs de tout-terrain, des randonn\u00e9es encadr\u00e9es en quad ou en 4x4 vous emm\u00e8nent hors des sentiers battus pour explorer des zones recul\u00e9es. Quelle que soit l'activit\u00e9 choisie, l\u2019accent est mis sur le respect de l\u2019environnement et des consignes de s\u00e9curit\u00e9 pour que l\u2019adr\u00e9naline reste un plaisir pur.<\/p>\",\"en\":\"<h2>Adrenaline Leisure: Take to the Skies and Feel the Speed<\/h2><p>For those looking to spice up their stay, our selection of <strong>motor and aerial sports<\/strong> offers unforgettable experiences. Whether on the ground or in the air, these activities are supervised by professionals.<\/p><h3>The Sky as Your Playground<\/h3><p>Take flight to discover landscapes from a brand-new perspective. A <strong>hot air balloon<\/strong> flight at sunrise offers absolute peace. For more excitement, try <strong>paragliding<\/strong> or skydiving for the daring. These aerial experiences provide breathtaking panoramas.<\/p><h3>Speed and Ground Control<\/h3><p>On solid ground, <strong>motorsports<\/strong> let you test your reflexes. <strong>Karting<\/strong> is the perfect activity for friends or family. For off-road fans, guided quad or 4x4 tours take you off the beaten path.<\/p>\"}","group_id":4,"group_ids":[4]},"refuges-chalets":{"icon":"fa-solid fa-house-chimney-window","label":"Refuges","labels":{"fr":"Refuges"},"types":["Hut","Chalet","Mountain"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Refuges\"}","seo_description":"{\"fr\":\"Nuits en altitude.\"}","seo_intro":"{\"fr\":\"Atmosph\u00e8re bois\u00e9e.\"}","group_id":8,"group_ids":[8]},"services-sante-wifi":{"icon":"fa-solid fa-kit-medical","label":"Services","labels":{"fr":"Services"},"types":["Pharmacy","ATM","PublicLavatories","WifiHotSpot"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Services utiles\"}","seo_description":"{\"fr\":\"Sant\u00e9 et wifi.\"}","seo_intro":"{\"fr\":\"Pratique au quotidien.\"}","group_id":10,"group_ids":[10]},"sources-fontaines":{"icon":"fa-solid fa-faucet","label":"Sources","labels":{"fr":"Sources"},"types":["Source","WaterSource","Fountain"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Sources\"}","seo_description":"{\"fr\":\"Eaux bienfaitrices.\"}","seo_intro":"{\"fr\":\"Eau vive.\"}","group_id":6,"group_ids":[6]},"nautisme-plongee":{"icon":"fa-solid fa-person-swimming","label":"Sports Nautiques","labels":{"fr":"Sports Nautiques"},"types":["NauticalCentre","UnderwaterRoute","LaunchingRamp"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Sports Nautiques\"}","seo_description":"{\"fr\":\"Activit\u00e9s en mer.\"}","seo_intro":"{\"fr\":\"Plongez.\"}","group_id":7,"group_ids":[7]},"tourisme-memoire":{"icon":"fa-solid fa-monument","label":"M\u00e9moire","labels":{"fr":"M\u00e9moire"},"types":["RemembranceSite","MilitaryCemetery","Commemoration"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Sites de m\u00e9moire\"}","seo_description":"{\"fr\":\"Hommage et histoire.\"}","seo_intro":"{\"fr\":\"Ne pas oublier.\"}","group_id":9,"group_ids":[9]},"vins-distilleries":{"icon":"fa-solid fa-wine-glass","label":"Vins & Caves","labels":{"fr":"Vins & Caves"},"types":["Winery","Cellar","Distillery","Brewery","TastingProvider"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Vignobles, Caves & Distilleries | Art du Vin & Spiritueux\",\"en\":\"Vineyards, Cellars & Distilleries | Wine & Spirit Art\"}","seo_description":"{\"fr\":\"D\u00e9couvrez vignobles prestigieux, caves historiques et distilleries artisanales. D\u00e9gustations, visites guid\u00e9es, patrimoine viticole. Apprentissage du vin.\",\"en\":\"Explore prestigious vineyards, historic cellars, and artisanal distilleries. Tastings, guided tours, wine heritage. Wine education.\"}","seo_intro":"{\"fr\":\"<h2>Vignobles, Caves & Distilleries : L'Alchimie du Nectar Fran\u00e7ais<\/h2><p>Le vin fran\u00e7ais repr\u00e9sente bien plus qu'une boisson : il incarne si\u00e8cles de savoir-faire, de traditions transmises g\u00e9n\u00e9rations apr\u00e8s g\u00e9n\u00e9rations, et de dialogue profond entre l'homme et territoire. Chaque bouteille raconte histoire : climat particulier ann\u00e9e, choix du vigneron, exposition parcelle, moment r\u00e9colte, techniques fermentation anciennes. Les vignobles, caves et distilleries fran\u00e7aises constituent authentique patrimoine culturel, o\u00f9 science rejoint art, o\u00f9 nature dicte rythme, et o\u00f9 passion anime chaque d\u00e9tail.<\/p><h3>Vignobles : Terroir & Expression Naturelle<\/h3><p>Le concept fran\u00e7ais de \\\"terroir\\\" d\u00e9signe totalit\u00e9 conditions naturelles affectant vigne : nature sol, exposition au soleil, influence climat, altitude, proximit\u00e9 eau. Deux parcelles \u00e0 quelques centaines m\u00e8tres distance produisent vins radicalement diff\u00e9rents. Visites vignobles offrent compr\u00e9hension profonde cette alchimie naturelle. On marche entre ceps, on observe feuillet\u00e9, on apprend reconnaissance maturit\u00e9 raisins.<\/p><h3>C\u00e9pages & Traditions Viticoles S\u00e9culaires<\/h3><p>France cultive centaines c\u00e9pages : Pinot Noir, Cabernet Sauvignon, Merlot, Chardonnay, Sauvignon Blanc, Riesling, Muscadet. Chaque c\u00e9page poss\u00e8de caract\u00e9ristiques gustatifs propres, exigeances culturales distinctes, et traditions d'assemblage particuli\u00e8res. Vignerons h\u00e9ritent savoir-faire parents, m\u00e9langent innovations modernes respectueuses avec techniques ancestrales.<\/p><h3>Caves Historiques & Patrimoine Souterrain<\/h3><p>Caves historiques constituent patrimoine architectural souterrain impressionnant. Tunnels creus\u00e9s craie sous Champagne stockent millions bouteilles. Catacombes Paris abritaient production clandestine. Ces souterrains deviennent parcours initiatique o\u00f9 on d\u00e9couvre secrets maturation, o\u00f9 on apprend dur\u00e9e vieillissement, o\u00f9 atmosph\u00e8re musty r\u00e9v\u00e8le patience requise excellence.<\/p><h3>D\u00e9gustations : \u00c9ducation Sensorielle<\/h3><p>D\u00e9gustation vin n'est pas simplement boire : c'est apprentissage sensoriel structur\u00e9. Sommelier guide progressivement travers niveaux analyse : d'abord observation visuelle, puis olfaction, finalement gustation. Cette approche m\u00e9thodique transforme d\u00e9gustation simple en exp\u00e9rience d'\u00e9ducation gustative.<\/p><h3>Visites Guid\u00e9es & Rencontres Vignerons<\/h3><p>Vignobles France proposent visites guid\u00e9es offrant exp\u00e9riences authentiques. Marche travers vignes, observation techniques viticulture, d\u00e9monstration vendanges, visite caves, d\u00e9gustation dans contexte cultural riche. Nombreux vignerons passionn\u00e9s partagent trajectoires personnelles, expliquent d\u00e9cisions viticoles, r\u00e9v\u00e8lent philosophies.<\/p><h3>Distilleries & Eaux-de-Vie : Tradition Alcooli\u00e8re<\/h3><p>Au-del\u00e0 vin, France produit eaux-de-vie prestigieuses : Cognac, Armagnac, Calvados, Alsacian Kirsch. Processus production complexe transforme raisin ou fruits en eau-de-vie raffin\u00e9e. Visites distilleries r\u00e9v\u00e8lent alchimie : alcool distill\u00e9 brut transform\u00e9 vieillissement en nectar dor\u00e9 \u00e9quilibr\u00e9.<\/p><p>Choisir d\u00e9couvrir vignobles caves distilleries, c'est entreprendre voyage travers terroirs, traditions, et passions qui font France destination vinicole r\u00e9f\u00e9rence mondiale.\",\"en\":\"<h2>Vineyards, Cellars & Distilleries: Alchemy of French Nectar<\/h2><p>French wine represents far more than beverage: it embodies centuries of expertise, traditions transmitted generationally, and profound dialogue between humans and territory. Every bottle tells story: particular year's climate, winemaker choices, plot exposure, harvest timing, ancient fermentation techniques. French vineyards, cellars, and distilleries constitute authentic cultural heritage, where science meets art, where nature dictates rhythm, and where passion animates every detail.<\/p><h3>Vineyards: Terroir & Natural Expression<\/h3><p>The French concept of \\\"terroir\\\" designates all natural conditions affecting vines: soil nature, sun exposure, climate influence, altitude, water proximity. Two plots mere hundreds meters apart produce radically different wines. Vineyard visits offer profound understanding of this natural alchemy. Walking between vines, observing foliage, learning grape maturity recognition.<\/p><h3>Grape Varieties & Centuries-Old Viticultural Traditions<\/h3><p>France cultivates hundreds of grape varieties: Pinot Noir, Cabernet Sauvignon, Merlot, Chardonnay, Sauvignon Blanc, Riesling, Muscadet. Each variety possesses distinct flavor characteristics, specific cultivation demands, and particular blending traditions. Winemakers inherit parental expertise, mixing modern respectful innovations with ancestral techniques.<\/p><h3>Historic Cellars & Underground Patrimony<\/h3><p>Historic cellars constitute impressive underground architectural heritage. Tunnels carved into Champagne chalk store millions of bottles. Paris catacombs harbored clandestine production. These underground passages become initiatory journeys discovering maturation secrets, learning aging duration, experiencing musty atmosphere revealing patience excellence requires.<\/p><h3>Tastings: Sensorial Education<\/h3><p>Wine tasting isn't simply drinking: it's structured sensorial learning. Sommeliers progressively guide through analysis levels: first visual observation, then olfaction, finally gustation. This methodical approach transforms simple tasting into gustatory education experience.<\/p><h3>Guided Tours & Winemaker Encounters<\/h3><p>French vineyards offer guided visits providing authentic experiences. Walking vineyard rows, observing viticulture techniques, harvest demonstrations, cellar visits, tastings within rich cultural context. Many passionate winemakers share personal trajectories, explain viticultural decisions, reveal philosophies.<\/p><h3>Distilleries & Spirits: Alcoholic Tradition<\/h3><p>Beyond wine, France produces prestigious spirits: Cognac, Armagnac, Calvados, Alsatian Kirsch. Complex production processes transform grapes or fruits into refined spirits. Distillery visits reveal alchemy: crude distilled alcohol transformed through aging into balanced golden nectar.<\/p><p>Choosing to discover vineyards, cellars, and distilleries means undertaking journey through terroirs, traditions, and passions making France the world's reference wine destination.\"}","group_id":2,"group_ids":[2]},"aventure-loisirs":{"icon":"fa-solid fa-mountain-climbing","label":"Aventure & Sport","labels":{"fr":"Aventure & Sport"},"types":["AdventurePark","ClimbingWall","GolfCourse","ViaFerrata"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Bien-\u00eatre, Spa et Relaxation : Votre Parenth\u00e8se D\u00e9tente\",\"en\":\"Wellness, Spa & Relaxation: Your Peaceful Break\"}","seo_description":"{\"fr\":\"Prenez soin de vous : spas, centres de thalasso, massages et s\u00e9ances de yoga pour d\u00e9connecter.\",\"en\":\"Take care of yourself: spas, thalassotherapy, massages, and yoga sessions to disconnect.\"}","seo_intro":"{\"fr\":\"<h2>Bien-\u00eatre et Relaxation : L\u2019Art de se Ressourcer<\/h2><p>Dans un monde qui va toujours plus vite, s\u2019accorder une pause <strong>bien-\u00eatre<\/strong> n\u2019est plus un luxe, mais une n\u00e9cessit\u00e9. Notre s\u00e9lection de centres de d\u00e9tente et de spas vous invite \u00e0 l\u00e2cher prise. Des soins ancestraux aux technologies de pointe en thalassoth\u00e9rapie, chaque lieu est une bulle de s\u00e9r\u00e9nit\u00e9 con\u00e7ue pour harmoniser le corps et l\u2019esprit.<\/p><h3>Spas, Hammams et Centres Thermaux<\/h3><p>Laissez-vous envelopper par la chaleur d\u2019un <strong>hammam<\/strong> traditionnel ou d\u2019un sauna scandinave. Les <strong>Spas<\/strong> de la r\u00e9gion proposent des rituels de soins complets : gommages, enveloppements et massages du monde (ayurv\u00e9dique, pierres chaudes, shiatsu). Les centres thermaux utilisent les bienfaits des eaux min\u00e9rales pour des cures de sant\u00e9 ou simplement pour le plaisir de se pr\u00e9lasser dans des bassins chauff\u00e9s, offrant une d\u00e9connexion imm\u00e9diate.<\/p><h3>Activit\u00e9s Zen et Retraites<\/h3><p>Le bien-\u00eatre passe aussi par le mouvement doux. De nombreux praticiens proposent des s\u00e9ances de <strong>yoga<\/strong> en plein air, face \u00e0 la mer ou en for\u00eat, ainsi que de la m\u00e9ditation guid\u00e9e. Pour une immersion totale, tournez-vous vers les retraites d\u00e9tox ou les s\u00e9jours de sylvoth\u00e9rapie (bains de for\u00eat). Ces exp\u00e9riences vous apprennent \u00e0 respirer, \u00e0 \u00e9couter votre corps et \u00e0 repartir avec une \u00e9nergie renouvel\u00e9e. Prendre soin de soi, c'est s'offrir le plus beau des voyages int\u00e9rieurs.<\/p>\",\"en\":\"<h2>Wellness and Relaxation: The Art of Recharging<\/h2><p>In a fast-paced world, taking a <strong>wellness<\/strong> break is a necessity. Our selection of relaxation centers and spas invites you to let go and harmonize your body and mind.<\/p><h3>Spas, Hammams, and Thermal Centers<\/h3><p>Wrapped in the warmth of a traditional <strong>hammam<\/strong> or a Scandinavian sauna, enjoy complete care rituals: scrubs and massages. <strong>Spas<\/strong> offer world-class treatments, while thermal centers use mineral waters for health and pleasure.<\/p><h3>Zen Activities and Retreats<\/h3><p>Wellness also involves gentle movement. Many practitioners offer <strong>yoga<\/strong> sessions outdoors or guided meditation. For total immersion, try detox retreats or forest bathing.<\/p>\"}","group_id":4,"group_ids":[4]},"campings-insolite":{"icon":"fa-solid fa-tent","label":"Campings & Insolite","labels":{"fr":"Campings & Insolite"},"types":["Camping","Yurt","TreeHouse","Bubble","Tipi","Hut"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Campings & H\u00e9bergements Insolites | Nuits Magiques\",\"en\":\"Camping & Unusual Accommodations | Magical Nights\"}","seo_description":"{\"fr\":\"D\u00e9couvrez campings de charme, yourtes, cabanes dans les arbres, bulles et tipis. S\u00e9jours insolites et nature. Aventure inoubliable en famille.\",\"en\":\"Explore charming campsites, yurts, treehouses, bubbles, and tipis. Unique nature stays. Unforgettable adventures for families.\"}","seo_intro":"{\"fr\":\"<h2>Campings & H\u00e9bergements Insolites : Aventure, Confort et Magie<\/h2><p>Le camping et l'h\u00e9bergement insolite incarnent une philosophie de voyage lib\u00e9r\u00e9e des conventions : la fusion harmonieuse entre connexion \u00e0 la nature, confort raisonn\u00e9 et exp\u00e9riences m\u00e9morables. Que vous choisissiez un camping traditionnel avec toutes les commodit\u00e9s, une yourte confortable sous les \u00e9toiles, une cabane suspendue entre les branches, ou une bulle transparente offrant un panorama sur le ciel nocturne, chaque formule propose une aventure unique o\u00f9 la nature devient complice de vos vacances.<\/p><h3>Campings de Charme : Naturalit\u00e9 et \u00c9quipements Modernes<\/h3><p>Oubliez l'image st\u00e9r\u00e9otyp\u00e9e des campings bruyants et surpeupl\u00e9s. Les campings que nous s\u00e9lectionnons incarnent la qualit\u00e9 : emplacements espac\u00e9s respectant l'environnement, acc\u00e8s direct aux lacs ou rivi\u00e8res, piscines \u00e9cologiques, et \u00e9quipements sanitaires au-del\u00e0 des standards. Certains proposent m\u00eame des services haut de gamme : restaurants sur site, animations culturelles, spas en plein air. Ces \u00e9tablissements allient respect de la nature avec confort moderne, permettant aux familles de jouir de loisirs en toute s\u00e9r\u00e9nit\u00e9.<\/p><h3>Yourtes : Entre Tradition Nomade et Confort Contemporain<\/h3><p>La yourte, cette habitation traditionnelle des steppes mongoles, offre une exp\u00e9rience de voyage authentique. Circulaire et spacieuse, elle favorise la sensation d'amplitude tout en maintenant une temp\u00e9rature stable. Les yourtes modernes des \u00e9tablissements que nous proposons sont \u00e9quip\u00e9es de lits confortables, chauffage performant, \u00e9lectricit\u00e9 et m\u00eame salle d'eau priv\u00e9e. Dormir sous la toile, avec la lumi\u00e8re naturelle cr\u00e9ant une ambiance chaleureuse, cr\u00e9e une intimit\u00e9 avec la nature impossible dans un b\u00e2timent conventionnel.<\/p><h3>Cabanes dans les Arbres : R\u00eave d'Enfance R\u00e9alis\u00e9<\/h3><p>Pour les \u00e2mes en qu\u00eate de po\u00e9sie, les cabanes dans les arbres transforment chaque nuit en conte de f\u00e9es. Construites solidement avec respect pour l'\u00e9cosyst\u00e8me arboricole, elles offrent perspective unique sur la canop\u00e9e. Vue sur la for\u00eat, bruits de la nature au r\u00e9veil, sensation de l\u00e9g\u00e8ret\u00e9 : chaque d\u00e9tail renforce l'\u00e9vasion. Ces habitats, souvent d\u00e9cor\u00e9s avec cr\u00e9ativit\u00e9, proposent des lits douillets, chauffage, \u00e9clairage discret et parfois jacuzzis priv\u00e9s. C'est le voyage dans l'imaginaire enfantin rendu possible \u00e0 l'\u00e2ge adulte.<\/p><h3>Bulles & D\u00f4mes Transparents : Dormir Sous les \u00c9toiles<\/h3><p>La bulle transparente repr\u00e9sente l'innovations pour les amoureux de nature : allong\u00e9 dans votre lit, vous contemplez le ciel \u00e9toil\u00e9, les mouvements des nuages, la danse des aurores bor\u00e9ales selon la saison. Construites en mat\u00e9riaux r\u00e9sistants offrant isolations thermique et phonique, ces structures futuristes offrent confort surprenant. Am\u00e9nag\u00e9es avec lits premium, chauffage discret et salles d'eau priv\u00e9es, elles incarnent le mariage parfait entre aventure et luxe.<\/p><h3>Tipis et Habitats Traditionnels R\u00e9invent\u00e9s<\/h3><p>Les tipis, inspir\u00e9s des traditions am\u00e9rindiennes, offrent une g\u00e9om\u00e9trie parfaite pour accumuler chaleur. Spacieux, accueillants et d\u00e9cor\u00e9s d'\u00e9l\u00e9ments authentiques, ils cr\u00e9ent atmosph\u00e8re boh\u00e8me incomparable. Campfires ext\u00e9rieurs, mobilier rustique confortable, et int\u00e9gration totale au paysage transforment chaque tipi en refuge chaleureux adapt\u00e9 aux couples comme aux familles.<\/p><h3>Avantages de l'H\u00e9bergement Insolite<\/h3><p>Ces alternatives extraordinaires offrent des b\u00e9n\u00e9fices uniques : co\u00fbts g\u00e9n\u00e9ralement inf\u00e9rieurs aux h\u00f4tels, capacit\u00e9 \u00e0 cr\u00e9er des souvenirs ind\u00e9l\u00e9biles surtout pour enfants, immersion totale en nature, et sentiment d'aventure. Elles conviennent parfaitement aux familles, groupes d'amis, ou voyageurs solitaires cherchant reconnexion authentique avec le monde naturel.<\/p><p>Choisir le camping ou l'h\u00e9bergement insolite, c'est opter pour des vacances o\u00f9 chaque nuit devient histoire \u00e0 raconter pour des ann\u00e9es.\",\"en\":\"<h2>Camping & Unusual Accommodations: Adventure, Comfort & Magic<\/h2><p>Camping and unusual accommodations embody a philosophy of unconventional travel: harmonious fusion of nature connection, considered comfort, and memorable experiences. Whether choosing a traditional campsite with full amenities, a comfortable yurt beneath stars, a treehouse suspended between branches, or a transparent bubble offering panoramic night sky views, each option provides unique adventure where nature becomes your vacation companion.<\/p><h3>Charming Campsites: Naturality and Modern Facilities<\/h3><p>Forget the stereotypical image of noisy, overcrowded campgrounds. Our selected campsites embody quality: spacious, environmentally respectful pitches, direct access to lakes or rivers, ecological pools, and sanitization exceeding standards. Some offer premium services: onsite restaurants, cultural activities, outdoor spas. These establishments blend nature respect with modern comfort, enabling families to enjoy leisure with complete peace of mind.<\/p><h3>Yurts: Where Nomadic Tradition Meets Contemporary Comfort<\/h3><p>The yurt, this traditional Central Asian dwelling, offers authentic travel experience. Circular and spacious, it promotes openness while maintaining stable temperature. Modern yurts in our selected establishments feature comfortable beds, efficient heating, electricity, and private bathrooms. Sleeping under canvas, with natural light creating warmth, creates nature intimacy impossible in conventional buildings.<\/p><h3>Treehouses: Childhood Dreams Realized<\/h3><p>For souls seeking poetry, treehouses transform each night into fairy tales. Solidly constructed with respect for arboreal ecosystems, they offer unique canopy perspectives. Forest views, nature sounds at wake-up, lightness sensation: every detail reinforces escape. These habitats, often creatively decorated, offer cozy beds, heating, discreet lighting, and sometimes private hot tubs. It's childhood imagination made possible in adulthood.<\/p><h3>Bubbles & Transparent Domes: Sleeping Under Stars<\/h3><p>The transparent bubble represents innovation for nature lovers: lying in bed, you contemplate the starry sky, cloud movements, seasonal auroras. Constructed with durable, thermally and acoustically insulated materials, these futuristic structures offer surprising comfort. Furnished with premium beds, discreet heating, and private bathrooms, they embody perfect fusion of adventure and luxury.<\/p><h3>Tipis & Reinvented Traditional Habitats<\/h3><p>Tipis, inspired by Native American traditions, offer perfect geometry for heat accumulation. Spacious, welcoming, and decorated with authentic elements, they create incomparable bohemian atmosphere. Outdoor campfires, comfortable rustic furnishings, and total landscape integration transform each tipi into warm refuge suited for couples and families alike.<\/p><h3>Benefits of Unusual Accommodations<\/h3><p>These extraordinary alternatives offer unique advantages: typically lower costs than hotels, unforgettable memories especially for children, complete nature immersion, and genuine adventure feeling. They suit families perfectly, friend groups, or solo travelers seeking authentic reconnection with the natural world.<\/p><p>Choosing camping or unusual accommodations means opting for vacations where every night becomes a story to recount for years.\"}","group_id":1,"group_ids":[1]},"nuit-casinos":{"icon":"fa-solid fa-glass-cheers","label":"Nuit & Bars","labels":{"fr":"Nuit & Bars"},"types":["Casino","BarOrPub","NightClub"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Casinos, Bars et Vie Nocturne : Sortir et s'Amuser le Soir\",\"en\":\"Casinos, Bars & Nightlife: Night Out & Fun\"}","seo_description":"{\"fr\":\"Vivez l'ambiance nocturne : casinos, pubs anim\u00e9s et bars branch\u00e9s pour vos soir\u00e9es.\",\"en\":\"Experience the nightlife: casinos, lively pubs, and trendy bars for your evenings.\"}","seo_intro":"{\"fr\":\"<h2>Vie Nocturne : Quand la Ville s'Illumine<\/h2><p>La nuit appartient \u00e0 ceux qui aiment la f\u00eate et la convivialit\u00e9. Notre s\u00e9lection de <strong>casinos<\/strong>, <strong>bars<\/strong> et pubs vous garantit des soir\u00e9es anim\u00e9es. Que vous souhaitiez tenter votre chance aux machines \u00e0 sous, d\u00e9guster un cocktail cr\u00e9atif dans un bar lounge ou partager une bi\u00e8re artisanale dans un pub \u00e0 l'ambiance \u00e9lectrique, il y a toujours un lieu pour prolonger la journ\u00e9e.<\/p><h3>Divertissement et Adr\u00e9naline<\/h3><p>Les <strong>casinos<\/strong> offrent un m\u00e9lange unique de glamour et d'excitation avec leurs tables de jeux et leurs spectacles. Pour une ambiance plus d\u00e9contract\u00e9e, tournez-vous vers les bars \u00e0 th\u00e8mes ou les \u00e9tablissements proposant des concerts live. La <strong>vie nocturne<\/strong> est le moment id\u00e9al pour rencontrer les locaux et d\u00e9couvrir la culture festive de la r\u00e9gion. Sortez, amusez-vous, mais restez responsables !<\/p>\",\"en\":\"<h2>Nightlife: When the City Lights Up<\/h2><p>Night is for those who love celebration and conviviality. Our selection of <strong>casinos<\/strong>, <strong>bars<\/strong>, and pubs guarantees lively evenings.<\/p><h3>Entertainment and Adrenaline<\/h3><p><strong>Casinos<\/strong> offer a unique mix of glamour and excitement. For a more relaxed vibe, head to theme bars or live music venues. Nightlife is the perfect time to meet locals.<\/p>\"}","group_id":5,"group_ids":[5]},"balades-mer":{"icon":"fa-solid fa-ship","label":"Bateau","labels":{"fr":"Bateau"},"types":["SightseeingBoat","FluvialTour"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Bateau\"}","seo_description":"{\"fr\":\"Excursions en mer.\"}","seo_intro":"{\"fr\":\"Prendre le large.\"}","group_id":7,"group_ids":[7]},"producteurs-marches":{"icon":"fa-solid fa-basket-shopping","label":"March\u00e9s & Producteurs","labels":{"fr":"March\u00e9s & Producteurs"},"types":["Market","Producer","Farm","LocalProductsShop"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"March\u00e9s & Vente \u00e0 la Ferme | Produits Locaux Authentiques\",\"en\":\"Markets & Farm Direct Sales | Authentic Local Products\"}","seo_description":"{\"fr\":\"D\u00e9couvrez march\u00e9s fermiers et producteurs. Produits frais de saison, vente directe \u00e0 la ferme, circuits courts. Support \u00e9conomie locale.\",\"en\":\"Explore farmers markets and producers. Fresh seasonal products, farm direct sales, short supply chains. Support local economy.\"}","seo_intro":"{\"fr\":\"<h2>March\u00e9s & Producteurs : Du Champ \u00e0 Votre Table<\/h2><p>Les march\u00e9s fermiers et ventes directes repr\u00e9sentent essence \u00e9conomie alimentaire authentique fran\u00e7aise : relation directe producteur consommateur, garantie produits fra\u00eecheur sup\u00e9rieure, et reconnaissance valeur v\u00e9ritable travail agricole. Loin supermarch\u00e9s o\u00f9 origines demeurent myst\u00e9rieuses, ces lieux de vie permettent dialogue entre ceux cultivent et ceux consomment. Le produit achet\u00e9 march\u00e9 fermier porte identit\u00e9 producteur, histoire champ, et gout incomparable produits supermarch\u00e9 longtemps stock\u00e9s.<\/p><h3>March\u00e9s Fermiers : Vie Hebdomadaire & Tradition<\/h3><p>March\u00e9s fermiers constituent rendez-vous hebdomadaire incontournable villes villages. Chaque mercredi, dimanche matin, place village se transforme veritable vitrine richesses agricoles r\u00e9gionales. Producteurs, avec \u00e9tals d\u00e9bordant couleurs fraicheur, offrent joie sensorielle : senteurs herbes aromatiques fraichement cueillies, couleur vibrante tomates \u00e9t\u00e9, silence quand client examine fruits d\u00e9licatement. Conversations entre marchands clients cr\u00e9ent sociabilit\u00e9 perdue supermarch\u00e9s.<\/p><h3>Fruits & L\u00e9gumes de Saison : Respect Cycle Naturel<\/h3><p>Produits march\u00e9s fermiers \u00e9pousent cycles saisons naturels. Fraises avril, asperges mai, tomates juillet, aubergines ao\u00fbt, pommes septembre : cette saisonnalit\u00e9 offre vari\u00e9t\u00e9 annuelle constamment renouvel\u00e9e. Consommer produits saison signifie respect rythmes naturels, r\u00e9duction empreinte carbone transport, et maximisation qualit\u00e9 gustative.<\/p><h3>Fromages, Charcuteries & Produits Laitiers Artisanaux<\/h3><p>Beaucoup march\u00e9s accueillent producteurs fromages fermiers, fromagers artisanaux transformant lait vaches ch\u00e8vres brebis en tr\u00e9sors gustatifs. Tomme traditionnelle, ch\u00e8vres frais, bleus fermiers : chaque fromage poss\u00e8de histoire propre affinage longueur varie. Go\u00fbter camembert vivant fermier, encore quelque peau moisissure noble d\u00e9velopp\u00e9e caverne naturelle, offre r\u00e9v\u00e9lation gustative majeure.<\/p><h3>Miel, Confitures & Transformations Artisanales<\/h3><p>Apiculteurs locaux vendent miels aux ar\u00f4mes variant fleurs saison : miel accacia clair printanier, miel ch\u00e2taigne automnal cors\u00e9, polyfloral nuanc\u00e9. Producteurs confitures font bouillir fruits frais sucre juste quantit\u00e9, cr\u00e9ant p\u00e2tes dor\u00e9es saveur concentr\u00e9e.<\/p><h3>Viandes & Poissons : Provenance Tra\u00e7able<\/h3><p>\u00c9leveurs fermiers vendent viandes directement : poulets fermiers \u00e9lev\u00e9s libert\u00e9 prairie, veaux \u00e9lev\u00e9s m\u00e8re, porc savoureux nourri tradition. Tra\u00e7abilit\u00e9 compl\u00e8te rassure quant conditions \u00e9levage, alimentation, bien-\u00eatre animal.<\/p><h3>Circuits Courts & Durabilit\u00e9 \u00c9cologique<\/h3><p>Ventes directes r\u00e9duisent drastiquement empreinte carbone : pas transport longue distance, peu emballage, minimisation gaspillage. Producteurs, sachant clients directement, soignent qualit\u00e9 exceptionnellement. \u00c9conomiquement, prix march\u00e9s fermiers souvent inf\u00e9rieurs supermarch\u00e9s, car absence intermediaires signifie producteur re\u00e7oit proportion majeure prix.<\/p><p>Choisir march\u00e9s fermiers vente directe, c'est voter pour alimentation authentique, soutenir producteurs passionn\u00e9s, et participer reconstruction lien terre dont notre alimentation proc\u00e8de.\",\"en\":\"<h2>Markets & Producers: From Field to Your Table<\/h2><p>Farmers' markets and direct sales represent the essence of authentic French food economy: direct producer-consumer relationship, guaranteed product freshness superiority, and recognition of genuine agricultural work value. Far from supermarkets where origins remain mysterious, these living places enable dialogue between cultivators and consumers. Products purchased at farmers markets bear the producer's identity, field history, and incomparable taste compared to long-stored supermarket products.<\/p><h3>Farmers Markets: Weekly Life & Tradition<\/h3><p>Farmers' markets constitute essential weekly appointments in towns and villages. Each Wednesday, Sunday morning, village squares transform into veritable showcases of regional agricultural riches. Producers, with stalls overflowing with color and freshness, offer sensorial joy: scents of freshly harvested aromatic herbs, vibrant colors of summer tomatoes, gentle care as customers examine fruits. Conversations between vendors and customers create sociability lost in supermarkets.<\/p><h3>Seasonal Fruits & Vegetables: Respect Natural Cycles<\/h3><p>Farmers market products embrace natural seasonal cycles. Strawberries in April, asparagus in May, tomatoes in July, eggplants in August, apples in September: this seasonality offers constantly renewed annual variety. Consuming seasonal products means respecting natural rhythms, reducing transport carbon footprint, and maximizing gustatory quality.<\/p><h3>Artisanal Cheeses, Charcuterie & Dairy Products<\/h3><p>Many markets welcome farm cheese producers, artisanal cheesemakers transforming cow, goat, and sheep milk into gustatory treasures. Traditional tomme, fresh goat cheeses, farmstead blues: each cheese possesses its own affinage history with varying maturation lengths. Tasting living camembert from the farm, still bearing some noble mold developed in natural caves, offers major gustatory revelation.<\/p><h3>Honey, Jams & Artisanal Transformations<\/h3><p>Local beekeepers sell honeys with aromas varying by seasonal flowers: clear spring acacia honey, robust autumn chestnut honey, nuanced multifloral. Jam producers boil fresh fruits with precise sugar quantities, creating golden pastes of concentrated flavor.<\/p><h3>Meat & Fish: Traceable Provenance<\/h3><p>Farm breeders sell meat directly: free-range farm chickens raised in meadows, calves raised by mothers, flavorful pork fed traditional nourishment. Complete traceability reassures regarding breeding conditions, feeding, and animal welfare.<\/p><h3>Short Supply Chains & Ecological Sustainability<\/h3><p>Direct sales drastically reduce carbon footprint: no long-distance transport, minimal packaging, waste minimization. Producers, knowing customers directly, care for quality exceptionally. Economically, farmers market prices often undercut supermarkets because lack of intermediaries means producers receive major price proportions.<\/p><p>Choosing farmers markets and direct sales means voting for authentic food, supporting passionate producers, and participating in land connection reconstruction from which our nourishment proceeds.\"}","group_id":2,"group_ids":[2]},"teleferiques-acces":{"icon":"fa-solid fa-cable-car","label":"T\u00e9l\u00e9ph\u00e9riques","labels":{"fr":"T\u00e9l\u00e9ph\u00e9riques"},"types":["TourismCableCar","CableCarStation"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"T\u00e9l\u00e9ph\u00e9riques\"}","seo_description":"{\"fr\":\"Acc\u00e8s aux sommets.\"}","seo_intro":"{\"fr\":\"Sans effort.\"}","group_id":8,"group_ids":[8]},"archeologie-grottes":{"icon":"fa-solid fa-hill-rockslide","label":"Arch\u00e9ologie & Grottes","labels":{"fr":"Arch\u00e9ologie & Grottes"},"types":["ArcheologicalSite","MegalithDolmenMenhir","CaveSinkholeOrAven"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Sites Naturels, Parcs et Jardins Remarquables\",\"en\":\"Natural Sites, Parks & Remarkable Gardens\"}","seo_description":"{\"fr\":\"\u00c9vadez-vous dans la nature : parcs nationaux, jardins botaniques et panoramas exceptionnels.\",\"en\":\"Escape into nature: national parks, botanical gardens, and exceptional panoramas.\"}","seo_intro":"{\"fr\":\"<h2>Nature et Espaces Verts : Une Bouff\u00e9e d\u2019Air Pur<\/h2><p>La nature est notre plus bel \u00e9crin. Entre <strong>parcs naturels r\u00e9gionaux<\/strong>, r\u00e9serves prot\u00e9g\u00e9es et jardins botaniques, le territoire offre une diversit\u00e9 de paysages qui sauront combler les amateurs de grands espaces et les passionn\u00e9s de botanique. Que vous cherchiez la fra\u00eecheur d\u2019une for\u00eat centenaire, le calme d\u2019un jardin \u00e0 la fran\u00e7aise ou la puissance d\u2019un site naturel sauvage, chaque escapade est une invitation au ressourcement.<\/p><h3>Jardins Remarquables et Parcs Urbains<\/h3><p>Les <strong>jardins remarquables<\/strong> sont des \u0153uvres d\u2019art vivantes. Des jardins de ch\u00e2teaux aux parcs paysagers contemporains, ces espaces invitent \u00e0 la fl\u00e2nerie. On y d\u00e9couvre des collections v\u00e9g\u00e9tales rares, des jeux d\u2019eau apaisants et des compositions florales qui \u00e9voluent au fil des saisons. Pour les citadins, les parcs urbains constituent de v\u00e9ritables poumons verts, id\u00e9aux pour une promenade en famille, un jogging matinal ou une pause lecture \u00e0 l\u2019ombre des grands arbres.<\/p><h3>Sites Naturels Class\u00e9s et Panoramas<\/h3><p>Pour ceux qui pr\u00e9f\u00e8rent le sauvage au cultiv\u00e9, nos <strong>sites naturels class\u00e9s<\/strong> offrent des panoramas \u00e0 couper le souffle. Gorges profondes, sommets majestueux, falaises escarp\u00e9es ou marais myst\u00e9rieux : la biodiversit\u00e9 y est reine. Ces sites sont souvent \u00e9quip\u00e9s de sentiers d\u2019interpr\u00e9tation pour comprendre la faune et la flore locales sans les perturber. C\u2019est le terrain de jeu favori des photographes de nature et des observateurs d\u2019oiseaux. En explorant ces lieux, vous participez \u00e0 la protection d\u2019\u00e9cosyst\u00e8mes fragiles. N\u2019oubliez pas de respecter les consignes de pr\u00e9servation et de rester sur les sentiers balis\u00e9s.<\/p>\",\"en\":\"<h2>Nature and Green Spaces: A Breath of Fresh Air<\/h2><p>Nature is our most beautiful setting. Between <strong>regional natural parks<\/strong>, protected reserves, and botanical gardens, the territory offers a diversity of landscapes that will satisfy lovers of the outdoors.<\/p><h3>Remarkable Gardens and Urban Parks<\/h3><p><strong>Remarkable gardens<\/strong> are living works of art. From castle gardens to contemporary landscaped parks, these spaces invite you to stroll. For city dwellers, urban parks are true green lungs, ideal for a family walk or a morning jog.<\/p><h3>Classified Natural Sites and Panoramas<\/h3><p>For those who prefer the wild, our <strong>classified natural sites<\/strong> offer breathtaking panoramas. Deep gorges, majestic peaks, or mysterious marshes: biodiversity is king here.<\/p>\"}","group_id":3,"group_ids":[3]},"tourisme-eco":{"icon":"fa-solid fa-seedling","label":"\u00c9co-tourisme","labels":{"fr":"\u00c9co-tourisme"},"types":["NaturalPark","EducationalTrail","Producer","Farm"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Tourisme durable\"}","seo_description":"{\"fr\":\"Voyager responsable.\"}","seo_intro":"{\"fr\":\"Respect de la nature.\"}","group_id":9,"group_ids":[9]},"camping-car-van":{"icon":"fa-solid fa-caravan","label":"Aires Camping-Car","labels":{"fr":"Aires Camping-Car"},"types":["CamperVanArea","RVServiceArea","CampingPitch"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Aires de Camping-Car & Van : \u00c9tapes et Services Complets\",\"en\":\"RV Parks & Van Areas: Complete Stops and Services\"}","seo_description":"{\"fr\":\"Trouvez l'aire de camping-car ou de van id\u00e9ale. Services de vidange, \u00e9lectricit\u00e9 et stationnement s\u00e9curis\u00e9. \u00c9tapes confortables et bien localis\u00e9es.\",\"en\":\"Find the perfect RV or van stop. Drainage services, electricity, and secure parking. Comfortable and well-located stops.\"}","seo_intro":"{\"fr\":\"<h2>Aires de Camping-Car & Van : Libert\u00e9 et Mobilit\u00e9 pour vos Voyages<\/h2><p>Le voyage en van ou en camping-car est bien plus qu'un simple mode de transport ; c'est une v\u00e9ritable philosophie de vie synonyme de libert\u00e9 absolue. Cependant, pour que cette libert\u00e9 reste un plaisir quotidien, il est crucial de s'appuyer sur un r\u00e9seau d'infrastructures de qualit\u00e9. Nos aires de services et de stationnement sont rigoureusement s\u00e9lectionn\u00e9es pour r\u00e9pondre aux besoins techniques et au confort des nomades modernes.<\/p><h3>Des infrastructures adapt\u00e9es \u00e0 l'itin\u00e9rance<\/h3><p>Une \u00e9tape r\u00e9ussie commence par des services fonctionnels. Les <strong>aires de services<\/strong> permettent de g\u00e9rer l'essentiel : la vidange des eaux grises et noires, le remplissage du r\u00e9servoir d'eau potable et, bien souvent, l'acc\u00e8s \u00e0 une borne de recharge \u00e9lectrique. Ces points d'arr\u00eat techniques sont indispensables pour maintenir l'autonomie de votre v\u00e9hicule tout au long de votre p\u00e9riple. Nous r\u00e9pertorions des bornes artisanales simples mais efficaces ainsi que des stations modernes automatis\u00e9es.<\/p><h3>S\u00e9curit\u00e9 et cadre de vie<\/h3><p>Au-del\u00e0 de l'aspect technique, les <strong>aires de stationnement<\/strong> offrent un cadre s\u00e9curis\u00e9 pour passer la nuit en toute s\u00e9r\u00e9nit\u00e9. Nombre d'entre elles sont situ\u00e9es dans des environnements privil\u00e9gi\u00e9s, \u00e0 proximit\u00e9 de sentiers de randonn\u00e9e, de sites historiques class\u00e9s ou de centres-villes dynamiques accessibles \u00e0 pied. Contrairement au camping sauvage, stationner sur une aire d\u00e9di\u00e9e garantit le respect de la r\u00e9glementation locale et de l'environnement, tout en favorisant une cohabitation harmonieuse avec les r\u00e9sidents locaux.<\/p><h3>Conseils pour une \u00e9tape sereine<\/h3><p>Pour optimiser votre voyage, nous vous recommandons de v\u00e9rifier les \u00e9quipements sp\u00e9cifiques disponibles sur chaque fiche : acc\u00e8s WiFi pour les digital nomads, tri des d\u00e9chets pour un voyage \u00e9co-responsable, ou encore pr\u00e9sence d'un \u00e9clairage public rassurant. En haute saison, les aires les plus pris\u00e9es peuvent se remplir rapidement ; arriver en milieu d'apr\u00e8s-midi est souvent la meilleure strat\u00e9gie pour s'assurer une place de choix et profiter du coucher de soleil.<\/p>\",\"en\":\"<h2>RV Parks & Van Areas: Freedom and Mobility for Your Travels<\/h2><p>Traveling by van or RV is more than a mode of transport; it is a philosophy of freedom. To ensure this freedom remains a pleasure, quality infrastructure is essential. Our service areas and parking spots are selected to meet the technical and comfort needs of modern nomads.<\/p><h3>Tailored Infrastructure for Road Trips<\/h3><p>A successful stop starts with functional services. <strong>Service areas<\/strong> handle the essentials: grey and black water disposal, fresh water refilling, and often electric charging points. These technical stops are vital for maintaining your vehicle's autonomy throughout your journey.<\/p><h3>Security and Quality Living Spaces<\/h3><p>Beyond technical aspects, <strong>parking areas<\/strong> offer secure settings for peaceful nights. Many are located in privileged environments, near hiking trails, listed historical sites, or dynamic town centers accessible on foot. Unlike wild camping, parking in designated areas guarantees local regulation and environmental respect while promoting harmonious cohabitation with local residents.<\/p><h3>Advice for a Serene Stop<\/h3><p>To optimize your journey, verify specific equipment available: WiFi access for digital nomads, waste sorting for eco-responsible travel, or reassuring public lighting. High season areas fill quickly; arriving mid-afternoon often ensures good spots with sunset views.\"}","group_id":1,"group_ids":[1]},"patrimoine-industriel":{"icon":"fa-solid fa-gears","label":"Industrie & Artisanat","labels":{"fr":"Industrie & Artisanat"},"types":["Mill","Mine","IndustrialSite","CraftsmanShop"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Patrimoine Industriel et Artisanal : L\u2019H\u00e9ritage des Savoir-faire\",\"en\":\"Industrial & Craft Heritage: The Legacy of Know-how\"}","seo_description":"{\"fr\":\"D\u00e9couvrez l\u2019histoire industrielle : moulins, mines et manufactures anciennes. Un voyage technique.\",\"en\":\"Discover industrial history: mills, mines, and old factories. A technical journey.\"}","seo_intro":"{\"fr\":\"<h2>Patrimoine Industriel : Quand l\u2019Homme fa\u00e7onne la Mati\u00e8re<\/h2><p>Le <strong>patrimoine industriel<\/strong> est le t\u00e9moin de l\u2019ing\u00e9niosit\u00e9 humaine et de l\u2019\u00e9volution de nos soci\u00e9t\u00e9s. Des anciens <strong>moulins<\/strong> \u00e0 eau aux <strong>mines<\/strong> de charbon, en passant par les manufactures de textile ou de porcelaine, ces sites racontent l\u2019\u00e9pop\u00e9e du travail et de l\u2019innovation technique. Visiter ces lieux, c\u2019est comprendre comment nos anc\u00eatres ont domestiqu\u00e9 les \u00e9nergies naturelles pour transformer le paysage et l\u2019\u00e9conomie.<\/p><h3>Des sites de production transform\u00e9s en lieux de culture<\/h3><p>Beaucoup de ces sites ont trouv\u00e9 une seconde vie. Les anciennes usines deviennent des centres d\u2019art contemporain, tandis que les mines se transforment en mus\u00e9es immersifs o\u00f9 l\u2019on descend dans les galeries pour revivre le quotidien des mineurs. Le <strong>patrimoine artisanal<\/strong>, comme les forges ou les tanneries, permet de voir l\u2019\u00e9volution de l\u2019outil, de la main \u00e0 la machine. C\u2019est une plong\u00e9e fascinante dans la sociologie du travail et l\u2019architecture utilitaire qui poss\u00e8de sa propre esth\u00e9tique, brute et majestueuse.<\/p>\",\"en\":\"<h2>Industrial Heritage: How Man Shapes Matter<\/h2><p><strong>Industrial heritage<\/strong> testifies to human ingenuity and social evolution. From old <strong>water mills<\/strong> to <strong>mines<\/strong> and textile factories, these sites tell the story of labor and innovation.<\/p><h3>Production Sites Turned Cultural Hubs<\/h3><p>Many sites have found a second life as art centers or immersive museums. Discovering <strong>craft heritage<\/strong> like forges or tanneries allows visitors to see the evolution of tools from hand to machine. It is a fascinating dive into the sociology of work and utilitarian architecture.<\/p>\"}","group_id":3,"group_ids":[3]},"sensation-adrenaline":{"icon":"fa-solid fa-bolt","label":"Adr\u00e9naline","labels":{"fr":"Adr\u00e9naline"},"types":["Racetrack","Canyon","Parade","Icefall"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Sensations fortes\"}","seo_description":"{\"fr\":\"D\u00e9passement de soi.\"}","seo_intro":"{\"fr\":\"Coup de boost.\"}","group_id":9,"group_ids":[9]},"faune-animaliers":{"icon":"fa-solid fa-hippo","label":"Zoos & Animaux","labels":{"fr":"Zoos & Animaux"},"types":["Zoo","Aquarium","VivariumAquarium","TeachingFarm"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Zoos & Animaux\"}","seo_description":"{\"fr\":\"Rencontre animale.\"}","seo_intro":"{\"fr\":\"Pour les petits.\"}","group_id":4,"group_ids":[4]},"groupe-jeunesse":{"icon":"fa-solid fa-users-rectangle","label":"Groupes & Jeunesse","labels":{"fr":"Groupes & Jeunesse"},"types":["YouthHostel","CollectiveHostel","StopOverOrGroupLodge"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"H\u00e9bergements de Groupe & Jeunesse | S\u00e9jours Collectifs\",\"en\":\"Group & Youth Lodging | Collective Stays\"}","seo_description":"{\"fr\":\"D\u00e9couvrez nos auberges de jeunesse et h\u00e9bergements de groupe. Chambres partag\u00e9es ou priv\u00e9es, ambiance conviviale. Parfait pour voyageurs sociaux.\",\"en\":\"Explore youth hostels and group accommodations. Shared or private rooms, friendly atmosphere. Perfect for social travelers.\"}","seo_intro":"{\"fr\":\"<h2>H\u00e9bergements de Groupe & Jeunesse : Partage, Convivialit\u00e9 et Aventure Collective<\/h2><p>Les auberges de jeunesse et h\u00e9bergements collectifs incarnent une philosophie de voyage inclusif o\u00f9 chaque visiteur, quel que soit son \u00e2ge, sa nationalit\u00e9 ou son budget, trouve sa place. Bien au-del\u00e0 de simples lieux de repos, ces \u00e9tablissements constituent des carrefours d'\u00e9changes, des point de rencontre o\u00f9 naissent amiti\u00e9 internationales, projets communs, et o\u00f9 les murs r\u00e9sonnent des r\u00e9cits de voyageurs de tous horizons. Ils repr\u00e9sentent la d\u00e9mocratie du voyage : l'accessibilit\u00e9 financi\u00e8re combin\u00e9e \u00e0 l'enrichissement humain.<\/p><h3>Auberges de Jeunesse : Portes Ouvertes sur le Monde<\/h3><p>Les auberges de jeunesse traditionnelles proposent chambres partag\u00e9es de 4 \u00e0 12 lits, cr\u00e9ant atmosph\u00e8re communautaire naturelle. Les voyageurs dorment c\u00f4te \u00e0 c\u00f4te, s'\u00e9changent des conseils au petit-d\u00e9jeuner, organisent sorties en groupe. Cette configuration \u00e9conomique permet aux jeunes de voyager avec budgets limit\u00e9s sans sacrifier qualit\u00e9 basique. Les salles communes, souvent \u00e9quip\u00e9es de cuisines partag\u00e9es, deviennent lieux de cr\u00e9ation culinaire collective o\u00f9 chacun pr\u00e9pare plats de son pays d'origine.<\/p><h3>Chambres Priv\u00e9es & Semi-Priv\u00e9es pour Plus d'Intimit\u00e9<\/h3><p>Pour qui souhaitent confort d'une chambre priv\u00e9e sans l'isolement de l'h\u00f4tel, les dortoirs sp\u00e9cialis\u00e9s offrent 2 \u00e0 4 lits dans chambres ferm\u00e9es. Cette formule s\u00e9duit couples, petits groupes d'amis, ou voyageurs d\u00e9sirant intimit\u00e9 tout en participant \u00e0 vie communautaire. Les salles d'eau peuvent \u00eatre partag\u00e9es ou priv\u00e9es selon le standing. Cette flexibilit\u00e9 garantit que chacun trouve son \u00e9quilibre id\u00e9al entre socialisation et intimit\u00e9.<\/p><h3>\u00c9quipements Collectifs Favorisant Coh\u00e9sion<\/h3><p>Les meilleurs h\u00e9bergements de groupe proposent cuisines \u00e9quip\u00e9es, salons conviviaux, terrasses, jardins, et souvent espaces \u00e9v\u00e9nementiels. Certains organisent activit\u00e9s : ateliers culinaires, jeux d'\u00e9quipe, projections de films, randonn\u00e9es guid\u00e9es ou visites locales. Ces \u00e9quipements et animations transforment simples nuits en souvenirs partag\u00e9s, en aventures collectives m\u00e9morables.<\/p><h3>Inclusivit\u00e9 Financi\u00e8re & Accessibilit\u00e9<\/h3><p>Le tarif des auberges de jeunesse demeure significativement inf\u00e9rieur aux h\u00f4tels, permettant aux voyageurs avec budgets serr\u00e9s d'acc\u00e9der au tourisme de qualit\u00e9. Cette accessibilit\u00e9 financi\u00e8re ne signifie pas baisse de qualit\u00e9 hygi\u00e9nique ou s\u00e9curitaire. Les chambres, bien que partag\u00e9es, b\u00e9n\u00e9ficient de nettoyage r\u00e9gulier, draps chang\u00e9s fr\u00e9quemment, et \u00e9quipements fonctionnels.<\/p><h3>Opportunit\u00e9s de R\u00e9seautage International<\/h3><p>Les auberges de jeunesse cr\u00e9ent environnement propice aux rencontres authentiques. En naviguant corridors, en se croisant \u00e0 la r\u00e9ception, en partageant petits-d\u00e9jeuners : des amiti\u00e9s n\u00e9es dans une auberge peuvent durer decades. Certaines auberges organisent r\u00e9unions de anciens pensionnaires, cr\u00e9ant r\u00e9seaux mondiaux de voyageurs fid\u00e8les.<\/p><p>Choisir auberge de jeunesse, c'est choisir voyage o\u00f9 chaque rencontre enrichit, o\u00f9 chaque nuit forge liens humains durables.\",\"en\":\"<h2>Group & Youth Lodging: Sharing, Conviviality, and Collective Adventure<\/h2><p>Youth hostels and collective accommodations embody a philosophy of inclusive travel where every visitor, regardless of age, nationality, or budget, finds belonging. Far beyond simple rest places, these establishments constitute exchange crossroads where international friendships bloom, common projects emerge, and walls echo with stories from travelers worldwide. They represent travel democracy: financial accessibility combined with human enrichment.<\/p><h3>Youth Hostels: Gateways to Global Connection<\/h3><p>Traditional youth hostels offer shared rooms of 4-12 beds, creating natural communal atmosphere. Travelers sleep nearby, exchange advice at breakfast, organize group outings. This economical configuration enables young travelers with limited budgets to travel without sacrificing basic quality. Common areas, often equipped with shared kitchens, become venues for collective culinary creation.<\/p><h3>Private & Semi-Private Rooms for Enhanced Intimacy<\/h3><p>For those desiring private room comfort without hotel isolation, specialized dormitories offer 2-4 bed rooms. This format appeals to couples, friend groups, or travelers seeking privacy while participating in community life. Bathrooms may be shared or private depending on category. This flexibility ensures everyone finds their ideal balance between socialization and intimacy.<\/p><h3>Collective Facilities Promoting Cohesion<\/h3><p>The best group accommodations feature equipped kitchens, convivial lounges, terraces, gardens, and often event spaces. Some organize activities: cooking workshops, team games, film screenings, guided hikes, or local tours. These facilities and activities transform simple nights into shared memories, into memorable collective adventures.<\/p><h3>Financial Inclusivity & Accessibility<\/h3><p>Youth hostel rates remain significantly lower than hotels, enabling budget-conscious travelers to access quality tourism. This financial accessibility doesn't mean compromised hygiene or security. Rooms, though shared, benefit from regular cleaning, frequently changed linens, and functional equipment.<\/p><h3>International Networking Opportunities<\/h3><p>Youth hostels create environments conducive to authentic encounters. Navigating corridors, meeting at reception, sharing breakfasts: friendships born in hostels can last decades. Some hostels organize reunions of former residents, creating global networks of loyal travelers.<\/p><p>Choosing a youth hostel means selecting travel where every meeting enriches, where every night forges lasting human bonds.\"}","group_id":1,"group_ids":[1]},"agenda-manifestations":{"icon":"fa-solid fa-calendar-days","label":"Festivals","labels":{"fr":"Festivals"},"types":["Event","Agenda","Exhibition","EntertainmentAndEvent"],"api_endpoint":"catalog","header_image_url":null,"seo_title":"{\"fr\":\"Artisanat d\u2019Art et Savoir-faire : Rencontre avec les Cr\u00e9ateurs\",\"en\":\"Arts and Crafts: Meet the Creators\"}","seo_description":"{\"fr\":\"D\u00e9couvrez l'excellence de l'artisanat local : poterie, verrerie, bijoux et m\u00e9tiers d'art.\",\"en\":\"Discover local craftsmanship excellence: pottery, glassware, jewelry, and artistic trades.\"}","seo_intro":"{\"fr\":\"<h2>Artisanat d\u2019Art : L\u2019Excellence de la Main et du Geste<\/h2><p>L\u2019<strong>artisanat d\u2019art<\/strong> est le reflet vibrant de l\u2019identit\u00e9 d\u2019un territoire. Il incarne la transmission des gestes s\u00e9culaires alli\u00e9e \u00e0 la cr\u00e9ativit\u00e9 contemporaine. En poussant la porte d\u2019un atelier, vous d\u00e9couvrez des hommes et des femmes passionn\u00e9s qui transforment la mati\u00e8re \u2014 terre, verre, bois, m\u00e9tal ou textile \u2014 en objets uniques porteurs d\u2019\u00e9motion.<\/p><h3>Des ateliers ouverts au public<\/h3><p>De nombreux <strong>artisans cr\u00e9ateurs<\/strong> ouvrent leurs ateliers pour partager leur quotidien. Observer un souffleur de verre, voir une pi\u00e8ce de poterie prendre forme sur le tour ou comprendre la pr\u00e9cision d\u2019un bijoutier est une exp\u00e9rience fascinante. Ces moments de rencontre permettent de comprendre la valeur du temps et de l\u2019effort derri\u00e8re chaque cr\u00e9ation. C\u2019est l\u2019occasion d\u2019acqu\u00e9rir des pi\u00e8ces authentiques, loin de la production de masse, et de soutenir directement l\u2019\u00e9conomie cr\u00e9ative locale.<\/p><h3>Transmission et initiation<\/h3><p>Pour ceux qui souhaitent passer de l\u2019observation \u00e0 la pratique, certains artisans proposent des <strong>stages d\u2019initiation<\/strong>. Apprendre \u00e0 forger, \u00e0 tisser ou \u00e0 modeler l\u2019argile le temps d\u2019une apr\u00e8s-midi permet de se reconnecter avec ses propres capacit\u00e9s manuelles. Que vous soyez \u00e0 la recherche d\u2019un objet de d\u00e9coration, d\u2019un cadeau original ou simplement curieux de d\u00e9couvrir des m\u00e9tiers d\u2019exception, l\u2019artisanat d\u2019art saura vous s\u00e9duire par sa sinc\u00e9rit\u00e9 et son raffinement.<\/p>\",\"en\":\"<h2>Artistic Craftsmanship: Excellence of the Hand and Gesture<\/h2><p><strong>Arts and crafts<\/strong> reflect a territory's vibrant identity. It embodies ancient skills combined with contemporary creativity. In these workshops, passionate creators transform raw materials into unique objects.<\/p><h3>Workshops Open to the Public<\/h3><p>Many <strong>artisans<\/strong> open their doors to share their daily lives. Watching a glassblower or a potter is a fascinating experience. It is the perfect opportunity to buy authentic pieces and support the local creative economy.<\/p><h3>Workshops and Initiation<\/h3><p>Some artisans offer <strong>introductory workshops<\/strong> for those wanting to try the craft themselves. Learn to forge, weave, or model clay for an afternoon.<\/p>\"}","group_id":5,"group_ids":[5]}};
const ACTIVE_CAT = "locations-gites";
const LANG_PREFIX = "";
const CURRENT_LANG = "fr";
const UI = {"search_placeholder":"Rechercher\u2026","all_communes":"Toutes les communes","date_all":"Tous","date_today":"Aujourd'hui","date_weekend":"Week-end","date_month":"Ce mois","date_choose":"Choisir les dates","reset":"R\u00e9initialiser","map_btn":"Carte","share":"Partager","no_name":"Sans nom","no_image":"Image \u00e0 venir","view_details":"Voir la fiche \u2192","learn_more":"En savoir plus","ongoing":"En cours","loading":"Chargement\u2026","no_results":"Aucun r\u00e9sultat pour","error_title":"Erreur","copied":"\u2713 Copi\u00e9 !","loaded_progress":"charg\u00e9s\u2026","results":"r\u00e9sultats","hidden":"masqu\u00e9s","hero_badge":"Exp\u00e9rience Locale","period":"P\u00e9riode :","filters":"Filtres","apply":"Voir les r\u00e9sultats","filter_search":"Recherche","filter_location":"Commune","x_areas":"communes","featured":"Coup de c\u0153ur","weebnb_stay":"Choisir un s\u00e9jour","weebnb_clear":"Effacer les dates","book_now":"R\u00e9server","stay_price":"Prix du s\u00e9jour","per_stay":"le s\u00e9jour","sleeps":"pers.","no_avail":"Disponibilit\u00e9 \u00e0 confirmer","weebnb_nights":"nuit","price_from_badge":"\u00e0 partir de","persons":"Personnes","persons_title":"Combien de personnes ?","persons_reset":"Annuler la s\u00e9lection","persons_single":"personne","persons_plural":"personnes","photo_only":"Avec photo","photo_only_label":"Uniquement avec photos","months_short":["jan.","f\u00e9v.","mars","avr.","mai","juin","juil.","ao\u00fbt","sep.","oct.","nov.","d\u00e9c."]};
const TYPE_LABELS = {"Restaurant":"Restaurant","FoodEstablishment":"Restauration","CafeOrCoffeeShop":"Caf\u00e9","FastFoodRestaurant":"Restauration rapide","BarOrPub":"Bar \/ Pub","StreetFood":"Street food","Winery":"\u0152nologie","IceCreamShop":"Glacier","Hotel":"H\u00f4tel","BedAndBreakfast":"Chambre d'h\u00f4tes","Campground":"Camping","Guesthouse":"Maison d'h\u00f4tes","SelfCateringAccommodation":"Location","HolidayVillage":"Village vacances","Chalet":"Chalet","Hostel":"Auberge","Accommodation":"H\u00e9bergement","Museum":"Mus\u00e9e","TouristAttraction":"Attraction","AmusementPark":"Parc de loisirs","ArtGallery":"Galerie d'art","RuinsOrArchaeologicalSite":"Site arch\u00e9ologique","PlaceOfWorship":"Lieu de culte","Library":"Biblioth\u00e8que","SportsActivityPlace":"Activit\u00e9 sportive","NaturalHeritage":"Patrimoine naturel","Park":"Parc","Beach":"Plage","HikingTrail":"Randonn\u00e9e","CyclingRoute":"V\u00e9lo","SwimmingPool":"Piscine","LocalProductsShop":"Produits locaux","MarketPlace":"March\u00e9","Store":"Commerce"};
// ─── État ─────────────────────────────────────────────────────────────────────
let allData=[], filtered=[], searchQ="", communes=[], modalCommunes=[], dateFilter="all", dateFrom="", dateTo="";
let otfPreData = null; // offres OTF pré-chargées (sans dates) pour tri OTF_FIRST
let photoOnly = false; // filtre "uniquement avec photos"
let cityData=[];
// WeeBnB
let weebnbData = null; // null = inactif, objet = données chargées (peut être vide)
let otfData = null; // null = inactif, objet = offres OTF (toujours disponibles)
let weebnbCheckin = '';
let weebnbCheckout = '';
let weebnbLoading = false;
// Filtre personnes
let personMin = 0;
let personMax = 0;
const IS_EVENT_CAT = (CATEGORIES[ACTIVE_CAT]?.api_endpoint === 'entertainmentAndEvent');
const HAS_WEEBNB = true;
const OTF_FIRST = true;
const SHOW_PHOTO_FILTER = false;
window.addEventListener("DOMContentLoaded", () => {
if (!TERRITORY_SLUG) { showError("Territoire non configuré."); return; }
readUrlState();
fetchCategory();
});
function readUrlState() {
const p = new URLSearchParams(location.search);
searchQ = p.get("q") ?? "";
communes = (p.get("communes") || "").split(',').filter(Boolean);
dateFilter = p.get("df") ?? "all";
dateFrom = p.get("from") ?? "";
dateTo = p.get("to") ?? "";
document.getElementById("searchInput").value = searchQ;
// Restaure les dates WeeBnB depuis l'URL
if (HAS_WEEBNB) {
const wbCi = p.get("checkin") ?? "";
const wbCo = p.get("checkout") ?? "";
if (wbCi && wbCo) {
// Positionner immédiatement les vars module pour que pushUrlState() les conserve
weebnbCheckin = wbCi;
weebnbCheckout = wbCo;
// Mémoriser pour l'init flatpickr (qui survient dans un autre listener DOMContentLoaded)
window._urlWbCheckin = wbCi;
window._urlWbCheckout = wbCo;
}
}
// Restaure le bouton date actif
document.querySelectorAll('.date-btn').forEach(b => {
b.classList.toggle('active', b.dataset.df === dateFilter);
});
// Restaure Flatpickr si les dates sont dans l'URL
if (dateFrom && typeof fpInstance !== 'undefined' && fpInstance) {
const dates = dateTo ? [dateFrom, dateTo] : [dateFrom];
fpInstance.setDate(dates, false);
const fmtShort = d => {
const mo = UI.months_short;
return `${d.getDate()} ${mo[d.getMonth()]}`;
};
const input = document.getElementById('drpInput');
if (input) {
input.value = dateTo
? fmtShort(new Date(dateFrom)) + ' → ' + fmtShort(new Date(dateTo))
: fmtShort(new Date(dateFrom)) + ' → …';
input.classList.add('has-range');
}
}
}
function pushUrlState() {
const p = new URLSearchParams();
if (searchQ) p.set("q", searchQ);
if (communes.length) p.set("communes", communes.join(','));
if (dateFilter && dateFilter !== 'all') p.set("df", dateFilter);
if (dateFrom) p.set("from", dateFrom);
if (dateTo) p.set("to", dateTo);
if (weebnbCheckin) p.set("checkin", weebnbCheckin);
if (weebnbCheckout) p.set("checkout", weebnbCheckout);
const qs = p.toString();
const _lp = LANG_PREFIX ? '/' + LANG_PREFIX : '';
history.replaceState(null, "", _lp + '/' + ACTIVE_CAT + (qs ? '?' + qs : ''));
}
function copyShareUrl() {
navigator.clipboard.writeText(location.href).then(() => {
const btn = document.getElementById("shareBtn");
const orig = btn.innerHTML;
btn.innerHTML = UI.copied;
btn.classList.add("copied");
setTimeout(() => { btn.innerHTML = orig; btn.classList.remove("copied"); }, 2200);
});
}
async function fetchCategory() {
const cat = CATEGORIES[ACTIVE_CAT];
if (!cat) { showError(`Catégorie inconnue : ${ACTIVE_CAT}`); return; }
showLoading();
allData = [];
let totalPois = null;
let nextUrl = `${API_BASE}/pois.php?territory=${encodeURIComponent(TERRITORY_SLUG)}&cat=${encodeURIComponent(ACTIVE_CAT)}&lang=${encodeURIComponent(CURRENT_LANG)}`;
let firstPage = true;
try {
while (nextUrl) {
const res = await fetch(nextUrl);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
allData.push(...(json.objects??[]));
if (json.meta?.total != null) totalPois = json.meta.total;
setProgress(`${allData.length}${totalPois ? ' / ' + totalPois : ''} ${UI.loaded_progress}`);
nextUrl = json.meta?.next ?? null;
// Dès la première page : afficher immédiatement les premiers résultats
// sans attendre la fin du chargement de toutes les pages
if (firstPage) {
firstPage = false;
if (allData.length) {
buildCommuneSelect();
applyFilters(false);
}
}
}
if (!allData.length) { showEmpty(cat); return; }
// Toutes les pages chargées → filtrage events + tri final + rebuild filtres
if (IS_EVENT_CAT) {
const todayStr = new Date().toISOString().slice(0,10);
allData = allData.filter(r => {
const end = r.event_end_date || r.event_start_date;
return !end || end >= todayStr;
});
}
sortAllData();
// Si des dates WeeBnB sont déjà présentes (URL partagée), on attend la réponse
// API avant d'afficher les cartes → pas de flash de POIs non filtrés
if (HAS_WEEBNB && weebnbCheckin && weebnbCheckout && weebnbData === null && !weebnbLoading) {
await loadWeebnb(weebnbCheckin, weebnbCheckout);
// loadWeebnb appelle applyFilters en interne → pas besoin de l'appeler ici
} else {
applyFilters(false);
// Pré-charger les offres OTF pour tri OTF_FIRST sans dates
if (OTF_FIRST && HAS_WEEBNB && !weebnbCheckin) loadOtfOnly();
}
} catch(err) { showError(err.message); }
}
function buildCommuneSelect() {
const counts = {};
allData.forEach(r => { const c = city(r); if (c) counts[c] = (counts[c] ?? 0) + 1; });
// Toujours construire depuis les villes réelles des POIs chargés
const ordered = Object.keys(counts).sort((a, b) => a.localeCompare(b, CURRENT_LANG));
cityData = ordered.map(n => ({ name: n, count: counts[n] }));
renderCityList('cityDrop', 'citySearch', communes, false);
renderCityList('mCityDrop', 'mCitySearch', modalCommunes, true);
updateCityPickerLabel();
}
// ─── Tri allData (appelé après chargement initial et après pré-chargement OTF) ─
function sortAllData() {
if (IS_EVENT_CAT) {
const todayStr = new Date().toISOString().slice(0,10);
allData.sort((a,b) => {
if (!!b.is_featured !== !!a.is_featured) return b.is_featured ? 1 : -1;
const td = todayStr;
const aEnd = a.event_end_date || a.event_start_date || '9999';
const bEnd = b.event_end_date || b.event_start_date || '9999';
const aOn = !!a.event_start_date && a.event_start_date <= td && aEnd >= td;
const bOn = !!b.event_start_date && b.event_start_date <= td && bEnd >= td;
if (aOn !== bOn) return aOn ? -1 : 1;
return (a.event_start_date??'9999').localeCompare(b.event_start_date??'9999');
});
} else {
allData.sort((a,b) => {
// OTF_FIRST pré-tri : si données OTF disponibles et pas de dates WeeBnB
if (OTF_FIRST && otfPreData !== null) {
const aInOtf = !!(otfPreData[a['dc:identifier']]);
const bInOtf = !!(otfPreData[b['dc:identifier']]);
if (aInOtf !== bInOtf) return aInOtf ? -1 : 1;
}
if (!!b.is_featured !== !!a.is_featured) return b.is_featured ? 1 : -1;
const aHasImg = !!img(a), bHasImg = !!img(b);
if (aHasImg !== bHasImg) return aHasImg ? -1 : 1;
return lbl(a.label).localeCompare(lbl(b.label), CURRENT_LANG);
});
}
buildCommuneSelect();
}
// ─── Pré-chargement OTF (sans dates) pour tri OTF_FIRST immédiat ─────────────
async function loadOtfOnly() {
try {
const url = `/api/weebnb.php?territory=${encodeURIComponent(TERRITORY_SLUG)}&otf_only=1&lang=${CURRENT_LANG}`;
const res = await fetch(url);
const json = await res.json();
if (!json.error && json.otf_offers) {
otfPreData = json.otf_offers;
sortAllData();
applyFilters(false);
}
} catch(e) {
console.warn('OTF pre-load:', e.message);
}
}
function applyFilters(scroll = true) {
if (scroll && allData.length > 0) {
const hero = document.querySelector('.hero_cat');
// Le targetY sera toujours > 50px → header sera en état .scrolled à destination.
// On mesure sa hauteur finale en forçant .scrolled sans transition.
let hh = 65;
if (headerEl) {
headerEl.style.transition = 'none';
headerEl.classList.add('scrolled');
void headerEl.offsetHeight; // force reflow
hh = Math.round(headerEl.getBoundingClientRect().height);
headerEl.style.transition = '';
}
syncLayoutHeights();
const targetY = hero ? Math.max(0, hero.offsetTop + hero.offsetHeight - hh) : 0;
window.scrollTo({ top: targetY, behavior: 'smooth' });
setTimeout(() => document.getElementById('cardsPanel')?.scrollTo({ top: 0, behavior: 'smooth' }), 400);
}
const qn = norm(searchQ);
const hasQ = !!qn;
const hasCommune = communes.length > 0;
const from = dateFrom ? new Date(dateFrom) : null;
const to = dateTo ? new Date(dateTo) : null;
const now = new Date();
now.setHours(0,0,0,0);
filtered = [];
for (let i = 0; i < allData.length; i++) {
const r = allData[i];
// Commune
if (hasCommune && !communes.includes(city(r))) continue;
// Recherche (optimisé)
if (hasQ) {
const text =
(r._searchCache ||= norm(
(lbl(r.label) || '') + ' ' +
(desc(r) || '') + ' ' +
(addr(r) || '')
));
if (!text.includes(qn)) continue;
}
// Dates (events)
if (IS_EVENT_CAT) {
const s = r.event_start_date ? new Date(r.event_start_date) : null;
const e = r.event_end_date ? new Date(r.event_end_date) : s;
if (from || to) {
if (!s) continue;
if (from && e && e < from) continue;
if (to && s && s > to) continue;
} else if (dateFilter !== 'all') {
if (!s) continue;
if (dateFilter === 'today') {
const end = new Date(now); end.setHours(23,59,59);
if (e < now || s > end) continue;
}
}
}
// WeeBnB / OTF : ne garder que les POIs présents dans au moins une source
if (weebnbData !== null || otfData !== null) {
const dcId = r['dc:identifier'];
const inWb = weebnbData && dcId && weebnbData[dcId];
const inOtf = otfData && dcId && otfData[dcId];
if (!inWb && !inOtf) continue;
// Filtre capacité personnes : s'applique uniquement si WeeBnB fournit sleeps_max
if (personMin > 0 && inWb) {
const sm = weebnbData[dcId]?.sleeps_max ?? 0;
if (sm < personMin) continue;
}
}
// Filtre photo
if (photoOnly && !img(r)) continue;
filtered.push(r);
}
// WeeBnB / OTF : tri prix DESC (WeeBnB). OTF_FIRST = OTF avant WeeBnB, même tri prix DESC
if (weebnbData !== null || otfData !== null) {
filtered.sort((a, b) => {
const dcA = a['dc:identifier'], dcB = b['dc:identifier'];
const aInOtf = !!(otfData?.[dcA]), bInOtf = !!(otfData?.[dcB]);
// Si OTF_FIRST : groupe OTF avant groupe WeeBnB
if (OTF_FIRST) {
if (aInOtf !== bInOtf) return aInOtf ? -1 : 1;
}
// Prix WeeBnB en priorité, puis OTF, puis null en dernier
const pa = weebnbData?.[dcA]?.final_price ?? null;
const pb = weebnbData?.[dcB]?.final_price ?? null;
if (pa === null && pb === null) return 0;
if (pa === null) return 1;
if (pb === null) return -1;
return pb - pa; // prix DESC (plus élevé en premier)
});
}
pushUrlState();
syncResetBtn();
updateWeebnbBar();
updateFmCount();
renderCards();
// ⚡ Lazy map
requestAnimationFrame(() => renderMapLazy(filtered));
}
function setDateFilter(val, btn) {
dateFilter = val;
document.querySelectorAll('.date-btn').forEach(b => b.classList.remove('active'));
if (btn) btn.classList.add('active');
if (val !== 'all') drpClear(false);
applyFilters();
}
// ─── Flatpickr date range ─────────────────────────────────────────────────────
let fpInstance = null;
document.addEventListener('DOMContentLoaded', () => {
// Localisation globale flatpickr (doit être avant tout if (!input) return)
flatpickr.localize(flatpickr.l10ns[CURRENT_LANG] || flatpickr.l10ns.fr);
const input = document.getElementById('drpInput');
if (!input) return;
fpInstance = flatpickr(input, {
mode: 'range',
minDate: 'today',
dateFormat: 'Y-m-d',
showMonths: window.innerWidth <= 640 ? 1 : 2,
disableMobile: true,
onChange(selectedDates) {
const fmtShort = d => {
const months = UI.months_short;
return `${d.getDate()} ${months[d.getMonth()]}`;
};
if (selectedDates.length === 2) {
dateFrom = fpInstance.formatDate(selectedDates[0], 'Y-m-d');
dateTo = fpInstance.formatDate(selectedDates[1], 'Y-m-d');
input.value = fmtShort(selectedDates[0]) + ' → ' + fmtShort(selectedDates[1]);
input.classList.add('has-range');
document.querySelectorAll('.date-btn').forEach(b => b.classList.remove('active'));
dateFilter = 'all';
applyFilters();
} else if (selectedDates.length === 1) {
dateFrom = fpInstance.formatDate(selectedDates[0], 'Y-m-d');
dateTo = '';
input.value = fmtShort(selectedDates[0]) + ' → …';
input.classList.add('has-range');
} else {
dateFrom = ''; dateTo = '';
input.classList.remove('has-range');
}
}
});
// Restaure les dates depuis l'URL (après init Flatpickr)
if (dateFrom) {
const fmtShort = d => {
const mo = ['jan.','fév.','mars','avr.','mai','juin','juil.','août','sep.','oct.','nov.','déc.'];
return `${d.getDate()} ${mo[d.getMonth()]}`;
};
const dates = dateTo ? [dateFrom, dateTo] : [dateFrom];
fpInstance.setDate(dates, false);
input.value = dateTo
? fmtShort(new Date(dateFrom)) + ' → ' + fmtShort(new Date(dateTo))
: fmtShort(new Date(dateFrom)) + ' → …';
input.classList.add('has-range');
}
});
function hasActiveFilters() {
return !!(searchQ || communes.length || dateFrom || dateTo || (dateFilter && dateFilter !== 'all'));
}
function syncResetBtn() {
const btn = document.getElementById('resetBtn');
if (btn) btn.style.display = hasActiveFilters() ? 'flex' : 'none';
updateFilterBadge();
}
function resetFilters() {
searchQ = '';
communes = [];
modalCommunes = [];
dateFilter = 'all';
dateFrom = '';
dateTo = '';
photoOnly = false;
const si = document.getElementById('searchInput');
if (si) si.value = '';
renderCityList('cityDrop', 'citySearch', communes, false);
renderCityList('mCityDrop', 'mCitySearch', modalCommunes, true);
updateCityPickerLabel();
document.querySelectorAll('.date-btn').forEach(b => b.classList.toggle('active', b.dataset.df === 'all'));
drpClear(false);
_syncPhotoUi();
applyFilters();
}
// ─── Filtre photo ─────────────────────────────────────────────────────────────
function togglePhotoFilter(desktopBtn, modalToggle) {
photoOnly = !photoOnly;
_syncPhotoUi();
applyFromModal(); // sync + apply instantané
}
function _syncPhotoUi() {
// Bouton desktop
const db = document.getElementById('photoFilterBtn');
if (db) db.classList.toggle('active', photoOnly);
// Toggle modal
const mt = document.getElementById('mPhotoToggle');
if (mt) mt.classList.toggle('active', photoOnly);
const mc = document.getElementById('mPhotoCheck');
if (mc) mc.checked = photoOnly;
}
function drpClear(doApply = true) {
if (fpInstance) fpInstance.clear();
dateFrom = ''; dateTo = '';
const input = document.getElementById('drpInput');
if (input) { input.value = ''; input.classList.remove('has-range'); }
if (doApply) {
document.querySelector('.date-btn[data-df="all"]')?.classList.add('active');
applyFilters();
}
}
// ─── City multi-picker ────────────────────────────────────────────────────────
function renderCityList(listId, searchId, selected, isModal) {
const list = document.getElementById(listId);
if (!list) return;
const searchEl = document.getElementById(searchId);
const q = searchEl ? searchEl.value.trim().toLowerCase() : '';
const data = cityData.filter(c => !q || c.name.toLowerCase().includes(q));
if (!data.length) {
list.innerHTML = `<div class="city-none">${UI.no_results.replace(' pour','')}</div>`;
return;
}
list.innerHTML = data.map(c => {
const checked = selected.includes(c.name);
const fn = isModal ? `toggleCityModal` : `toggleCityDesktop`;
return `<label class="city-option${checked?' checked':''}${c.count===0?' zero-count':''}" onclick="event.preventDefault();${fn}('${c.name.replace(/'/g,"\\'")}')">
<input type="checkbox" class="city-checkbox" ${checked?'checked':''} readonly/>
<span>${esc(c.name)}</span>
${c.count > 0 ? `<span class="city-option-count">${c.count}</span>` : ''}
</label>`;
}).join('');
}
function toggleCityDesktop(name) {
const idx = communes.indexOf(name);
if (idx >= 0) communes.splice(idx, 1); else communes.push(name);
renderCityList('cityDrop', 'citySearch', communes, false);
updateCityPickerLabel();
applyFilters();
}
function toggleCityModal(name) {
const idx = modalCommunes.indexOf(name);
if (idx >= 0) modalCommunes.splice(idx, 1); else modalCommunes.push(name);
renderCityList('mCityDrop', 'mCitySearch', modalCommunes, true);
applyFromModal();
}
// ─── Sync modal → état principal + apply instantané ─────────────────────────
function applyFromModal() {
// Lire les champs modal
const ms = document.getElementById('mSearch');
if (ms) searchQ = ms.value.trim();
communes = [...modalCommunes];
dateFilter = modalDateFilter;
// Sync vers les contrôles desktop
const si = document.getElementById('searchInput');
if (si) si.value = searchQ;
renderCityList('cityDrop', 'citySearch', communes, false);
updateCityPickerLabel();
document.querySelectorAll('.date-btn').forEach(b =>
b.classList.toggle('active', b.dataset.df === dateFilter));
applyFilters(false);
}
function updateCityPickerLabel() {
const lbl = document.getElementById('cityPickerLabel');
const btn = document.getElementById('cityPickerBtn');
const hint = document.getElementById('cityCountHint');
const n = communes.length;
if (lbl) lbl.textContent = n === 0 ? UI.all_communes : n === 1 ? communes[0] : `${n} ${UI.x_areas}`;
if (btn) btn.classList.toggle('has-sel', n > 0);
if (hint) hint.textContent = n > 0 ? `${n} sélectionnée${n>1?'s':''}` : '';
}
function openCityPicker() {
const drop = document.getElementById('cityPickerDrop');
const btn = document.getElementById('cityPickerBtn');
if (!drop) return;
const isOpen = drop.classList.contains('is-open');
drop.classList.toggle('is-open', !isOpen);
btn?.setAttribute('aria-expanded', String(!isOpen));
if (!isOpen) {
document.getElementById('citySearch')?.focus();
setTimeout(() => document.addEventListener('click', _closeCityOutside, { once: true }), 50);
}
}
function _closeCityOutside(e) {
if (!e.target.closest('#cityPicker')) {
document.getElementById('cityPickerDrop')?.classList.remove('is-open');
document.getElementById('cityPickerBtn')?.setAttribute('aria-expanded', 'false');
} else {
setTimeout(() => document.addEventListener('click', _closeCityOutside, { once: true }), 50);
}
}
function clearCities() {
communes = [];
renderCityList('cityDrop', 'citySearch', communes, false);
updateCityPickerLabel();
applyFilters();
}
// ─── Modal mobile filtres ──────────────────────────────────────────────────────
let fpModal = null;
let modalDateFilter = 'all';
function updateFilterBadge() {
const count = (searchQ ? 1 : 0) + (communes.length ? 1 : 0)
+ ((dateFilter && dateFilter !== 'all') ? 1 : 0)
+ (dateFrom ? 1 : 0) + (photoOnly ? 1 : 0);
const badge = document.getElementById('filterBadge');
if (badge) { badge.textContent = count || ''; badge.style.display = count ? 'flex' : 'none'; }
const btn = document.getElementById('mobileFilterBtn');
if (btn) btn.classList.toggle('has-filters', count > 0);
}
function openFilterModal() {
const modal = document.getElementById('filterModal');
if (!modal) return;
// Sync état courant → champs modal
const mSearch = document.getElementById('mSearch');
if (mSearch) mSearch.value = searchQ;
modalCommunes = [...communes];
renderCityList('mCityDrop', 'mCitySearch', modalCommunes, true);
modalDateFilter = dateFilter;
document.querySelectorAll('#mDateFilter .date-btn').forEach(b =>
b.classList.toggle('active', b.dataset.df === modalDateFilter));
// Initialise flatpickr modal si besoin
if (!fpModal) initModalFlatpickr();
if (fpModal) {
fpModal.clear();
if (dateFrom) fpModal.setDate(dateTo ? [dateFrom, dateTo] : [dateFrom], false);
}
updateFmCount();
modal.classList.add('is-open');
document.body.style.overflow = 'hidden';
document.getElementById('filterModalBackdrop')?.addEventListener('click', closeFilterModal, { once: true });
}
function closeFilterModal() {
const modal = document.getElementById('filterModal');
if (!modal) return;
modal.classList.remove('is-open');
document.body.style.overflow = '';
}
function applyModalFilters() {
// Tout est déjà synchronisé via applyFromModal() (instantané).
// On ferme simplement la popup.
closeFilterModal();
}
function resetFilterModal() {
const mSearch = document.getElementById('mSearch');
if (mSearch) mSearch.value = '';
modalCommunes = [];
renderCityList('mCityDrop', 'mCitySearch', modalCommunes, true);
modalDateFilter = 'all';
document.querySelectorAll('#mDateFilter .date-btn').forEach(b =>
b.classList.toggle('active', b.dataset.df === 'all'));
if (fpModal) fpModal.clear();
photoOnly = false;
_syncPhotoUi();
applyFromModal(); // apply instantané
}
function selectModalDate(val, btn) {
modalDateFilter = val;
document.querySelectorAll('#mDateFilter .date-btn').forEach(b => b.classList.remove('active'));
if (btn) btn.classList.add('active');
if (val !== 'all' && fpModal) fpModal.clear();
applyFromModal();
}
function updateFmCount() {
const el = document.getElementById('fmCount');
if (!el) return;
el.textContent = filtered.length > 0 ? `· ${filtered.length} ${UI.results}` : '';
}
function initModalFlatpickr() {
const input = document.getElementById('mDrpInput');
if (!input) return;
fpModal = flatpickr(input, {
mode: 'range', minDate: 'today', dateFormat: 'Y-m-d',
showMonths: 1, disableMobile: true,
onChange(selectedDates) {
const fmtShort = d => `${d.getDate()} ${UI.months_short[d.getMonth()]}`;
if (selectedDates.length >= 1) {
input.value = selectedDates.length === 2
? fmtShort(selectedDates[0]) + ' → ' + fmtShort(selectedDates[1])
: fmtShort(selectedDates[0]) + ' → …';
input.classList.add('has-range');
if (selectedDates.length === 2) {
modalDateFilter = 'all';
document.querySelectorAll('#mDateFilter .date-btn').forEach(b =>
b.classList.toggle('active', b.dataset.df === 'all'));
// Sync dates à l'état principal + apply instantané
dateFrom = fmtLocalDate(selectedDates[0]);
dateTo = fmtLocalDate(selectedDates[1]);
const drpIn = document.getElementById('drpInput');
if (drpIn) {
drpIn.value = fmtShort(selectedDates[0]) + ' → ' + fmtShort(selectedDates[1]);
drpIn.classList.add('has-range');
}
if (fpInstance) fpInstance.setDate(selectedDates, false);
applyFromModal();
}
} else {
input.value = '';
input.classList.remove('has-range');
dateFrom = ''; dateTo = '';
drpClear(false);
applyFromModal();
}
}
});
}
// ─── Lazy rendering ──────────────────────────────────────────────────────────
const CARDS_BATCH = 24;
let renderedCount = 0;
let lazyObserver = null;
function renderCards() {
const stats = document.getElementById("statsBar"), grid = document.getElementById("grid");
const total = allData.length, shown = filtered.length;
const activeFilter = searchQ || communes.join(', ');
const hint = shown < total && activeFilter ? ` <span class="hint">— ${total-shown} ${UI.hidden}</span>` : "";
stats.innerHTML = `<p class="count"><strong>${shown}</strong> ${UI.results}${hint}</p>`;
const hc = document.getElementById('catHeaderCount');
if (hc) hc.textContent = `${shown} ${UI.results}`;
if (!shown) {
grid.innerHTML = `<div class="state"><div class="icon">🔍</div><p>${UI.no_results} <strong>"${esc(activeFilter)}"</strong>.</p></div>`;
renderMap([]);
return;
}
// Reset et rendu du premier batch
renderedCount = 0;
grid.innerHTML = '';
loadMoreCards();
// La carte reçoit tous les POIs filtrés dès le départ
renderMap(filtered);
}
function loadMoreCards() {
const grid = document.getElementById("grid");
if (!grid || renderedCount >= filtered.length) return;
const batch = filtered.slice(renderedCount, renderedCount + CARDS_BATCH);
const frag = document.createDocumentFragment();
batch.forEach((r, i) => {
const tmp = document.createElement('div');
tmp.innerHTML = cardHTML(r, renderedCount + i);
const card = tmp.firstElementChild;
frag.appendChild(card);
});
grid.appendChild(frag);
// Animation décalée uniquement pour les nouvelles cartes
const allCards = grid.querySelectorAll('.card:not(.visible)');
allCards.forEach((el, i) => setTimeout(() => el.classList.add('visible'), i * 40));
renderedCount += batch.length;
// Sentinel : retire l'ancien, recrée si d'autres cartes restent
const old = document.getElementById('cardSentinel');
if (old) old.remove();
if (renderedCount < filtered.length) {
const sentinel = document.createElement('div');
sentinel.id = 'cardSentinel';
sentinel.style.cssText = 'height:1px;width:100%;grid-column:1/-1';
grid.appendChild(sentinel);
if (!lazyObserver) {
lazyObserver = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) loadMoreCards();
}, { rootMargin: '300px' });
}
lazyObserver.observe(sentinel);
} else {
// Tout est rendu, on nettoie l'observer
if (lazyObserver) { lazyObserver.disconnect(); lazyObserver = null; }
}
}
// ─── Carte Leaflet ─────────────────────────────────────────────────────────────
let catalogueMap = null, markerLayer = null, mapVisible = true;
function toggleMap() {
mapVisible = !mapVisible;
const layout = document.getElementById('catalogueLayout');
const btn = document.getElementById('mapToggleBtn');
layout.classList.toggle('map-hidden', !mapVisible);
btn.classList.toggle('active', mapVisible);
if (mapVisible) {
// Pause du lazyObserver pour éviter conflit pendant le scroll vers la carte
if (lazyObserver) lazyObserver.disconnect();
// Attendre 2 frames pour que le CSS `display:block` soit appliqué et que
// le container ait une taille réelle avant d'initialiser Leaflet
requestAnimationFrame(() => requestAnimationFrame(() => {
if (!catalogueMap) initCatalogueMap();
// invalidateSize EN PREMIER pour que Leaflet connaisse les vraies dimensions
catalogueMap.invalidateSize({ animate: false });
// Puis render + fitBounds avec les bonnes dimensions
renderMap(filtered);
// Scroll vers la carte après que fitBounds ait repositionné la vue
setTimeout(() => {
scrollToMap();
// Reprendre le lazy loading après stabilisation
setTimeout(() => {
if (renderedCount < filtered.length) {
const sentinel = document.getElementById('cardSentinel');
if (sentinel && lazyObserver) lazyObserver.observe(sentinel);
}
}, 500);
}, 100);
}));
}
}
function scrollToMap() {
if (window.innerWidth > 900) return;
const panel = document.getElementById('mapPanel');
if (!panel) return;
const cs = getComputedStyle(document.documentElement);
const hh = parseFloat(cs.getPropertyValue('--header-h')) || 65;
const th = parseFloat(cs.getPropertyValue('--toolbar-h')) || 56;
const offset = panel.getBoundingClientRect().top + window.scrollY - hh - th - 8;
window.scrollTo({ top: offset, behavior: 'smooth' });
}
function initCatalogueMap() {
if (catalogueMap) return;
const isTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
catalogueMap = L.map('catalogue-map', {
zoomControl: true,
scrollWheelZoom: !isTouch,
dragging: !isTouch,
tap: false,
});
if (isTouch) {
catalogueMap.on('touchstart', e => {
if (e.originalEvent.touches.length >= 2) catalogueMap.dragging.enable();
});
catalogueMap.on('touchend', () => catalogueMap.dragging.disable());
}
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
maxZoom: 19
}).addTo(catalogueMap);
markerLayer = L.layerGroup().addTo(catalogueMap);
}
const markerRefs = {};
function hlMarker(idx, on) {
const m = markerRefs[idx];
if (!m) return;
const el = m.getElement()?.querySelector('.cmap-marker');
if (el) el.classList.toggle('highlighted', on);
m.setZIndexOffset(on ? 2000 : 0);
}
function renderMap(data) {
if (!mapVisible) return;
if (!catalogueMap) initCatalogueMap();
markerLayer.clearLayers();
Object.keys(markerRefs).forEach(k => delete markerRefs[k]);
const bounds = [];
const catIcon = CATEGORIES[ACTIVE_CAT]?.icon || '📍';
data.forEach((r, i) => {
const geo = r.isLocatedAt?.[0]?.geo;
const geoObj = Array.isArray(geo) ? geo[0] : geo;
const lat = geoObj?.latitude;
const lng = geoObj?.longitude;
if (!lat || !lng) return;
const name = lbl(r.label) || 'Sans nom';
const cityTxt = city(r);
const _mapDateQs = (weebnbCheckin && weebnbCheckout) ? `?checkin=${weebnbCheckin}&checkout=${weebnbCheckout}` : '';
const poiUrl = r.poi_slug ? `${LANG_PREFIX?'/'+LANG_PREFIX:''}/${ACTIVE_CAT}/${r.poi_slug}${_mapDateQs}` : null;
const imgUrl = img(r);
const icon = L.divIcon({
className: '',
html: `<div class="cmap-marker"><i class="fa-solid fa-house" aria-hidden="true"></i></div>`,
iconSize: [34, 34],
iconAnchor: [17, 34],
popupAnchor: [0, -36],
});
const marker = L.marker([lat, lng], { icon }).addTo(markerLayer);
marker.bindPopup(`
<div class="map-popup">
${imgUrl ? `<img src="${esc(imgUrl)}" style="width:100%;height:80px;object-fit:cover;border-radius:6px;margin-bottom:6px;display:block" onerror="this.style.display='none'">` : ''}
<strong>${esc(name)}</strong>
${cityTxt ? `<small><i class="fa-solid fa-location-dot" style="color:#b0b0b0"></i> ${esc(cityTxt)}</small>` : ''}
${poiUrl ? `<a href="${poiUrl}">${UI.view_details}</a>` : ''}
</div>
`, { maxWidth: 220 });
marker.on('click', () => {
const card = document.getElementById(`card-${i}`);
if (card) {
card.scrollIntoView({ behavior:'smooth', block:'center' });
card.classList.add('card-flash');
setTimeout(() => card.classList.remove('card-flash'), 1800);
}
});
marker.on('mouseover', () => {
marker.getElement()?.querySelector('.cmap-marker')?.classList.add('highlighted');
marker.setZIndexOffset(2000);
});
marker.on('mouseout', () => {
marker.getElement()?.querySelector('.cmap-marker')?.classList.remove('highlighted');
marker.setZIndexOffset(0);
});
markerRefs[i] = marker;
bounds.push([lat, lng]);
});
if (bounds.length) {
catalogueMap.fitBounds(bounds, { padding: [40, 40], maxZoom: 14 });
}
}
// Init carte au chargement (desktop) — masquée sur mobile
window.addEventListener('load', () => {
if (!document.getElementById('catalogueLayout')) return;
if (window.innerWidth <= 900) {
// Mobile : carte cachée par défaut
mapVisible = false;
document.getElementById('catalogueLayout').classList.add('map-hidden');
document.getElementById('mapToggleBtn')?.classList.remove('active');
} else {
initCatalogueMap();
}
});
function cardHTML(r,i) {
const cat = CATEGORIES[ACTIVE_CAT];
const name = lbl(r.label) || UI.no_name;
const cityName= city(r);
const dsc = desc(r), imgUrl = img(r);
const c = r.hasContact?.[0] ?? {};
const tels = arr(c.telephone).filter(Boolean);
const emails = arr(c.email).filter(Boolean);
const urls = arr(c.homepage).filter(Boolean);
const typeBadge = formatType(r.type, cat?.types ?? []);
const _dateQs = (weebnbCheckin && weebnbCheckout) ? `?checkin=${weebnbCheckin}&checkout=${weebnbCheckout}` : '';
const poiUrl = r.poi_slug ? `${LANG_PREFIX?'/'+LANG_PREFIX:''}/${ACTIVE_CAT}/${esc(r.poi_slug)}${_dateQs}` : null;
const ctaUrl = poiUrl || (urls[0] ? esc(urls[0]) : '#');
// Image https://weetable.com/site/img/resize.php?url=https://decibelles-data.media.tourinsoft.eu/upload/Vezelay-site-taille-moyenne-3.jpg&width=400&height=400&crop=1&quality=85
const catFaIcon = catFAIcon(cat);
const imgHTML = imgUrl
//? `<div data-crop="0" data-bg="${esc(imgUrl)}" style="width:100%; aspect-ratio:16/9; margin:auto;"></div>`
? `<div class="specialite-image chef-bg" data-bg="${esc(imgUrl)}" style="height: 100%;"></div>`
//? `<img src="/img/resize.php?url=${esc(imgUrl)}&width=500&height=240&crop=1&quality=85" alt="${esc(name)}" loading="lazy" onerror="this.style.display='none';this.nextElementSibling.style.display='flex'">`
: ``;
const noImg = `<div class="no-img"${imgUrl?' style="display:none"':''}><i class="fas ${catFaIcon}"></i><p>${UI.no_image}</p></div>`;
// Badge date (events)
let dateBadge = '';
if (IS_EVENT_CAT && r.event_start_date) {
const todayStr2 = new Date().toISOString().slice(0,10);
const endStr = r.event_end_date || r.event_start_date;
const isOngoing = r.event_start_date <= todayStr2 && endStr >= todayStr2;
const cls = isOngoing ? 'badge-ongoing' : '';
dateBadge = `<div class="card-date-badge ${cls}">${isOngoing ? '● ' + UI.ongoing : '📅'} ${fmtEventDate(r.event_start_date, r.event_end_date)}</div>`;
}
// Badge prix WeeBnB / OTF ou min_price DB
const wbnbRental = weebnbData !== null ? (weebnbData[r['dc:identifier']] ?? null) : null;
const otfOffer = otfData !== null ? (otfData[r['dc:identifier']] ?? null) : null;
let priceBadge = '';
if (wbnbRental) {
if (wbnbRental.final_price != null && wbnbRental.final_price > 0) {
const nights = wbnbRental.nights ?? '';
const priceFrom = UI.price_from_badge || 'à partir de';
priceBadge = `<div class="price-badge weebnb-price"><span style="font-size:9px;font-weight:500;opacity:.85">${priceFrom}</span>${wbnbRental.final_price.toLocaleString(CURRENT_LANG)} ${wbnbRental.currency || 'EUR'}<span class="price-badge-sub">${nights ? nights + ' ' + (UI.weebnb_nights || 'nuit') + (nights > 1 ? 's' : '') : ''}</span></div>`;
} else {
priceBadge = `<div class="price-badge weebnb-price weebnb-na"><i class="fa-solid fa-calendar-check" style="font-size:.75rem"></i> ${UI.no_avail || 'Disponibilité à confirmer'}</div>`;
}
} else if (otfOffer) {
priceBadge = `<div class="price-badge weebnb-price weebnb-na"><i class="fa-solid fa-calendar-check" style="font-size:.75rem"></i> ${UI.no_avail || 'Disponibilité à confirmer'}</div>`;
} else if (r.min_price != null && weebnbData === null && otfData === null) {
priceBadge = `<div class="price-badge">dès ${r.min_price%1===0 ? r.min_price.toFixed(0) : r.min_price.toFixed(2)} €</div>`;
}
// Badge mise en avant
const featuredBadge = r.is_featured
//? `<div class="featured-badge">★ ${UI.featured || 'Coup de cœur'}</div>`
? ``
: '';
// CTA principal → toujours notre site
const wbnbBookUrl = wbnbRental?.booking_url ?? null;
const detailLabel = poiUrl ? UI.view_details.replace(' →','') : UI.learn_more;
const detailUrl = ctaUrl; // poiUrl ou fallback URL externe
const detailTarget = !poiUrl && urls[0] ? ' target="_blank" rel="noopener"' : '';
// Meta chips
let metaHTML = '<div class="hotel-meta">';
if (typeBadge) metaHTML += `<span>${esc(typeBadge)}</span>`;
if (r.stars) metaHTML += `<span>${'★'.repeat(r.stars)}</span>`;
if (tels[0]) metaHTML += `<span><i class="fas fa-phone"></i> ${esc(tels[0])}</span>`;
metaHTML += '</div>';
// Bouton "Réserver" WeeBnB séparé (seulement si booking_url disponible)
const wbnbBtnHTML = wbnbBookUrl
? `<a href="${esc(wbnbBookUrl)}" class="book-btn weebnb-book-btn" target="_blank" rel="noopener">${UI.book_now || 'Réserver'}</a>`
: '';
// Bouton "Réserver" OTF (affiché uniquement quand dates actives)
const otfBookUrl = otfOffer?.booking_url ?? null;
const otfBtnHTML = otfBookUrl
? `<a href="${esc(otfBookUrl)}" class="book-btn weebnb-book-btn otf-book-btn" target="_blank" rel="noopener">${UI.book_now || 'Réserver'}</a>`
: '';
return `
<div class="card" id="card-${i}" data-card-idx="${i}"
onmouseenter="hlMarker(${i},true)" onmouseleave="hlMarker(${i},false)">
<a href="${ctaUrl}" class="card-img-link"${detailTarget}>
<div class="card-img">
${imgHTML}${noImg}
${dateBadge}${priceBadge}${featuredBadge}
</div>
</a>
<div class="card-body">
${cityName ? `<div class="card-city">${esc(cityName)}</div>` : ''}
${poiUrl
? `<a href="${poiUrl}" class="card-title-link"><h2 class="card-title">${hl(name)}</h2></a>`
: `<h2 class="card-title">${hl(name)}</h2>`}
${dsc ? `<p class="card-desc">${hl(dsc)}</p>` : ''}
${metaHTML}
<a href="${detailUrl}" class="book-btn"${detailTarget}>${detailLabel}</a>
${wbnbBtnHTML}
${otfBtnHTML}
</div>
</div>`;
}
function catFAIcon(cat) {
const lbl2 = (cat?.label || '').toLowerCase();
if (lbl2.includes('hberg') || lbl2.includes('hotel') || lbl2.includes('gîte') || lbl2.includes('camping')) return 'fa-bed';
if (lbl2.includes('restaurant') || lbl2.includes('gastro') || lbl2.includes('bistro')) return 'fa-utensils';
if (lbl2.includes('manifest') || lbl2.includes('event') || lbl2.includes('agenda')) return 'fa-calendar-day';
if (lbl2.includes('activit') || lbl2.includes('sport') || lbl2.includes('loisir')) return 'fa-bicycle';
return 'fa-map-marker-alt';
}
function fmtEventDate(start, end) {
if (!start) return '';
const months = UI.months_short;
const fmt = d => {
const [y,m,day] = d.split('-');
return `${parseInt(day)} ${months[parseInt(m)-1]} ${y}`;
};
if (!end || end===start) return fmt(start);
const [sy,sm]=start.split('-'), [ey,em]=end.split('-');
if (sy===ey && sm===em) {
const sd=parseInt(start.split('-')[2]), ed=parseInt(end.split('-')[2]);
return `${sd}–${ed} ${months[parseInt(sm)-1]} ${sy}`;
}
return `${fmt(start)} → ${fmt(end)}`;
}
// ─── Extracteurs ──────────────────────────────────────────────────────────────
function lbl(raw) {
if (!raw) return "";
if (typeof raw === "string") return raw;
return raw[CURRENT_LANG] || raw['@'+CURRENT_LANG] || raw.fr || raw["@fr"] || Object.values(raw)[0] || "";
}
function city(r) {
// Ton API renvoie directement "city" à la racine de l'objet ou dans isLocatedAt
return r.city || r.isLocatedAt?.[0]?.address?.[0]?.addressLocality || "";
}
function addr(r) {
// Ton API renvoie l'adresse dans cette structure précise
const addrObj = r.isLocatedAt?.[0]?.address?.[0] || r.isLocatedAt?.[0]?.address;
return addrObj?.streetAddress || "";
}
function zipCode(r) {
const addrObj = r.isLocatedAt?.[0]?.address?.[0] || r.isLocatedAt?.[0]?.address;
return addrObj?.postalCode || "";
}
function desc(r) { const d=r.hasDescription?.[0]; return lbl(d?.description)||lbl(d?.shortDescription)||""; }
function img(r) { const res=r.hasMainRepresentation?.[0]?.hasRelatedResource?.[0]; const loc=res?.locator; return Array.isArray(loc)?loc[0]:loc; }
function arr(v) { return Array.isArray(v)?v:(v?[v]:[]); }
// Formate une Date JS en YYYY-MM-DD en heure LOCALE (évite le décalage UTC)
function fmtLocalDate(d) {
const y = d.getFullYear();
const mo = String(d.getMonth() + 1).padStart(2, '0');
const da = String(d.getDate()).padStart(2, '0');
return `${y}-${mo}-${da}`;
}
function formatType(raw,catTypes) {
if (!raw) return "";
const types=Array.isArray(raw)?raw:[raw];
for (const t of catTypes) { if (types.includes(t)&&TYPE_LABELS[t]) return TYPE_LABELS[t]; }
return "";
}
function esc(s) { return String(s||"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""); }
function norm(s) { return String(s||"").toLowerCase().normalize("NFD").replace(/\p{Diacritic}/gu,""); }
function hl(text) {
const safe=esc(text); if (!searchQ) return safe;
const re=new RegExp(`(${searchQ.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")})`,"gi");
return safe.replace(re,"<mark>$1</mark>");
}
// ─── États UI ─────────────────────────────────────────────────────────────────
function showLoading() { document.getElementById("statsBar").innerHTML=""; document.getElementById("grid").innerHTML=`<div class="state"><div class="spinner"></div><p>${UI.loading}</p><p class="progress" id="progressMsg"></p></div>`; }
function setProgress(m) { const e=document.getElementById("progressMsg"); if(e) e.textContent=m; }
function showEmpty(cat) { document.getElementById("statsBar").innerHTML=""; document.getElementById("grid").innerHTML=`<div class="state"><div class="icon">${cat?.icon??"🔍"}</div><p>${UI.no_results} <strong>${esc(cat?.label??"")}</strong>.</p></div>`; }
function showError(msg) { document.getElementById("statsBar").innerHTML=""; document.getElementById("grid").innerHTML=`<div class="state"><div class="icon">⚠️</div><p><strong>${UI.error_title}</strong><br>${msg}</p></div>`; }
// ─── Événements ───────────────────────────────────────────────────────────────
// ─── Événements Optimisés ───────────────────────────────────────────────────
let filterTimeout;
let mapTimer;
let lastMapData = null;
function renderMapLazy(data) {
clearTimeout(mapTimer);
mapTimer = setTimeout(() => {
renderMap(data);
}, 120); // petit délai pour laisser respirer le UI
}
function debouncedFilter(delay = 300) {
clearTimeout(filterTimeout);
filterTimeout = setTimeout(() => {
searchQ = document.getElementById("searchInput").value.trim();
applyFilters();
}, delay);
}
// ─── Événements ──────────────────────────────────────────────────────────────
document.getElementById("searchInput")
.addEventListener("input", () => debouncedFilter(300));
document.getElementById("clearSearch")
.addEventListener("click", () => {
document.getElementById("searchInput").value = "";
searchQ = "";
applyFilters();
});
// ─── WeeBnB ───────────────────────────────────────────────────────────────────
async function loadWeebnb(checkin, checkout) {
if (!checkin || !checkout || weebnbLoading) return;
weebnbLoading = true;
weebnbCheckin = checkin;
weebnbCheckout = checkout;
// Indicateur sur la barre + spinner dans le grid si des cartes étaient déjà affichées
const wbBar = document.getElementById('weebnbBar');
if (wbBar) wbBar.classList.add('weebnb-loading');
const grid = document.getElementById('grid');
if (grid && allData.length > 0) {
grid.innerHTML = '<div class="state"><div class="spinner"></div><p>'
+ (UI.loading || 'Chargement…') + '</p></div>';
}
try {
const url = `/api/weebnb.php?territory=${encodeURIComponent(TERRITORY_SLUG)}&checkin=${checkin}&checkout=${checkout}&lang=${CURRENT_LANG}&persons=${personMin || 0}`;
const res = await fetch(url);
const json = await res.json();
if (json.error) throw new Error(json.error);
weebnbData = json.rentals ?? {};
otfData = json.otf_offers ?? {};
} catch(e) {
weebnbData = {};
otfData = {};
console.warn('WeeBnB:', e.message);
} finally {
weebnbLoading = false;
if (wbBar) wbBar.classList.remove('weebnb-loading');
}
// Sync boutons clear
const show = weebnbCheckin !== '';
document.getElementById('weebnbClearBtn')?.style.setProperty('display', show ? '' : 'none');
document.getElementById('mWeebnbClearBtn')?.style.setProperty('display', show ? '' : 'none');
applyFilters(false);
}
function clearWeebnb() {
weebnbData = null;
otfData = null;
weebnbCheckin = '';
weebnbCheckout = '';
document.getElementById('weebnbClearBtn')?.style.setProperty('display', 'none');
document.getElementById('mWeebnbClearBtn')?.style.setProperty('display', 'none');
// Reset flatpickr instances
document.getElementById('weebnbPicker')?._flatpickr?.clear();
document.getElementById('mWeebnbPicker')?._flatpickr?.clear();
applyFilters(false);
}
function updateWeebnbBar() {
const bar = document.getElementById('weebnbBar');
if (!bar) return;
bar.classList.toggle('weebnb-active', weebnbData !== null || otfData !== null);
}
// Init flatpickr WeeBnB
document.addEventListener('DOMContentLoaded', () => {
if (!HAS_WEEBNB) return;
const fpOpts = {
mode: 'range',
minDate: 'today',
dateFormat: 'Y-m-d',
altInput: true,
altFormat: 'd M Y',
disableMobile: true,
showMonths: window.innerWidth <= 640 ? 1 : 2,
onChange(dates) {
if (dates.length === 2) {
const ci = fmtLocalDate(dates[0]);
const co = fmtLocalDate(dates[1]);
loadWeebnb(ci, co);
}
},
};
const desk = document.getElementById('weebnbPicker');
const mob = document.getElementById('mWeebnbPicker');
if (desk) flatpickr(desk, fpOpts);
if (mob) flatpickr(mob, fpOpts);
// Restaure visuellement les dates dans le picker (l'appel API se fait depuis fetchCategory)
if (window._urlWbCheckin && window._urlWbCheckout) {
desk?._flatpickr?.setDate([window._urlWbCheckin, window._urlWbCheckout], false);
mob?._flatpickr?.setDate([window._urlWbCheckin, window._urlWbCheckout], false);
}
});
window.addEventListener("popstate", () => {
readUrlState();
renderCityList('cityDrop', 'citySearch', communes, false);
updateCityPickerLabel();
applyFilters(false);
});
// ─── Person picker ────────────────────────────────────────────────────────────
const PERSON_MAX = 10;
let _pStart = null, _pEnd = null, _pHover = null;
const _pCells = {};
function _buildPersonGrid() {
const grid = document.getElementById('personGrid');
if (!grid || grid.children.length > 0) return;
for (let i = 1; i <= PERSON_MAX; i++) {
const wrap = document.createElement('div');
wrap.className = 'p-cell';
wrap.dataset.n = i;
const dot = document.createElement('div');
dot.className = 'p-dot';
dot.textContent = i;
wrap.appendChild(dot);
grid.appendChild(wrap);
_pCells[i] = wrap;
wrap.onclick = () => {
if (_pStart === null || _pEnd !== null) {
_pStart = i; _pEnd = null;
} else {
_pEnd = i;
const mn = Math.min(_pStart, _pEnd);
const mx = Math.max(_pStart, _pEnd);
personMin = mn; personMax = mx;
_updatePersonBtn();
closePersonPicker();
applyFilters(false);
}
_renderPersonCells();
};
wrap.onmouseenter = () => { if (_pStart !== null && _pEnd === null) { _pHover = i; _renderPersonCells(); } };
}
grid.onmouseleave = () => { _pHover = null; _renderPersonCells(); };
}
function _renderPersonCells() {
const curMin = _pStart !== null ? ((_pEnd !== null ? Math.min(_pStart, _pEnd) : (_pHover !== null ? Math.min(_pStart, _pHover) : _pStart))) : null;
const curMax = _pStart !== null ? ((_pEnd !== null ? Math.max(_pStart, _pEnd) : (_pHover !== null ? Math.max(_pStart, _pHover) : _pStart))) : null;
for (let i = 1; i <= PERSON_MAX; i++) {
const el = _pCells[i]; if (!el) continue;
el.classList.remove('in-range','range-start','range-end','is-selected');
if (curMin !== null && curMax !== null && i >= curMin && i <= curMax) {
el.classList.add('in-range');
if (i === curMin) el.classList.add('range-start');
if (i === curMax) el.classList.add('range-end');
}
if (i === _pStart || i === _pEnd || (i === _pHover && _pEnd === null && _pStart !== null)) {
el.classList.add('is-selected');
}
}
const mn = _pStart !== null ? Math.min(_pStart, _pEnd ?? _pHover ?? _pStart) : null;
const mx = _pStart !== null ? Math.max(_pStart, _pEnd ?? _pHover ?? _pStart) : null;
const title = document.getElementById('personModalTitle');
if (title && mn !== null) {
const pl = UI.persons_plural || 'personnes', sg = UI.persons_single || 'personne';
title.textContent = mn === mx ? `${mn} ${mn > 1 ? pl : sg}` : `De ${mn} à ${mx} ${pl}`;
}
}
function _updatePersonBtn() {
const lbl = document.getElementById('personBtnLabel');
const btn = document.getElementById('personBtn');
if (!lbl) return;
if (personMin > 0) {
const pl = UI.persons_plural || 'personnes', sg = UI.persons_single || 'personne';
lbl.textContent = personMin === personMax || personMax === 0
? `${personMin} ${personMin > 1 ? pl : sg}`
: `${personMin}–${personMax} ${pl}`;
if (btn) btn.classList.add('active');
} else {
lbl.textContent = UI.persons || 'Personnes';
if (btn) btn.classList.remove('active');
}
}
function togglePersonPicker() {
_buildPersonGrid();
const ov = document.getElementById('personOverlay');
if (!ov) return;
if (ov.classList.contains('show')) { closePersonPicker(); }
else { ov.style.display='flex'; setTimeout(() => ov.classList.add('show'), 10); _renderPersonCells(); }
}
function closePersonPicker() {
const ov = document.getElementById('personOverlay');
if (!ov) return;
ov.classList.remove('show');
setTimeout(() => ov.style.display='none', 250);
}
function resetPersons() {
_pStart = null; _pEnd = null; personMin = 0; personMax = 0;
_updatePersonBtn();
_renderPersonCells();
closePersonPicker();
applyFilters(false);
}
document.addEventListener('keydown', e => { if (e.key === 'Escape') closePersonPicker(); });
</script>
<script>
// Header scroll + mise à jour hauteurs CSS
const headerEl = document.getElementById('catalogueHeader');
const toolbarEl = document.querySelector('.toolbar');
function syncLayoutHeights() {
const hh = headerEl ? Math.round(headerEl.getBoundingClientRect().height) : 65;
const th = toolbarEl ? Math.round(toolbarEl.getBoundingClientRect().height) : 56;
document.documentElement.style.setProperty('--header-h', hh + 'px');
document.documentElement.style.setProperty('--toolbar-h', th + 'px');
}
syncLayoutHeights();
if (typeof ResizeObserver !== 'undefined' && headerEl) {
new ResizeObserver(syncLayoutHeights).observe(headerEl);
}
window.addEventListener('scroll', () => {
headerEl?.classList.toggle('scrolled', window.scrollY > 50);
syncLayoutHeights();
}, { passive: true });
// Fullscreen menu
document.getElementById('openMenu')?.addEventListener('click', () => {
document.getElementById('fullMenu').classList.add('is-open');
document.body.style.overflow = 'hidden';
});
document.getElementById('closeMenu')?.addEventListener('click', () => {
document.getElementById('fullMenu').classList.remove('is-open');
document.body.style.overflow = '';
});
</script>
</body>
</html>