/*!
 * ============================================================================
 *  esperienze.css — Modulo "Esperienze" (listing + dettaglio)
 *
 *  Cosa contiene:
 *    - Stili migrati dai blocchi <style> inline di esperienze.php
 *    - Classi sostitutive degli style="..." inline (Separation of Concerns)
 *    - Skeleton loader, mappa Leaflet, popup, empty state, sidebar mobile,
 *      footer sticky, sort bar mobile, dettaglio esperienza
 *
 *  Convenzioni:
 *    - Tutte le classi specifiche del modulo usano il prefisso `esp-` o
 *      `esperienze-` per evitare collisioni col CSS globale (main.css).
 *    - Le regole "scoped" alla pagina usano `body.esperienze-page` come
 *      ancora di scoping: la classe è iniettata da esperienze.php /
 *      esperienza.php subito dopo l'apertura del body (vedi inline script).
 *    - Niente !important salvo override forzati su utility globali in
 *      media query mobile (empty state).
 *
 *  Inclusione:
 *    - Caricato condizionalmente da templates/header.html via il placeholder
 *      {{extra_head}}, popolato in header.php solo quando `$is_esperienze_page`
 *      o `$is_esperienze_detail_page` è true. In altre route NON viene mai
 *      richiesto: zero overhead.
 * ============================================================================
 */


/* ----------------------------------------------------------------------------
 *  Step 147 — Filtro categorie client-side (OR piatto)
 *
 *  Classe applicata dalle card che NON soddisfano l'intersezione fra le
 *  categorie spuntate nella sidebar e gli ID dichiarati su `data-categorie`.
 *  Comportamento identico a `.d-none` ma con namespace dedicato per evitare
 *  collisioni con il filtro prezzo (`.d-none`) e l'availability check
 *  (`.is-unavailable`). Ogni filtro è "owner" della propria classe e non
 *  tocca quelle altrui (Single Responsibility per i side effect DOM).
 * -------------------------------------------------------------------------- */
.js-esp-card.d-none-by-cat,
.js-esp-card.d-none-by-filter {
	display: none !important;
}

/* ----------------------------------------------------------------------------
 *  1. SKELETON LOADER (esperienze.php → AJAX placeholder)
 *  Usato per dare feedback "sta caricando" finché l'AJAX non ritorna gli
 *  item del listing. Lo shimmer è una banda diagonale che attraversa
 *  ciclicamente la box; durata 1.4s pensata per non distrarre.
 * -------------------------------------------------------------------------- */
.skeleton-box,
.skeleton-line {
	position: relative;
	overflow: hidden;
	background: #eef0f2;
}

.skeleton-box::after,
.skeleton-line::after {
	content: "";
	position: absolute;
	inset: 0;
	transform: translateX(-100%);
	background: linear-gradient(90deg, rgba(238, 240, 242, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(238, 240, 242, 0) 100%);
	animation: shimmer 1.4s infinite;
}

.skeleton-line {
	height: 12px;
	border-radius: 6px;
	margin-bottom: 12px;
}

.skeleton-title { height: 18px; width: 80%; }
.skeleton-price { width: 45%; margin-top: auto; }
.skeleton-button { height: 40px; width: 100%; margin-bottom: 0; }

@keyframes shimmer {
	100% { transform: translateX(100%); }
}


/* ----------------------------------------------------------------------------
 *  2. MAPPA ESPERIENZE — Leaflet container (.esperienze-map-container)
 *  Quando la mappa è attiva nella colonna risultati deve occupare una porzione
 *  verticale rilevante (come un listing). Uso calc(100vh - offset header)
 *  per avere un'altezza utile anche su schermi molto lunghi, con un minimo
 *  per garantire leggibilità su laptop bassi.
 * -------------------------------------------------------------------------- */
.esperienze-map-container {
	width: 100%;
	height: calc(100vh - 220px);
	min-height: 520px;
	z-index: 1;
}
@media (max-width: 991.98px) {
	.esperienze-map-container {
		height: calc(100vh - 180px);
		min-height: 420px;
	}
}


/* ----------------------------------------------------------------------------
 *  3. POPUP LEAFLET (aderiscono al design-system esistente)
 *  Non vogliamo lo stile "fumetto" default Leaflet: lo allineiamo alla
 *  hotelsCard del progetto (rounded, shadow, font del design system).
 * -------------------------------------------------------------------------- */
.leaflet-popup-content-wrapper {
	border-radius: 8px;
	padding: 0;
	box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.leaflet-popup-content {
	margin: 0;
	width: 230px !important;
}
.esp-map-popup {
	display: block;
	color: inherit;
	text-decoration: none;
}
.esp-map-popup__image {
	width: 100%;
	height: 110px;
	object-fit: cover;
	border-top-left-radius: 8px;
	border-top-right-radius: 8px;
	background: #eef0f2;
}
.esp-map-popup__body {
	padding: 10px 12px 12px;
}
.esp-map-popup__title {
	font-size: 14px;
	font-weight: 700;
	line-height: 1.2;
	color: #1a1a1a;
	margin: 0 0 4px;
}
.esp-map-popup__meta {
	font-size: 12px;
	color: #6b7785;
	margin: 0 0 6px;
}
.esp-map-popup__price {
	font-size: 14px;
	font-weight: 700;
	color: #e94e1b;
}

/* Wrapper zero-size per L.divIcon: ancoraggio lat/lng sul vertice "pin" (in basso). */
.esp-leaflet-marker-outer {
	position: relative;
	width: 0;
	height: 0;
	overflow: visible;
}

/* Pin prezzo (stile booking / Airbnb) — marker interattivo sulla mappa. */
.esp-price-marker {
	position: absolute;
	left: 0;
	bottom: 0;
	white-space: nowrap;
	box-sizing: border-box;
	background-color: #ffffff;
	color: #333333;
	font-weight: 700;
	font-size: 14px;
	line-height: 1.2;
	border: 1px solid rgba(0, 0, 0, 0.1);
	border-radius: 20px;
	padding: 5px 10px;
	box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
	cursor: pointer;
	z-index: 1;
	-webkit-tap-highlight-color: transparent;
	transform: translate(-50%, 0);
}

.esp-price-marker--info {
	font-weight: 700;
}

.esp-price-marker:hover,
.esp-price-marker:focus-visible {
	color: #e94e1b;
	border-color: rgba(233, 78, 27, 0.45);
	box-shadow: 0 3px 8px rgba(0, 0, 0, 0.22);
}

#esperienze-map .leaflet-marker-icon {
	/* Elide il clip del box 0×0 sui divIcon con pillola più larga dell’ancora. */
	overflow: visible !important;
}

/* Cluster Marker (Leaflet.markercluster): colori brand per coerenza UI. */
#esperienze-map .marker-cluster-small,
#esperienze-map .marker-cluster-medium,
#esperienze-map .marker-cluster-large {
	background-color: rgba(233, 78, 27, 0.24);
}

#esperienze-map .marker-cluster-small div,
#esperienze-map .marker-cluster-medium div,
#esperienze-map .marker-cluster-large div {
	background-color: #e94e1b;
	color: #ffffff;
	font-weight: 700;
}


/* ----------------------------------------------------------------------------
 *  4. EMPTY STATE (Step 24 - Task C)
 *  Box centrato con icona, titolo e CTA. Replica il pattern Vacanze/Offerte
 *  mantenendo coerenza tipografica e di shadow.
 * -------------------------------------------------------------------------- */
.esp-empty-state {
	max-width: 560px;
	margin: 0 auto;
}
.esp-empty-state__icon img {
	opacity: 0.85;
}
.esp-empty-map-placeholder {
	max-width: 420px;
	margin-left: auto;
	margin-right: auto;
}


/* ----------------------------------------------------------------------------
 *  5. FOOTER STICKY BOTTOM (Step 24 - Task A3)
 *  Su pagine con pochi risultati il footer "saltava" verso l'alto.
 *  Promuoviamo <main> a flex column con min-height 100vh: il footer,
 *  ultimo figlio, viene spinto a fondo pagina con margin-top:auto.
 *
 *  Scoping su `body.esperienze-page` per non impattare altre route che
 *  condividono lo stesso templates/header.html. La classe è aggiunta da
 *  un inline script al primo paint (vedi esperienze.php / esperienza.php).
 * -------------------------------------------------------------------------- */
body.esperienze-page main {
	display: flex;
	flex-direction: column;
	min-height: 100vh;
}
body.esperienze-page main > footer {
	margin-top: auto;
}


/* ----------------------------------------------------------------------------
 *  6. SIDEBAR MOBILE OFFCANVAS (Step 24 - Task A1)
 *  La logica di toggle è già in main.js (FiltriSwitch + classe
 *  filtro-display-none). Qui aggiungiamo solo il body-scroll-lock UX
 *  quando il sidebar overlay è aperto su mobile.
 * -------------------------------------------------------------------------- */
@media (max-width: 479.98px) {
	body.esperienze-page:has(#filtro_spalla_form_contenitore:not(.filtro-display-none)) {
		overflow: hidden;
	}
	/* Empty state più compatto su mobile (override forzato del pattern desktop) */
	.esp-empty-state { padding: 20px !important; }
	.esp-empty-state h3 { font-size: 18px !important; }
	.esp-empty-state p { font-size: 14px !important; }
}


/* ============================================================================
 *  7. UTILITY CLASSES (rimpiazzo dei vecchi style="..." inline)
 *  Estratte dai PHP (esperienze.php / esperienza.php) per Separation of
 *  Concerns. Usiamo prefisso `esp-` per non collidere con utility globali.
 * ============================================================================ */

/* 7a. Mobile filter top bar (#mappa-filtri-mobile) ------------------------- */
/*
 * La barra è split 50/50 (mappa | filtri). La metà sinistra ha un border
 * verticale per separare visivamente i due controlli; la destra no perché
 * confina con il bordo destro della viewport.
 */
.esp-mobile-bar__half {
	width: 50%;
}
.esp-mobile-bar__half--bordered {
	border-right: 1px solid rgba(0, 0, 0, 0.2);
}
/*
 * Pill "Nessuna mappa": variant non interattiva del pulsante mappa,
 * mostrata quando i risultati non hanno coordinate geografiche valide.
 */
.esp-mobile-bar__disabled-pill {
	opacity: 0.55;
}


/* 7b. Sort bar mobile (#risultati-mobile) ---------------------------------- */
/*
 * Wrapper full-width per il <select> nativo + label "Ordina per:".
 * `white-space: nowrap` impedisce che la label vada a capo su schermi
 * piccoli (340-380px) lasciando spazio sufficiente al control select.
 */
.esp-sort-mobile__wrapper {
	width: 100%;
}
.esp-sort-mobile__label {
	white-space: nowrap;
	margin-bottom: 0;
}

/*
 * Allineamento verticale barra "Ordina per" (desktop + mobile):
 * titolo e controlli devono stare sulla stessa linea centrale.
 */
body.esperienze-page #risultati-desk .d-flex.gap-1 {
	align-items: center;
}

body.esperienze-page #risultati-desk .d-flex.gap-1 h3 {
	margin-bottom: 0;
}

body.esperienze-page #risultati-desk .list-sort-select {
	display: inline-flex;
	align-items: center;
}

body.esperienze-page #risultati-mobile .esp-sort-mobile__wrapper {
	align-items: center !important;
}


/* 7c. Card listing — small price suffix (a destra) ------------------------ */
/*
 * I `<small>` sotto il prezzo o il "Prezzo su richiesta" devono essere
 * allineati a destra, coerenti con la colonna prezzo. Centralizziamo qui
 * sia per il render server-side che per il template HTML del JS AJAX.
 */
.esp-card__price-suffix {
	display: block;
	text-align: right;
	color: #6c757d;
	font-size: 12px;
	font-weight: 700;
	line-height: 1.25;
	text-decoration: none !important;
}

/*
 * Layout prezzo card con date attive:
 * data sopra, prezzo sotto, entrambi allineati a sinistra (colonna).
 * Lo stesso layout è usato in SSR (skeleton) e dopo update JS, azzerando CLS.
 */
.esp-card-price--split {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 2px;
	width: 100%;
}

.esp-card-price__dates {
	color: #6c757d;
	font-size: 12px;
	line-height: 1.25;
	font-weight: 700;
}

/*
 * Step 115/116 hardening:
 * se rimane markup legacy con .esp-card-price__dates dentro il blocco prezzo
 * della card, lo nascondiamo. La data corretta resta quella a sinistra con icona.
 */
.js-esp-card-price .esp-card-price__dates {
	display: none !important;
}

.esp-card-price__total {
	text-align: left;
	line-height: 1.1;
}

/*
 * Prezzo totale (ricerca con date): colore arancione brand, bold, font leggermente
 * più grande. La sottolineatura è solo su :hover per non appesantire il riposo visivo.
 */
.esp-price-total-val {
	display: inline-block;
	color: #e65100;
	font-size: 22px;
	font-weight: 700;
	text-decoration: none;
}

.js-esp-card:hover .esp-price-total-val,
.esp-price-total-val:hover {
	text-decoration: underline;
	text-decoration-thickness: 2px;
	text-decoration-color: #e65100;
	text-underline-offset: 4px;
}

/*
 * Step 82 / 155 - Landing categorie:
 * 4 colonne fisse (1/4 ciascuna): con 1–3 card non si allargano a riempire la riga.
 */
body.esperienze-page .esp-category-card-grid {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 30px;
	width: 100%;
}

body.esperienze-page .esp-category-card-grid__item {
	min-width: 0;
	max-width: 100%;
	display: flex;
}

@media (max-width: 1199px) {
	body.esperienze-page .esp-category-card-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

@media (max-width: 991px) {
	body.esperienze-page .esp-category-card-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 575px) {
	body.esperienze-page .esp-category-card-grid {
		grid-template-columns: minmax(0, 1fr);
	}
}

body.esperienze-page .esp-category-card-grid .js-esp-category-card-link {
	width: 100%;
}

/*
 * Step 78 - Card categorie:
 * manteniamo tutte le card della griglia alla stessa altezza e tronchiamo
 * la descrizione a 4 righe per evitare sfalsamenti visivi tra colonne.
 */
body.esperienze-page .js-esp-category-card-link .hotelsCard__content {
	min-height: 0;
}

body.esperienze-page .esp-category-card__body {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	min-height: 0;
}

body.esperienze-page .esp-category-card__desc {
	display: -webkit-box;
	-webkit-line-clamp: 4;
	-webkit-box-orient: vertical;
	overflow: hidden;
	text-overflow: ellipsis;
	margin-bottom: 0;
}

/*
 * Step 79 - Clamp titolo card categoria su viewport piccoli:
 * riduce le differenze verticali quando il titolo e lungo.
 */
@media (max-width: 991px) {
	body.esperienze-page .esp-category-card__title {
		display: -webkit-box;
		-webkit-line-clamp: 2;
		-webkit-box-orient: vertical;
		overflow: hidden;
		text-overflow: ellipsis;
		min-height: calc(1.2em * 2);
	}
}

body.esperienze-page .esp-single-card-item .esp-card__categoria-icon {
	margin-top: 0.1em;
}

/*
 * Descrizione card listing: testo limitato a 3 righe con ellissi
 * (stesso schema blocchi mh-19 di Vacanze/box.html).
 */
body.esperienze-page .esp-single-card-item .esp-card__descrizione {
	margin-bottom: 0;
	overflow: hidden;
	word-wrap: break-word;
	overflow-wrap: anywhere;
	white-space: normal;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 3;
	line-clamp: 3;
	text-overflow: ellipsis;
}

/* 7d. Badge informativi card listing -------------------------------------- */
body.esperienze-page .esp-single-card-item .esp-card__badges {
	display: flex;
	flex-direction: column;
	gap: 6px;
	width: 100%;
}

body.esperienze-page .esp-single-card-item .esp-card__badge {
	display: flex;
	align-items: flex-start;
	gap: 8px;
	padding: 0;
	border: none;
	background: transparent;
	color: #00000099;
	font-size: 13px;
	font-weight: 500;
	line-height: 1.3;
	max-width: 100%;
}

body.esperienze-page .esp-single-card-item .esp-card__badge-check {
	margin-top: 2px;
}

body.esperienze-page .esp-single-card-item .esp-card__badge-label {
	flex: 1;
	min-width: 0;
}


/* 7d. Accordion content full-height ---------------------------------------- */
/*
 * Le checkbox-list dei filtri, quando l'accordion è aperto (.is-active),
 * devono poter espandere il contenuto senza tagli. Non applicare
 * max-height:100% con lo stato chiuso: altrimenti i pannelli restano
 * sempre aperti (regola .accordion__content { max-height:0 } in main.css).
 */
.accordion__item.is-active .esp-accordion-content--full {
	max-height: 100% !important;
}

/* 7e. Filtri sidebar — allineamento checkbox + label (asse Y) -------------- */
/*
 * Riga "custom checkbox" + testo: flex centra il box e la label senza
 * dipendere da margini verticali incoerenti (.mb-1, .ml-10) sul tema globale.
 */
body.esperienze-page .esp-filtro-checkbox-row {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	flex-wrap: nowrap;
	margin-bottom: 0;
}
body.esperienze-page .esp-filtro-checkbox-row .form-checkbox {
	flex-shrink: 0;
}
body.esperienze-page .esp-filtro-checkbox-row label.text-14 {
	margin-left: 0 !important;
	margin-bottom: 0;
	line-height: 1.3;
}

body.esperienze-page .esp-filter-checkbox-item {
	margin-bottom: 0.75rem;
}

body.esperienze-page .esp-filter-checkbox-item:last-child {
	margin-bottom: 0;
}

/*
 * Accordion filtri sidebar:
 * icona sempre a destra, centrata verticalmente rispetto al titolo.
 */
body.esperienze-page #filtro_spalla_form_contenitore .accordion.-simple .esp-filter-accordion__button {
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: 100%;
}

body.esperienze-page #filtro_spalla_form_contenitore .accordion.-simple .esp-filter-accordion__button .accordion__icon {
	margin-left: auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 24px;
	min-height: 24px;
}

body.esperienze-page #filtro_spalla_form_contenitore .accordion.-simple .esp-filter-accordion__button .accordion__icon img {
	display: block;
}

/* 7f. Loading AJAX (filtri / ordinamento senza reload) --------------------- */
body.esperienze-page .esperienze-risultati-dinamici.esperienze-ajax--loading {
	position: relative;
	min-height: 200px;
	pointer-events: none;
	opacity: 0.65;
	transition: opacity 0.2s ease;
}

/* 7g. Header/Footer categoria con descrizione espandibile ------------------- */
/*
 * Blocco informativo categoria preso dal layout storico di esp.html e
 * adattato al listing moderno: stessa gerarchia visiva ma senza inline style.
 *
 * Override: main.css forza `.container3 { min-height: 409px; }` per la ricerca
 * full-width — qui il contenuto è solo titolo/descrizione: senza questo reset
 * restano ~400px di fascia vuota sotto il titolo categoria.
 */
body.esperienze-page .esp-category-info-layout.container3 {
	min-height: 0;
}

body.esperienze-page .esp-category-info-block {
	margin: 1.5rem 0;
}

body.esperienze-page .esp-category-info {
	padding-top: 0.5rem;
}

body.esperienze-page .esp-category-info__title {
	margin: 0;
	font-size: 1.75rem;
	font-weight: 700;
	line-height: 1.25;
	color: #1f2937;
}

body.esperienze-page .esp-category-info__description-wrapper {
	overflow: hidden;
	transition: max-height 0.28s ease;
}

body.esperienze-page .esp-category-info__description-wrapper.is-collapsed {
	max-height: 7.5rem;
}

body.esperienze-page .esp-category-info__description-wrapper.is-expanded {
	max-height: 100rem;
}

body.esperienze-page .esp-category-info__description {
	margin: 0;
	padding-top: 0.5rem;
	line-height: 1.6;
	color: #3f3f46;
}

body.esperienze-page .esp-category-info__toggle-wrap {
	margin-top: 0.5rem;
	display: flex;
	justify-content: flex-end;
}

body.esperienze-page .esp-category-info__toggle {
	border: 0;
	background: transparent;
	padding: 0;
	color: #eb5305;
	font-weight: 700;
	text-decoration: underline;
	cursor: pointer;
}

body.esperienze-page .esp-category-info__toggle:hover,
body.esperienze-page .esp-category-info__toggle:focus {
	color: #d84b04;
	text-decoration: underline;
}

@media (max-width: 767px) {
	body.esperienze-page .esp-category-info__title {
		font-size: 1.375rem;
	}
}


/* ============================================================================
 *  8. DETTAGLIO ESPERIENZA (esperienza.php) — layout uniforme a offerta.php
 * ============================================================================ */

/*
 * Header esperienza: location label sopra il titolo principale.
 * line-height stretto allineato a offerta.php (style="line-height:15px;").
 */
.esp-detail__location-title {
	line-height: 15px;
}

/*
 * Colonna sinistra hero (col-12 col-lg): consente al testo lungo di andare a capo
 * senza spingere la colonna destra su una nuova riga.
 */
.esp-detail__header-main {
	min-width: 0;
	overflow-wrap: break-word;
	word-break: break-word;
}

.esp-detail__sintesi {
	max-width: 100%;
	overflow-wrap: break-word;
	word-wrap: break-word;
}

/*
 * Breadcrumb dettaglio esperienza: stesso comportamento delle pagine Offerte.
 * Link senza sottolineatura a riposo, sottolineati solo in hover/focus.
 */
body.esperienze-page .esp-detail-breadcrumbs a {
	color: inherit;
	text-decoration: none;
}

body.esperienze-page .esp-detail-breadcrumbs a:hover,
body.esperienze-page .esp-detail-breadcrumbs a:focus-visible {
	text-decoration: underline;
}

/*
 * Blocco prezzo desktop: testo allineato a destra tramite text-lg-end sul
 * contenitore (colonna destra), quindi non serve sovrascrivere qui.
 * Viene mantenuto per sicurezza sui browser che non supportano text-lg-end.
 */
@media (min-width: 992px) {
	.js-detail-price {
		text-align: right;
	}
}

/*
 * Utility justify-lg-end: non presente nel tema, necessaria per allineare
 * a destra il bottone Prenota e il blocco Condividi su desktop.
 */
@media (min-width: 992px) {
	.justify-lg-end {
		justify-content: flex-end !important;
	}
}

/*
 * Skeleton del prezzo nel dettaglio: stessa altezza del testo "text-20 fw-700".
 */
#esp-detail-price-desktop .esp-price-skeleton {
	display: inline-block;
	height: 28px;
	width: 120px;
}

/*
 * Container mappa Google Embed nel dettaglio esperienza.
 * min-height a 600px riproduce l'aspetto ratio dell'iframe Google.
 */
.esp-detail__map-embed {
	min-height: 325px;
}

/*
 * Slot vuoti della galleria dettaglio esperienza:
 * servono a mantenere la griglia a 5 celle senza duplicare foto.
 */
body.esperienze-page .empty-image-slot {
	background-color: #ffffff;
	width: 100%;
	height: 100%;
	display: block;
	border-radius: 8px;
	border: 1px solid #f3f3f3;
}

/*
 * Form ricerca Esperienze: le tre aree input devono avere larghezza uguale
 * in desktop, con bottone cerca in colonna separata.
 */
.ricerca-form-esperienze .ricerca-form-esperienze__main-search .button-grid {
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) min-content;
}

.ricerca-form-esperienze .ricerca-form-esperienze__field {
	min-width: 0;
}

/*
 * Step 59 - fix-transparent-date-box:
 * nel form Esperienze forziamo lo stesso "peso visivo" del modulo Offerte
 * (sfondo pieno + bordo neutro) per i tre box Destinazione/Date/Partecipanti.
 */
.ricerca-form-esperienze .searchMenu-loc.boxform,
.ricerca-form-esperienze .searchMenu-date.boxform,
.ricerca-form-esperienze .searchMenu-guests.boxform {
	background-color: #ffffff;
	border: 1px solid #0000004d;
	border-radius: 1rem;
}

.ricerca-form-esperienze .searchMenu-date__field > .bg-white {
	background-color: #ffffff !important;
}

.ricerca-form-esperienze .esp-date-display {
	color: #000000cc;
}

/* Sidebar tree condiviso (Destinazione + Categorie) */
.esp-sidebar-tree-row__inner {
	width: 100%;
	min-width: 0;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
}

.esp-sidebar-tree-row__label {
	flex: 1 1 auto;
	min-width: 0;
}

.esp-sidebar-tree-toggle {
	width: 1.25rem;
	height: 1.25rem;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	align-self: center;
	cursor: pointer;
	flex-shrink: 0;
	margin-left: auto;
}

.esp-sidebar-tree-toggle__icon {
	width: 1rem;
	height: 1rem;
	display: block;
}

.esp-sidebar-tree-children.is-collapsed,
.js-esp-cat-children.is-collapsed {
	display: none;
}

.esp-cat-tree {
	width: 100%;
}

.esp-cat-row__inner {
	width: 100%;
	min-width: 0;
}

.sidebar-categorie .esp-filtro-checkbox-row {
	align-items: flex-start;
}

.sidebar-categorie .esp-filtro-checkbox-row label {
	line-height: 1.35;
}

/* Filtro Destinazione ad albero (Stato → Regione → Località) */
.esp-geo-tree {
	width: 100%;
}

.esp-geo-row__inner {
	width: 100%;
	min-width: 0;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
}

.esp-geo-row__label {
	flex: 1 1 auto;
	min-width: 0;
}

.esp-geo-toggle {
	width: 1.25rem;
	height: 1.25rem;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	align-self: center;
	cursor: pointer;
	flex-shrink: 0;
	margin-left: auto;
}

.esp-geo-toggle__icon {
	width: 1rem;
	height: 1rem;
	display: block;
}

.esp-geo-children.is-collapsed {
	display: none;
}

.sidebar-destinazioni .esp-filtro-checkbox-row {
	align-items: flex-start;
}

.sidebar-destinazioni .esp-filtro-checkbox-row label {
	line-height: 1.35;
}

/*
 * Utility locali per il form Esperienze:
 * sostituiscono i precedenti `style="display:none"` e il close icon del datepicker.
 */
.esp-hidden-block {
	display: none;
}

.esp-search-date-close {
	float: right;
	margin-top: -15px;
}

.esp-date-display {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.esp-date-clear {
	margin-left: auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
}

.esp-pagination-actions {
	display: none;
	margin-top: 1.5rem;
	column-gap: 1rem;
	row-gap: 0.75rem;
	align-items: center;
	justify-content: center;
	flex-wrap: wrap;
}

/* ============================================================================
 *  9. AVAILABILITY CHECK UI STATES (Step 91)
 *  Classi gestite dal JS orchestrator post-chiamata API:
 *    .is-checking-availability → card in attesa della risposta live
 *    .is-unavailable           → card non disponibile per le date scelte
 *    .esp-price-skeleton       → placeholder animato nel blocco prezzo
 * ============================================================================ */

/*
 * Stato "in attesa risposta API":
 * abbassa leggermente l'opacità per segnalare che il prezzo non è ancora
 * confermato, senza nascondere la card (UX progressiva).
 * pointer-events disabilitato solo sul blocco prezzo per evitare click
 * su un prezzo ancora indefinito.
 */
.esp-single-card-item.is-checking-availability .js-esp-card-price {
	pointer-events: none;
}

/*
 * Skeleton del prezzo: occupa lo spazio del valore numerico con
 * la stessa animazione shimmer già usata per il listing AJAX (#1 in questo file).
 * L'altezza è tarata sul font-size del prezzo (text-20 = ~20px + padding).
 */
.esp-price-skeleton {
	display: block;
	height: 22px;
	width: 80px;
	border-radius: 4px;
	position: relative;
	overflow: hidden;
	background: #eef0f2;
	margin-bottom: 4px;
}

.esp-card-price--split .esp-price-skeleton {
	margin-bottom: 0;
}

.esp-price-skeleton::after {
	content: "";
	position: absolute;
	inset: 0;
	transform: translateX(-100%);
	background: linear-gradient(90deg, rgba(238, 240, 242, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(238, 240, 242, 0) 100%);
	animation: shimmer 1.4s infinite;
}

/*
 * Stato "non disponibile":
 * nasconde la card in modo accessibile. Usiamo display:none (non visibility:hidden)
 * perché vogliamo che la card non occupi spazio nel layout della griglia.
 * Il JS applica questa classe dopo aver ricevuto available=false dall'API.
 * !important necessario per override delle classi Bootstrap .d-flex/.d-block
 * già presenti sulle card.
 */
.esp-single-card-item.is-unavailable {
	display: none !important;
}


/* ============================================================================
 *  10. EMPTY STATE DINAMICO AVAILABILITY CHECK (Step 95)
 *  Mostrato dal JS quando tutte le card vengono nascoste dopo il check live.
 *  Riusa le classi .esp-empty-state esistenti (§4 in questo file) per coerenza
 *  visiva con l'empty state SSR (nessun risultato da server).
 * ============================================================================ */

/*
 * Contenitore: si allinea al ritmo verticale della griglia card (row y-gap-30).
 * max-width limitato per evitare che il testo si dilati su schermi molto larghi.
 */
.esp-dynamic-empty-state {
	width: 100%;
}

/* dates-virtual / bootstrap indice deferred: sidebar non interattiva finché il listing non è pronto */
#filtro_spalla_form_contenitore.esp-dates-virtual-pending {
	pointer-events: none;
	opacity: 0.55;
}

/* Indice deferred (virtual, >2500 risultati): blocca click sulle card SSR finché l'indice non è caricato */
body.esperienze-page #esperienze-risultati-dinamici.esp-listing-bootstrap-pending {
	pointer-events: none;
	opacity: 0.65;
}

/* Render card post-filtro: skeleton visibile, lista attenuata */
body.esperienze-page #offers-list.esp-filter-render-pending {
	opacity: 0.35;
	pointer-events: none;
}

body.esperienze-page #offers-skeleton:not(.d-none) + #offers-list.esp-filter-render-pending {
	min-height: 200px;
}

.esp-dynamic-empty-state .esp-empty-state {
	max-width: 520px;
}

/*
 * Animazione di ingresso: fade-in da 0 a opacity:1 in 250ms.
 * Appare solo quando il JS rimuove la classe .d-none, quindi l'animazione
 * scatta al momento giusto senza bisogno di logica JS aggiuntiva.
 */
@keyframes espEmptyStateFadeIn {
	from { opacity: 0; transform: translateY(8px); }
	to   { opacity: 1; transform: translateY(0); }
}

.esp-dynamic-empty-state:not(.d-none) .esp-empty-state {
	animation: espEmptyStateFadeIn 0.25s ease both;
}

/*
 * Icona calendario: visivamente coerente con gli empty state del progetto
 * (§4 usa img width=48; qui 52px per dare più respiro al contenuto).
 */
.esp-dynamic-empty-state .esp-empty-state__icon img {
	opacity: 0.80;
}


/* ============================================================================
 *  11. BOOKING WIDGET DETTAGLIO ESPERIENZA (Step 93)
 *  Sticky panel desktop con date display, pax counter, prezzo live e CTA.
 *  Segue la stessa gerarchia visiva del listing card ma è ottimizzato
 *  per un'interazione puntuale (1 esperienza, 1 data range, 1+ adulti).
 * ============================================================================ */

.esp-detail-booking-widget {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 0.75rem;
	min-width: 240px;
}

/* 10a. Riga date -------------------------------------------------------------- */
.esp-detail-booking-widget__dates {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	font-size: 14px;
	color: #3f3f46;
}

.esp-detail-booking-widget__dates-label {
	font-weight: 600;
}

.esp-detail-booking-widget__dates-edit {
	color: #eb5305;
	text-decoration: underline;
	font-weight: 600;
	cursor: pointer;
}

.esp-detail-booking-widget__dates-edit:hover,
.esp-detail-booking-widget__dates-edit:focus {
	color: #d84b04;
}

/* 10b. Prezzo non disponibile ------------------------------------------------- */
.esp-detail__price-unavailable {
	color: #b91c1c;
	font-size: 15px;
}

/* 10c. CTA Prenota — stati disabilitato / verifica in corso ------------------- */
/*
 * .esp-detail-booking-widget__cta--checking è applicata:
 *   - da PHP al render SSR se ci sono date attive (prima che la fetch risponda)
 *   - dal JS durante la chiamata e se la risposta è "non disponibile"
 *
 * Usiamo opacity + pointer-events invece di disabled perché il tag è <a>,
 * non <button>: non supporta l'attributo HTML disabled nativo.
 * aria-disabled="true" garantisce l'accessibilità.
 */
.js-detail-prenota-btn.esp-detail-booking-widget__cta--checking,
.js-detail-prenota-btn[aria-disabled="true"] {
	opacity: 0.55;
	pointer-events: none;
	cursor: not-allowed;
}

/* Quick Facts dettaglio — griglia 2 colonne con check verde */
body.esperienze-page .esp-quick-facts {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 12px 32px;
	margin-top: 15px;
}

body.esperienze-page .esp-quick-fact-item {
	display: flex;
	align-items: flex-start;
	gap: 10px;
}

body.esperienze-page .esp-quick-fact-check {
	flex-shrink: 0;
	display: inline-block;
	width: 6px;
	height: 9px;
	margin-top: 3px;
	border-right: 2px solid var(--color-green-2);
	border-bottom: 2px solid var(--color-green-2);
	transform: rotate(45deg);
}

@media (max-width: 575px) {
	body.esperienze-page .esp-quick-facts {
		grid-template-columns: 1fr;
	}
}

/* Pallino stato conferma nei chip bianchi (istantanea / evasa su richiesta) */
.esp-chip-dot {
	flex-shrink: 0;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    margin-right: 5px;
}

.esp-chip-dot--green {
	background-color: var(--color-green-2);
}

.esp-chip-dot--orange {
	background-color: #eb5305;
}

@media (max-width: 991px) {
	/*
	 * In viewport piccoli la CTA desktop non deve creare overflow:
	 * prende tutta la larghezza disponibile come nel pattern mobile.
	 */
	.esp-detail__booking-button {
		width: 100%;
	}

	.ricerca-form-esperienze .ricerca-form-esperienze__main-search .button-grid {
		grid-template-columns: 1fr;
		row-gap: 1rem;
	}

	.ricerca-form-esperienze .ricerca-form-esperienze__field {
		width: 100%;
		margin: 0;
	}

	.ricerca-form-esperienze .searchMenu-loc.boxform,
	.ricerca-form-esperienze .searchMenu-date.boxform,
	.ricerca-form-esperienze .searchMenu-guests.boxform {
		width: 100%;
		min-height: 64px;
	}

	.ricerca-form-esperienze .button-item {
		width: 100%;
	}

	.ricerca-form-esperienze .button-item .mainSearch__submit {
		width: 100%;
		min-height: 64px;
	}
}
