/* BoatsFun — Page Catalogue (bateaux.html)
Grille complète des bateaux + filtres (recherche texte, type, capacité, fourchette de prix).
Consomme window.BFBoats (BOATS, TYPES) et réutilise Header/Footer partagés. */
(function () {
const { I, Photo } = window.BF;
const { BOATS, TYPES, TIME_SLOTS, getRegions, areCombinable, blockTotal, depositFor, startingPriceLabel } = window.BFBoats;
// Tranches de capacité
const CAPS = [
{ id: "all", label: "Toutes", min: 0, max: 999 },
{ id: "1-4", label: "1-4 pers", min: 1, max: 4 },
{ id: "5-8", label: "5-8 pers", min: 5, max: 8 },
{ id: "9-12", label: "9-12 pers",min: 9, max: 12 },
{ id: "13+", label: "13+ pers", min: 13, max: 999 }
];
const SORTS = [
{ id: "popular", label: "Recommandés" },
{ id: "price-asc", label: "Prix : moins cher au plus cher" },
{ id: "price-desc",label: "Prix : plus cher au moins cher" },
{ id: "cap-desc", label: "Capacité" }
];
// localStorage key pour persister la sélection combinée entre catalogue ↔ checkout
const COMBINE_KEY = "bf.combine.selection";
function loadSelection() {
try { return JSON.parse(localStorage.getItem(COMBINE_KEY)) || { slugs: [], ctx: {} }; }
catch (e) { return { slugs: [], ctx: {} }; }
}
function saveSelection(data) {
try { localStorage.setItem(COMBINE_KEY, JSON.stringify(data)); } catch (e) {}
}
const styles = `
.bf .cat-hero { background:linear-gradient(180deg, #002244 0%, #003a66 100%); color:#fff; padding:64px 0 56px; }
.bf .cat-hero .eyebrow { color:var(--teal); }
.bf .cat-hero h1 { font-family:'Poppins', sans-serif; font-size:48px; line-height:1.1; font-weight:800; color:#fff; margin:14px 0 14px; letter-spacing:-1.2px; }
.bf .cat-hero p.lead { font-size:17px; line-height:1.55; color:rgba(255,255,255,.82); max-width:640px; }
.bf .cat-hero .ch-meta { display:flex; gap:18px; margin-top:22px; flex-wrap:wrap; color:rgba(255,255,255,.7); font-size:13.5px; }
.bf .cat-hero .ch-meta span { display:inline-flex; align-items:center; gap:8px; }
.bf .cat-hero .ch-meta svg { color:var(--teal); width:16px; height:16px; }
/* Bloc filtres */
.bf .cat-filters { background:#fff; border:1px solid var(--hair); border-radius:18px; box-shadow:0 8px 24px -16px rgba(0,34,68,.18); padding:18px 20px; margin-top:-36px; position:relative; z-index:2; }
.bf .cf-row { display:grid; grid-template-columns: 1.6fr 1fr 1fr 1fr 1fr; gap:14px; align-items:end; }
.bf .cf-row-2 { display:grid; grid-template-columns: 1fr auto; gap:14px; align-items:center; margin-top:14px; }
.bf .cf-field { display:flex; flex-direction:column; gap:6px; min-width:0; }
.bf .cf-field label { font-family:'Inter', sans-serif; font-size:11.5px; font-weight:700; letter-spacing:1.4px; text-transform:uppercase; color:var(--muted); }
.bf .cf-search { display:flex; align-items:center; gap:10px; background:var(--sea-mist); border:1px solid var(--hair); border-radius:12px; padding:10px 14px; }
.bf .cf-search svg { color:var(--navy); width:18px; height:18px; flex-shrink:0; }
.bf .cf-search input { flex:1; background:transparent; border:none; outline:none; font-family:'Inter', sans-serif; font-size:14.5px; color:var(--navy); min-width:0; }
.bf .cf-search input::placeholder { color:var(--muted); }
.bf .cf-select { background:var(--sea-mist); border:1px solid var(--hair); border-radius:12px; padding:11px 14px; font-family:'Inter', sans-serif; font-size:14px; color:var(--navy); font-weight:500; outline:none; cursor:pointer; appearance:none; background-image:url("data:image/svg+xml;utf8,"); background-repeat:no-repeat; background-position:right 14px center; padding-right:38px; }
.bf .cf-reset { background:transparent; border:none; color:var(--muted); font-family:'Inter', sans-serif; font-weight:600; font-size:13px; cursor:pointer; padding:12px 4px; white-space:nowrap; transition:color .15s; }
.bf .cf-reset:hover { color:var(--orange); }
.bf .cf-input { background:var(--sea-mist); border:1px solid var(--hair); border-radius:12px; padding:11px 14px; font-family:'Inter', sans-serif; font-size:14px; color:var(--navy); font-weight:500; outline:none; width:100%; min-width:0; }
.bf .cf-input::placeholder { color:var(--muted); }
/* Combiner toggle */
.bf .cf-combine { display:flex; align-items:flex-start; gap:14px; background:linear-gradient(135deg, #002244 0%, #003a66 100%); color:#fff; border-radius:14px; padding:14px 18px; }
.bf .cf-combine .ccb-text { flex:1; min-width:0; }
.bf .cf-combine .ccb-text strong { display:block; font-family:'Inter', sans-serif; font-weight:700; font-size:14px; letter-spacing:.01em; color:#fff; }
.bf .cf-combine .ccb-text span { display:block; font-size:12.5px; color:rgba(255,255,255,.72); margin-top:3px; line-height:1.4; }
.bf .cf-combine .ccb-switch { position:relative; width:46px; height:26px; flex-shrink:0; cursor:pointer; }
.bf .cf-combine .ccb-switch input { position:absolute; opacity:0; width:0; height:0; }
.bf .cf-combine .ccb-track { position:absolute; inset:0; background:rgba(255,255,255,.22); border-radius:999px; transition:background .2s; }
.bf .cf-combine .ccb-thumb { position:absolute; top:3px; left:3px; width:20px; height:20px; background:#fff; border-radius:50%; transition:transform .2s; }
.bf .cf-combine.is-on .ccb-track { background:var(--orange); }
.bf .cf-combine.is-on .ccb-thumb { transform:translateX(20px); }
/* Combine bar (sticky bottom) */
.bf .combine-bar { position:fixed; bottom:18px; left:50%; transform:translate(-50%, 120%); z-index:55; background:#002244; color:#fff; border-radius:16px; box-shadow:0 24px 60px -16px rgba(0,34,68,.5); padding:14px 18px; display:flex; align-items:center; gap:20px; min-width:min(680px, calc(100vw - 28px)); max-width:calc(100vw - 28px); transition:transform .3s ease; }
.bf .combine-bar.is-visible { transform:translate(-50%, 0); }
.bf .combine-bar .cb-info { flex:1; min-width:0; }
.bf .combine-bar .cb-count { font-family:'Inter', sans-serif; font-weight:700; font-size:15px; }
.bf .combine-bar .cb-count b { color:var(--teal); }
.bf .combine-bar .cb-meta { font-family:'Inter', sans-serif; font-size:12.5px; color:rgba(255,255,255,.7); margin-top:2px; }
.bf .combine-bar .cb-clear { background:transparent; border:1px solid rgba(255,255,255,.22); color:#fff; font-family:'Inter', sans-serif; font-size:12.5px; font-weight:600; padding:8px 14px; border-radius:999px; cursor:pointer; transition:all .15s; }
.bf .combine-bar .cb-clear:hover { background:rgba(255,255,255,.1); }
.bf .combine-bar .cb-cta { background:var(--orange); border:none; color:#fff; font-family:'Inter', sans-serif; font-weight:600; font-size:14px; padding:12px 22px; border-radius:999px; cursor:pointer; display:inline-flex; align-items:center; gap:8px; transition:all .2s; box-shadow:var(--cta-shadow-orange); white-space:nowrap; }
.bf .combine-bar .cb-cta:hover:not(:disabled) { background:#FF9420; transform:translateY(-2px); }
.bf .combine-bar .cb-cta:disabled { opacity:.45; cursor:not-allowed; }
/* Carte : bouton combiner + state sélectionné / désactivé */
.bf .cat-card .cc-combine-btn { width:100%; margin-top:10px; background:#fff; border:1.5px solid var(--navy); color:var(--navy); font-family:'Inter', sans-serif; font-weight:600; font-size:13px; padding:9px 12px; border-radius:999px; cursor:pointer; transition:all .18s; display:inline-flex; align-items:center; justify-content:center; gap:6px; }
.bf .cat-card .cc-combine-btn:hover { background:var(--navy); color:#fff; }
.bf .cat-card.is-selected { border-color:var(--orange); box-shadow:0 0 0 2px var(--orange) inset, 0 18px 40px -20px rgba(255,130,0,.35); }
.bf .cat-card.is-selected .cc-combine-btn { background:var(--orange); border-color:var(--orange); color:#fff; }
.bf .cat-card.is-incompatible { opacity:.55; }
.bf .cat-card.is-incompatible .cc-combine-btn { background:transparent; border-color:var(--hair); color:var(--muted); cursor:not-allowed; }
.bf .cat-card.is-incompatible .cc-combine-btn:hover { background:transparent; color:var(--muted); }
.bf .cat-card .cc-incompatible-note { font-size:11.5px; color:var(--muted); margin-top:6px; font-style:italic; }
/* Pills filtres (type) */
.bf .cat-pills { display:flex; gap:10px; flex-wrap:wrap; margin-top:14px; padding-top:14px; border-top:1px dashed var(--hair); }
.bf .cat-pill { background:#fff; border:1px solid var(--hair); border-radius:999px; padding:9px 18px; font-family:'Inter', sans-serif; font-size:13.5px; font-weight:600; color:var(--navy); cursor:pointer; transition:all .18s ease; }
.bf .cat-pill:hover { border-color:var(--navy); }
.bf .cat-pill.active { background:var(--navy); color:#fff; border-color:var(--navy); }
/* Toolbar : résultats + tri */
.bf .cat-toolbar { display:flex; justify-content:space-between; align-items:center; margin-top:32px; margin-bottom:18px; gap:14px; flex-wrap:wrap; }
.bf .cat-toolbar .ct-count { font-family:'Inter', sans-serif; font-size:14.5px; color:var(--body); }
.bf .cat-toolbar .ct-count b { color:var(--navy); font-weight:700; }
.bf .cat-toolbar .ct-sort { display:flex; align-items:center; gap:10px; font-family:'Inter', sans-serif; font-size:13.5px; color:var(--muted); }
/* Grille bateaux */
.bf .cat-section { padding:0 0 var(--section-pad); }
.bf .cat-grid { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:22px; }
.bf .cat-card { display:flex; flex-direction:column; background:#fff; border:1px solid var(--hair); border-radius:18px; overflow:hidden; text-decoration:none; color:inherit; transition:transform .25s ease, box-shadow .25s ease, border-color .25s ease; }
.bf .cat-card:hover { transform:translateY(-4px); box-shadow:0 18px 40px -20px rgba(0,34,68,.22); border-color:transparent; }
.bf .cat-card .cc-imgwrap { position:relative; aspect-ratio:16/11; overflow:hidden; background:var(--sea-mist); }
.bf .cat-card .cc-imgwrap img { width:100%; height:100%; object-fit:cover; display:block; transition:transform .5s ease; }
.bf .cat-card:hover .cc-imgwrap img { transform:scale(1.05); }
.bf .cat-card .cc-badges { position:absolute; top:12px; left:12px; display:flex; gap:6px; flex-wrap:wrap; }
.bf .cat-card .cc-badge { background:#fff; color:var(--navy); font-family:'Inter', sans-serif; font-size:11px; font-weight:700; letter-spacing:.04em; text-transform:uppercase; padding:5px 10px; border-radius:999px; box-shadow:0 2px 6px rgba(0,34,68,.15); }
.bf .cat-card .cc-badge.is-orange { background:var(--orange); color:#fff; }
.bf .cat-card .cc-type { position:absolute; bottom:12px; right:12px; background:rgba(0,34,68,.85); color:#fff; backdrop-filter:blur(8px); font-family:'Inter', sans-serif; font-size:11.5px; font-weight:600; padding:5px 11px; border-radius:999px; }
.bf .cat-card .cc-body { padding:18px 20px 20px; display:flex; flex-direction:column; gap:8px; flex:1; }
.bf .cat-card h3 { font-family:'Poppins', sans-serif; font-size:18px; font-weight:700; color:var(--navy); line-height:1.25; letter-spacing:-.3px; }
.bf .cat-card .cc-loc { display:inline-flex; align-items:center; gap:6px; font-size:13.5px; color:var(--body); }
.bf .cat-card .cc-loc svg { width:14px; height:14px; color:var(--teal); }
.bf .cat-card .cc-meta { display:flex; gap:14px; margin-top:4px; font-size:13px; color:var(--muted); }
.bf .cat-card .cc-meta span { display:inline-flex; align-items:center; gap:5px; }
.bf .cat-card .cc-meta svg { width:13px; height:13px; }
.bf .cat-card .cc-foot { display:flex; justify-content:space-between; align-items:center; margin-top:auto; padding-top:14px; border-top:1px dashed var(--hair); }
.bf .cat-card .cc-price { font-family:'Poppins', sans-serif; font-size:20px; font-weight:700; color:var(--navy); }
.bf .cat-card .cc-price .pu { font-family:'Inter', sans-serif; font-size:12.5px; font-weight:500; color:var(--muted); margin-left:3px; }
.bf .cat-card .cc-cta { font-family:'Inter', sans-serif; font-size:13px; font-weight:600; color:var(--orange); display:inline-flex; align-items:center; gap:6px; transition:gap .2s ease; }
.bf .cat-card:hover .cc-cta { gap:10px; }
.bf .cat-card .cc-cta svg { width:14px; height:14px; }
/* Empty state */
.bf .cat-empty { text-align:center; padding:80px 24px; background:#fff; border:1px dashed var(--hair); border-radius:18px; }
.bf .cat-empty h3 { font-family:'Poppins', sans-serif; font-size:22px; color:var(--navy); margin-bottom:8px; }
.bf .cat-empty p { color:var(--body); margin-bottom:18px; }
/* ============ Responsive ============ */
@media (max-width: 1180px) {
.bf .cat-grid { grid-template-columns:repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 1180px) {
.bf .cf-row { grid-template-columns: 1fr 1fr 1fr; }
.bf .cf-row .cf-search-field { grid-column: 1 / -1; }
}
@media (max-width: 1024px) {
.bf .cat-hero h1 { font-size:40px; }
.bf .cf-row { grid-template-columns: 1fr 1fr; }
.bf .cf-row-2 { grid-template-columns: 1fr; }
}
@media (max-width: 860px) {
.bf .cat-hero { padding:48px 0 56px; }
.bf .cat-hero h1 { font-size:32px; }
.bf .cat-hero p.lead { font-size:15.5px; }
.bf .cat-filters { margin-top:-28px; padding:16px; }
.bf .cf-row { grid-template-columns: 1fr; gap:12px; }
.bf .cat-pill { padding:8px 14px; font-size:13px; }
.bf .cat-grid { grid-template-columns:1fr; gap:18px; }
.bf .cat-toolbar { margin-top:24px; }
.bf .combine-bar { left:14px; right:14px; transform:translate(0, 120%); min-width:0; flex-direction:column; align-items:stretch; gap:12px; padding:14px; }
.bf .combine-bar.is-visible { transform:translate(0, 0); }
.bf .combine-bar .cb-cta { width:100%; justify-content:center; }
.bf .combine-bar .cb-clear { align-self:flex-end; }
}
@media (max-width: 500px) {
.bf .cat-hero h1 { font-size:27px; }
.bf .cat-hero p.lead { font-size:14.5px; }
.bf .cat-card .cc-body { padding:16px; }
.bf .cat-card h3 { font-size:16.5px; }
}
`;
function BoatCard({ b, combineMode, isSelected, isCompatible, incompatibleReason, onToggleSelect }) {
const href = `/bateau?id=${encodeURIComponent(b.slug)}`;
const cardClass = [
"cat-card",
combineMode && isSelected ? "is-selected" : "",
combineMode && !isCompatible ? "is-incompatible" : ""
].filter(Boolean).join(" ");
const handleCombineClick = (e) => {
e.preventDefault();
e.stopPropagation();
if (!isCompatible) return;
onToggleSelect(b.slug);
};
return (
{b.type}
{b.name}
Pontons, yachts, voiliers, speedboats. Réservez en quelques clics ou faites une offre — dépôt 100 % remboursable si le propriétaire refuse.
Essayez d'élargir votre recherche ou de réinitialiser les filtres.