.shop-sidebar {
	position: sticky;
	top: var(--header-height, 117px);
}
@media (max-width: 900px) {
	/* Was `position: static` — dumped the entire filter sidebar (4+ checkbox
	   groups) inline above the results, pushing the actual listings a full
	   screen or more below the fold on a phone. No real listing/travel site
	   does this; Klook/Traveloka/Agoda all tuck mobile filters behind a
	   "Bộ Lọc" button that opens a sheet. Now an off-canvas bottom sheet
	   instead, toggled by .shop-filter-toggle (in .shop-toolbar) via
	   main.js, same is-open/backdrop mechanism as the .main-navigation nav
	   drawer above. */
	.shop-sidebar {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 0;
		max-height: 85vh;
		overflow-y: auto;
		background: var(--color-bg);
		z-index: 1001;
		border-radius: 16px 16px 0 0;
		box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.18);
		padding: 18px 20px calc(20px + env(safe-area-inset-bottom, 0px));
		/* `translateY(100%)` (= 100% of THIS element's own rendered height)
		   should in theory push the whole sheet exactly to the viewport's
		   bottom edge, fully offscreen — but a mobile browser's `vh` unit
		   (used above for max-height) and its actual fixed-position
		   viewport don't always agree on the same number (the classic
		   "100vh doesn't account for the address bar" class of bug), so in
		   practice this can leave a ~35-45px sliver — exactly
		   .shop-filter-head's own height — still visible at the bottom of
		   the screen even while "closed". `translateY(100vh)` instead is
		   unconditionally larger than the
		   sheet's own 85vh-capped height regardless of which `vh` a given
		   browser moment resolves to, so it can never fall short the same
		   way; open state (`.is-open`, below) is unaffected since it
		   targets 0 either way. */
		transform: translateY(100vh);
		transition: transform 0.28s ease;
	}
}

.shop-filter-group {
	padding-bottom: 22px;
	margin-bottom: 22px;
	border-bottom: 1px solid var(--color-border);
}

.shop-filter-group:last-child {
	border-bottom: none;
	margin-bottom: 0;
	padding-bottom: 0;
}

.shop-filter-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	margin-bottom: 12px;
}

.shop-filter-head .shop-filter-title {
	display: inline-flex;
	align-items: center;
	gap: 8px;
}

.shop-filter-head .shop-filter-title .icon {
	width: 17px;
	height: 17px;
}

.shop-filter-title {
	font-size: 0.9375rem;
	font-weight: 800;
}

.shop-filter-reset {
	font-size: 0.8125rem;
	font-weight: 600;
	color: var(--color-primary);
}

.shop-filter-reset:hover {
	color: var(--color-primary-dark);
}

/* Mobile-only "Bộ Lọc" toggle (lives in .shop-toolbar) and its matching
   close button (lives in .shop-filter-head) — both hidden on desktop,
   where the sidebar is always visible inline and needs neither. See the
   ≤900px override below for what they open/close. */
.shop-filter-toggle,
.shop-filter-close {
	display: none;
}
@media (max-width: 900px) {
	.shop-filter-toggle {
		display: inline-flex;
		align-items: center;
		gap: 6px;
		padding: 8px 14px;
		border: 1px solid var(--color-border);
		border-radius: 999px;
		background: var(--color-bg);
		font-size: 0.8125rem;
		font-weight: 700;
		color: var(--color-text);
		flex-shrink: 0;
	}
}
@media (max-width: 900px) {
	/* Same X-via-rotated-bars technique as .nav-close. */
	.shop-filter-close {
		display: flex;
		align-items: center;
		justify-content: center;
		width: 34px;
		height: 34px;
		border-radius: 50%;
		background: var(--color-bg-alt);
		border: 0;
		cursor: pointer;
		position: relative;
		flex-shrink: 0;
	}
}

.shop-filter-list {
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.shop-filter-item {
	display: flex;
	align-items: center;
	gap: 10px;
	font-size: 0.9375rem;
	color: var(--color-text);
	cursor: pointer;
}

.shop-filter-item input[type="checkbox"] {
	width: 18px;
	height: 18px;
	accent-color: var(--color-primary);
	flex-shrink: 0;
}

.shop-filter-item .icon {
	width: 16px;
	height: 16px;
	flex-shrink: 0;
}

.shop-filter-apply {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	padding: 12px 20px;
	margin-top: 4px;
	background: var(--color-primary);
	color: #fff;
	border: none;
	border-radius: 999px;
	font-weight: 700;
	font-size: 0.9375rem;
	font-family: inherit;
	cursor: pointer;
}

.shop-filter-apply:hover {
	background: var(--color-primary-dark);
}

/* Dual-handle price-range filter (khach-san.html's "Khoảng Giá") — two
   overlapping native <input type="range"> stacked on one invisible track,
   the classic technique for a two-thumb slider without a JS widget
   library. Decorative like every other filter on this page (no live
   result filtering — see the shop-toolbar comment on tour.html), but kept
   genuinely interactive (drag either thumb, labels + fill bar update in
   real time, min can't cross max) at the same polish level as the qty
   stepper rather than a static image of a slider. The bound labels are
   generic filter-range numbers, not a claim about any specific listing's
   price — doesn't fall under the content-guidelines.md "no invented VND
   prices" rule, same as a marketplace's stock price-filter widget. */
.price-range {
	position: relative;
	height: 28px;
	margin: 4px 0 2px;
}

.price-range-track {
	position: absolute;
	top: 50%;
	left: 9px;
	right: 9px;
	height: 4px;
	background: var(--color-border);
	border-radius: 999px;
	transform: translateY(-50%);
}

.price-range-fill {
	position: absolute;
	top: 50%;
	height: 4px;
	background: var(--color-primary);
	border-radius: 999px;
	transform: translateY(-50%);
}

.price-range-input {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 28px;
	margin: 0;
	background: none;
	pointer-events: none;
	-webkit-appearance: none;
	appearance: none;
}

.price-range-input::-webkit-slider-runnable-track {
	-webkit-appearance: none;
	background: none;
}

.price-range-input::-moz-range-track {
	background: none;
	border: none;
}

.price-range-input::-webkit-slider-thumb {
	-webkit-appearance: none;
	pointer-events: auto;
	width: 18px;
	height: 18px;
	border-radius: 50%;
	background: #fff;
	border: 3px solid var(--color-primary);
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
	cursor: pointer;
}

.price-range-input::-moz-range-thumb {
	pointer-events: auto;
	width: 18px;
	height: 18px;
	border-radius: 50%;
	background: #fff;
	border: 3px solid var(--color-primary);
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
	cursor: pointer;
}

.price-range-values {
	display: flex;
	align-items: center;
	justify-content: space-between;
	font-size: 0.8125rem;
	font-weight: 700;
	color: var(--color-text);
	margin-top: 4px;
}

/* Sidebar "Cần tư vấn?" contact card (ve-tham-quan.html) — points to the
   site's real hotline, not a fabricated claim like the reference's "Vé
   chính hãng" badge (deliberately dropped, see design-system.md). */
.shop-sidebar-cta {
	display: flex;
	align-items: flex-start;
	gap: 12px;
	margin-top: 24px;
	padding: 18px;
	background: var(--color-bg-alt);
	border-radius: var(--radius);
}

.shop-sidebar-cta-icon {
	width: 38px;
	height: 38px;
	flex-shrink: 0;
	border-radius: 50%;
	background: #fff;
	display: flex;
	align-items: center;
	justify-content: center;
}

.shop-sidebar-cta-body {
	min-width: 0;
}

.shop-sidebar-cta-title {
	font-weight: 800;
	font-size: 0.9375rem;
	margin-bottom: 2px;
}

.shop-sidebar-cta-text {
	font-size: 0.8125rem;
	color: var(--color-text-light);
	margin-bottom: 12px;
}

.shop-sidebar-cta .btn {
	width: 100%;
	justify-content: center;
	padding: 10px 16px;
	font-size: 0.875rem;
}

/* Backdrop for the mobile filter bottom sheet (same pattern as
   .nav-backdrop) — hidden/no-op on desktop, where .shop-sidebar never
   goes off-canvas. Kept as a plain fixed element with no positioned/
   transformed ancestor, same reasoning as .nav-backdrop's placement:
   see the .site-header z-index comment for why that matters. */
.shop-filter-backdrop {
	display: none;
	position: fixed;
	inset: 0;
	background: rgba(9, 20, 23, 0.45);
	z-index: 1000;
}

.shop-filter-backdrop.is-open {
	display: block;
}

.shop-toolbar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	margin-bottom: 20px;
	padding-bottom: 16px;
	border-bottom: 1px solid var(--color-border);
}
@media (max-width: 782px) {
	/* Klook-style compact toolbar: result count on its own smaller line,
	   "Bộ Lọc" + the sort select(s) below it as pill controls sharing ONE
	   horizontally-scrollable row — khach-san.html's two selects (sort +
	   price) don't fit next to the filter pill in 375px, and wrapping them
	   to a second line looks broken. A scrolling row, same swipe-don't-stack
	   idea as every other overflow-prone control
	   strip in this file (.category-nav-pills, .products-scroll, etc.),
	   instead of a wrap.
	   `.shop-toolbar-controls` wraps .shop-filter-toggle + .shop-sort in
	   the markup (tour/khach-san/ve-tham-quan/dich-vu.html) — a plain
	   div, invisible to desktop's layout since only .shop-sort is visible
	   there and the existing .shop-toolbar space-between still applies
	   between .shop-result-count and this wrapper. */
	.shop-toolbar {
		flex-wrap: wrap;
		row-gap: 10px;
	}
}

.shop-result-count {
	font-size: 0.9375rem;
	color: var(--color-text-light);
}
@media (max-width: 782px) {
	.shop-result-count {
		width: 100%;
		font-size: 0.8125rem;
	}
}

.shop-result-count strong {
	color: var(--color-text);
}

.shop-sort {
	display: flex;
	align-items: center;
	gap: 10px;
	font-size: 0.875rem;
	color: var(--color-text-light);
	flex-shrink: 0;
}
@media (max-width: 782px) {
	.shop-filter-toggle,
	.shop-sort {
		flex-shrink: 0;
	}
}

.shop-sort select {
	/* Custom-drawn caret instead of the browser's native <select> arrow —
	   native rendering varies by browser/OS/zoom and can crowd/overflow the
	   box edge. Two rotated-gradient triangles form the chevron, same shape
	   family as .menu-chevron's border-triangle trick. */
	appearance: none;
	-webkit-appearance: none;
	-moz-appearance: none;
	border: 1px solid var(--color-border);
	border-radius: var(--radius);
	padding: 8px 32px 8px 12px;
	font-size: 0.875rem;
	font-family: inherit;
	background-color: var(--color-bg);
	background-image: linear-gradient(45deg, transparent 50%, var(--color-text-light) 50%), linear-gradient(135deg, var(--color-text-light) 50%, transparent 50%);
	background-position: calc(100% - 18px) center, calc(100% - 13px) center;
	background-size: 5px 5px, 5px 5px;
	background-repeat: no-repeat;
	color: var(--color-text);
}
@media (max-width: 782px) {
	.shop-sort select {
		border-radius: 999px;
		padding: 8px 28px 8px 14px;
		white-space: nowrap;
	}
}

/* =========================================================
   Hero/floating search card — shared by the homepage AND all 4 catalog
   archive pages (tour/khach-san/ve-tham-quan/dich-vu), so this stays
   always-loaded rather than gated to pages/home.css's per-page-type
   condition. The tabbed variant above the card (.hero-search-tabs) is
   homepage-only and stays in pages/home.css.
   ========================================================= */
/* Floating search card, pulled up over the hero photo's bottom edge */
.hero-search-float-wrap {
	max-width: var(--container-width);
	margin: -54px auto 0;
	padding: 0 20px;
	position: relative;
	z-index: 4;
}
@media (max-width: 782px) {
	/* Hide the floating search/booking card entirely on phones — homepage + all 4 shop
	   listing pages (tour/khach-san/ve-tham-quan/dich-vu.html) use
	   this same .hero-search-float-wrap. The mobile nav drawer already
	   has its own search box (moved there by main.js), so this was a
	   second, more expensive-to-render copy of the same "find something"
	   entry point, just for costing a full card's worth of height right
	   under the hero on every one of those pages. The margin/flex rules
	   below are consequently dead on mobile now (only apply once display
	   is no longer none) — left in place rather than deleted in case this
	   ever needs reverting; harmless either way. */
	.hero-search-float-wrap {
		display: none;
		margin-top: -30px;
	}
}

.hero-search-card {
	background: #fff;
	border: 1px solid #edf3f4;
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-lg);
	padding: 12px;
	display: flex;
	align-items: stretch;
	gap: 10px;
}
@media (max-width: 782px) {
	.hero-search-card {
		flex-direction: column;
		padding: 12px;
		gap: 8px;
	}
}

.hero-search-card-field {
	flex: 1;
	display: flex;
	flex-direction: column;
	gap: 6px;
	padding: 10px 16px;
	position: relative;
	min-width: 0;
	border: 1px solid var(--color-border);
	border-radius: var(--radius);
}
@media (max-width: 782px) {
	.hero-search-card-field {
		padding: 10px 14px;
	}
}

.hero-search-card-field label {
	font-size: 0.75rem;
	font-weight: 700;
	color: var(--color-text-light);
	display: flex;
	align-items: center;
	gap: 6px;
}

.hero-search-card-field label .icon {
	width: 15px;
	height: 15px;
}

.hero-search-card-field input,
.hero-search-card-field select {
	border: 0;
	padding: 2px 0;
	font: inherit;
	font-size: 1rem;
	color: var(--color-text);
	background: transparent;
	min-width: 0;
}

.hero-search-card-field input:focus,
.hero-search-card-field select:focus {
	outline: none;
}

/* Custom caret for this field's <select> only (not the sibling <input>,
   which shares the rule above) — same native-arrow-overflow fix as
   .shop-sort select just above, sized for this field's tighter, borderless
   layout. */
.hero-search-card-field select {
	appearance: none;
	-webkit-appearance: none;
	-moz-appearance: none;
	padding-right: 20px;
	background-image: linear-gradient(45deg, transparent 50%, var(--color-text-light) 50%), linear-gradient(135deg, var(--color-text-light) 50%, transparent 50%);
	background-position: right 5px center, right 0 center;
	background-size: 5px 5px, 5px 5px;
	background-repeat: no-repeat;
}

.hero-search-card .btn-primary {
	flex-shrink: 0;
	align-self: center;
	margin: 6px;
	padding: 14px 26px;
	white-space: nowrap;
	border-radius: var(--radius);
}
@media (max-width: 782px) {
	.hero-search-card .btn-primary {
		margin: 8px 4px 4px;
		justify-content: center;
	}
}

