/* Bảng điều khiển dán đáy bản đồ (map-dock.js).
   Ba nấc có HÌNH DẠNG khác nhau, không chỉ khác vị trí:
     thu  — viên pill nổi có lề, mờ kính, chỉ còn ô tìm kiếm (kiểu Apple Maps)
     nửa  — tấm phủ hết bề ngang, đủ chỗ cho bộ lọc
     hết  — tấm cao gần kín bản đồ, dùng khi xem toàn màn hình */
#ml-map {
	--md-nen: rgba(255, 255, 255, .86);
	--md-vien: rgba(60, 60, 58, .13);
	--md-chu: #35342f;
	--md-mo: #8a8880;
	--md-coral: #0f5e7c;   /* đổi theo ô "Ghim địa điểm" trong bảng */
}

.mdock {
	position: absolute;
	z-index: 20;   /* trên cụm nút và dòng bản quyền của MapLibre */
	left: 50%;
	bottom: 0;
	width: min(560px, 100%);
	height: 86%;
	display: none;                 /* chỉ bật ở chế độ toàn màn hình */
	flex-direction: column;
	background: rgba(255, 255, 255, .74);
	-webkit-backdrop-filter: saturate(180%) blur(15px);
	backdrop-filter: saturate(180%) blur(15px);
	color: var(--md-chu);
	font-family: inherit;
	overflow: hidden;
	border-radius: 18px 18px 0 0;
	box-shadow: 0 -8px 30px rgba(40, 40, 36, .16);
	transition: transform .34s cubic-bezier(.32, .72, 0, 1),
		height .34s cubic-bezier(.32, .72, 0, 1),
		width .34s cubic-bezier(.32, .72, 0, 1),
		bottom .34s cubic-bezier(.32, .72, 0, 1),
		border-radius .34s ease;
	touch-action: none;
	will-change: transform;
}
.mdock.is-hien { display: flex; }

/* Hai nấc bung: tấm phủ đáy, chỉ khác nhau ở chỗ tụt xuống bao nhiêu.
   Giữ nguyên kích thước nên lúc kéo mới bám được ngón tay.
   Phần -50% là để căn giữa — MỌI phép dịch dọc đều phải giữ nó. */
.mdock[data-nac="nua"] { transform: translate(-50%, 46%); }
.mdock[data-nac="het"] { transform: translate(-50%, 0); }

/* Nấc thu khi ĐỨNG YÊN: viên pill kính nổi, tách hẳn khỏi đáy và hai mép,
   bo tròn hết cỡ — đúng dáng thanh tìm kiếm của Apple Maps.
   Vừa chạm tay kéo là nó lập tức trở lại hình tấm (luật .is-keo bên dưới) để
   nội dung trượt theo ngón, thả ra mới về lại dáng pill. */
.mdock[data-nac="thu"]:not(.is-keo) {
	height: 56px;
	bottom: 16px;
	width: min(520px, calc(100% - 28px));
	border-radius: 28px;
	transform: translate(-50%, 0);
	box-shadow: 0 8px 26px rgba(40, 40, 36, .2);
	justify-content: flex-end;     /* ô tìm tụt xuống dưới vạch kéo */
}
/* Vạch kéo: mảnh, dính sát mép trên, KHÔNG chiếm chỗ trong dòng chảy — nhờ vậy
   ô tìm mới nằm cân trong viên pill. */
.mdock[data-nac="thu"]:not(.is-keo) .mdock__grip {
	position: absolute; top: 0; left: 0; right: 0; padding: 0; height: 14px;
	display: grid; place-items: center; line-height: 0;
}
.mdock[data-nac="thu"]:not(.is-keo) .mdock__grip i { width: 36px; height: 5px; }
/* Thân bảng phải BIẾN MẤT khỏi dòng chảy khi đang là viên pill. Để nó ở
   `flex: 1` thì dù cao 0 nó vẫn đòi ~20px, tổng nội dung vượt quá 56px của
   pill và `justify-content: flex-end` đẩy ô tìm TRÔI LÊN KHỎI mép trên — đúng
   cái lỗi nhìn thấy: ô tìm nằm hớ hênh phía trên, tiêu đề "Bản đồ" thò ra dưới. */
.mdock[data-nac="thu"]:not(.is-keo) .mdock__body { display: none; }
/* Ô nhập: viên xám bo tròn nằm trong viên trắng, chữ dạt trái như ảnh mẫu. */
.mdock[data-nac="thu"]:not(.is-keo) .mdock__bar {
	margin: 0 9px 9px; height: 38px; border-radius: 19px;
	background: rgba(60, 60, 58, .08);
}
.mdock[data-nac="thu"].is-keo { transform: translate(-50%, calc(100% - 58px)); }
.mdock.is-keo {
	transition: none;
	height: 86%;
	bottom: 0;
	width: min(560px, 100%);
	border-radius: 18px 18px 0 0;
}

.mdock__grip { flex: 0 0 auto; padding: 7px 0 2px; text-align: center; cursor: grab; }
.mdock__grip i {
	display: inline-block; width: 36px; height: 5px; border-radius: 5px;
	background: rgba(60, 60, 58, .22);
}
.mdock__grip:focus-visible { outline: 2px solid var(--md-coral); outline-offset: -3px; }

.mdock__bar {
	flex: 0 0 auto; display: flex; align-items: center; gap: 9px;
	margin: 0 16px 12px; padding: 0 12px;
	height: 38px; border-radius: 19px;
	background: rgba(60, 60, 58, .08);
}
/* ĐÃ THỬ RỒI BỎ: căn giữa kính lúp + chữ mờ khi ô trống. Nhìn lại ảnh mẫu thì
   Apple Maps để chữ DẠT TRÁI trong ô xám, chỉ có VIÊN PILL là căn giữa màn
   hình — căn giữa chữ làm thanh tìm trông lệch và rỗng ruột. */
.mdock__ic { width: 17px; height: 17px; flex: 0 0 auto; fill: none; stroke: var(--md-mo); stroke-width: 2.2; stroke-linecap: round; }
.mdock__input {
	flex: 1 1 auto; min-width: 0; border: 0; background: none; outline: none;
	/* 16px KHÔNG phải cho đẹp: Safari iOS tự phóng to cả trang khi con trỏ vào
	   ô nhập có cỡ chữ dưới 16px. Đổi số này là lỗi phóng trang quay lại. */
	font: inherit; font-size: 16px; color: var(--md-chu);
	-webkit-appearance: none; appearance: none;
}
.mdock__input::placeholder { color: var(--md-mo); }
.mdock__input::-webkit-search-cancel-button { display: none; }
/* Dùng display chứ không phải visibility: để ẩn mà vẫn chiếm chỗ thì cụm kính
   lúp + chữ bị đẩy lệch sang trái, không căn giữa được. */
.mdock__clear {
	flex: 0 0 auto; border: 0; background: none; cursor: pointer;
	font-size: 20px; line-height: 1; color: var(--md-mo); padding: 0 2px; display: none;
}
.mdock.is-tim .mdock__clear { display: block; }

.mdock__body {
	flex: 1 1 auto; overflow-y: auto; -webkit-overflow-scrolling: touch;
	padding: 0 18px 22px; touch-action: pan-y; overscroll-behavior: contain;
}
/* thân bảng vẫn nằm đó, chỉ là bị đẩy khỏi khung nhìn — nhờ vậy kéo lên
   là thấy nội dung trượt theo ngón tay chứ không bật hiện đột ngột */

/* ---- đầu bảng: tên + nút thu, kiểu Directions của Apple Maps ---- */
.mdock__dau {
	display: flex; align-items: center; justify-content: space-between;
	gap: 12px; margin: 2px 0 14px;
}
.mdock__dau h3, .mdock__tieu { margin: 0; font-size: 22px; font-weight: 800; letter-spacing: -.02em; }
.mdock__dong {
	flex: 0 0 auto; width: 30px; height: 30px; border: 0; border-radius: 50%;
	background: rgba(60, 60, 58, .1); cursor: pointer;
	display: grid; place-items: center; padding: 0;
}
.mdock__dong svg { width: 15px; height: 15px; fill: none; stroke: var(--md-mo); stroke-width: 2.4; stroke-linecap: round; }
.mdock__dong:hover { background: rgba(60, 60, 58, .16); }

.mdock__body h4, .mdock__body .mset__nhom {
	margin: 18px 2px 7px; font-size: 12px; font-weight: 700;
	letter-spacing: .04em; text-transform: uppercase; color: var(--md-mo);
	display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.mdock__body h4:first-of-type { margin-top: 4px; }
.mdock__reset {
	border: 0; background: none; cursor: pointer; font: inherit;
	font-size: 12px; font-weight: 600; letter-spacing: 0; text-transform: none;
	color: var(--md-coral); padding: 0;
}
.mdock.is-tim .mdock__body h4,
.mdock.is-tim .mdock__card,
.mdock.is-tim .mdock__ghi { display: none; }

/* ---- thẻ gom nhóm: nền xám nhạt, các hàng ngăn bằng vạch tóc thụt lề ---- */
.mdock__card {
	background: rgba(120, 120, 128, .09);
	border-radius: 13px; overflow: hidden;
}
.mdock__r {
	position: relative;
	display: flex; align-items: center; gap: 11px;
	min-height: 46px; padding: 7px 12px;
	font-size: 15px; font-weight: 500; cursor: pointer;
}
.mdock__r + .mdock__r::before {
	content: ''; position: absolute; left: 51px; right: 0; top: 0;
	height: 1px; background: rgba(60, 60, 58, .12);
}
.mdock__r.is-rong { opacity: .42; cursor: default; }
.mdock__nhan { flex: 1 1 auto; min-width: 0; }
.mdock__dem { flex: 0 0 auto; font-size: 13px; font-weight: 600; color: var(--md-mo); }

/* huy hiệu tròn — mắt nhận ra nhóm bằng màu trước khi kịp đọc chữ */
.mdock__ico {
	flex: 0 0 auto; width: 28px; height: 28px; border-radius: 8px;
	display: grid; place-items: center;
}
.mdock__ico svg {
	width: 17px; height: 17px; fill: none; stroke: #fff;
	stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}

.mdock__r input[type="checkbox"] { position: absolute; opacity: 0; pointer-events: none; }
.mdock__sw {
	flex: 0 0 auto; width: 44px; height: 26px; border-radius: 999px;
	background: rgba(60, 60, 58, .22); position: relative; transition: background .2s;
}
.mdock__sw::after {
	content: ''; position: absolute; top: 2px; left: 2px;
	width: 22px; height: 22px; border-radius: 50%; background: #fff;
	box-shadow: 0 1px 3px rgba(0, 0, 0, .22); transition: transform .2s;
}
.mdock__r input:checked + .mdock__sw { background: #34c759; }
.mdock__r input:checked + .mdock__sw::after { transform: translateX(18px); }
.mdock__r input:focus-visible + .mdock__sw { outline: 2px solid var(--md-coral); outline-offset: 2px; }

/* ô chọn màu — bỏ khung mặc định xấu của trình duyệt */
.mdock__r input[type="color"] {
	flex: 0 0 auto; width: 46px; height: 28px; padding: 0; cursor: pointer;
	border: 1.5px solid rgba(60, 60, 58, .16); border-radius: 8px; background: none;
	-webkit-appearance: none; appearance: none;
}
.mdock__r input[type="color"]::-webkit-color-swatch-wrapper { padding: 2px; }
.mdock__r input[type="color"]::-webkit-color-swatch { border: 0; border-radius: 6px; }

/* ---- kết quả tìm: cũng gom thành thẻ ---- */
.mdock__ket:not(:empty) {
	background: rgba(120, 120, 128, .09); border-radius: 13px;
	overflow: hidden; margin-bottom: 4px;
}
.mdock__item {
	position: relative;
	display: flex; align-items: center; gap: 11px; padding: 9px 12px;
	text-decoration: none; color: inherit;
}
.mdock__item + .mdock__item::before {
	content: ''; position: absolute; left: 69px; right: 0; top: 0;
	height: 1px; background: rgba(60, 60, 58, .12);
}
.mdock__item img, .mdock__no {
	width: 46px; height: 46px; flex: 0 0 auto; border-radius: 10px;
	object-fit: cover; background: rgba(60, 60, 58, .1);
}
.mdock__txt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.mdock__txt b { font-size: 15px; font-weight: 600; }
.mdock__txt i {
	font-style: normal; font-size: 12.5px; color: var(--md-mo);
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mdock__tag { flex: 0 0 auto; font-size: 11.5px; font-weight: 600; color: var(--md-mo); }
.mdock__rong, .mdock__ghi { font-size: 12.5px; color: var(--md-mo); margin: 12px 2px 0; }

/* ghim bị tắt trong bảng lọc */
#ml-map .ml-marker.is-loc-tat { display: none !important; }

/* Nút zoom và dòng bản quyền phải tránh bảng. Ngoài chế độ toàn màn hình thì
   bảng ẩn hẳn nên không cần đẩy gì. Khi bảng đã bung ra thì giấu luôn cụm nút
   zoom — nó nằm đè lên nội dung bảng, mà lúc đó người xem đang thao tác trong
   bảng chứ không phóng bản đồ. */
body.mdock-mo #ml-map .maplibregl-ctrl-bottom-left,
body.mdock-mo #ml-map .maplibregl-ctrl-bottom-right { bottom: 84px; }
/* Không cho dòng bản quyền trải ngang che bản đồ: giữ đúng nút tròn, bấm mới xổ */
#ml-map .maplibregl-ctrl-attrib.maplibregl-compact:not(.maplibregl-compact-show) {
	min-height: 24px; padding: 0; background: rgba(255, 255, 255, .82); border-radius: 12px;
}
#ml-map .maplibregl-ctrl-attrib.maplibregl-compact:not(.maplibregl-compact-show) .maplibregl-ctrl-attrib-inner {
	display: none;
}
body.mdock-bung #ml-map .maplibregl-ctrl-bottom-left,
body.mdock-bung #ml-map .maplibregl-ctrl-bottom-right { opacity: 0; pointer-events: none; }
#ml-map .maplibregl-ctrl-bottom-left,
#ml-map .maplibregl-ctrl-bottom-right { transition: opacity .2s, bottom .3s; }

/* xem toàn màn hình thì có chỗ, cho tấm cao hơn */


@media (max-width: 600px) {
	.mdock, .mdock.is-keo { width: 100%; height: 90%; }
	.mdock[data-nac="nua"] { transform: translate(-50%, 52%); }
	.mdock__body { padding: 0 15px 20px; }
}

@media (prefers-reduced-motion: reduce) {
	.mdock { transition: none; }
}

/* ---- Ô ảnh dán mép bản đồ: hiện/ẩn cho mượt ----
   style.css để sẵn `display: none` và JS bản cũ bật/tắt bằng display — nên khi
   chuyển sang bật/tắt bằng class thì ô biến mất sạch. Ở đây phải ghi đè
   display (chọn qua #ml-map cho đủ mạnh) rồi mới điều khiển bằng opacity.
   KHÔNG transition transform: vị trí do JS đặt mỗi khung hình, thêm transition
   là ô trôi chậm hơn bản đồ một nhịp. */
#ml-map .ml-edge__item {
	/* flex chứ không phải block: nút nay là cột ảnh + tên (style.css). */
	display: flex;
	opacity: 0;
	visibility: hidden;
	transition: opacity .26s ease, box-shadow .18s ease, filter .18s ease;
}
#ml-map .ml-edge__item.is-on {
	opacity: 1;
	visibility: visible;
}


/* Toàn màn hình trên điện thoại: bản đồ chạy sát mép trên nên cụm nút 3D /
   về nhà / định vị chui lên dưới thanh trạng thái và bị cắt. Chừa đúng phần
   khuyết an toàn của máy. */
body.map-is-fs #ml-map .maplibregl-ctrl-top-right,
body.map-is-fs #ml-map .maplibregl-ctrl-top-left,
body.map-is-fs #ml-map .ml-ctrl-extra {
	padding-top: env(safe-area-inset-top, 0px);
}

/*gcm-dock-cats-start*/
/* Phần còn lại của thời "5 nút chỉ có biểu tượng, xếp lưới vuông".
   ĐÃ DỌN: lưới 5 cột, ô vuông aspect-ratio, nền xám khi bật, và luật làm mờ ô
   chưa bật (opacity .38). Bốn thứ đó nay do khối gcm-mset lo, để cả hai nơi cùng
   định nghĩa thì mỗi lần đổi giao diện lại phải sửa hai chỗ — mà chỉ cần quên
   một chỗ là màu mới không lên (đúng lỗi vừa gặp).
   Giữ lại đúng những gì không nằm ở đâu khác. */
.mdock__cats { display: flex; }
.mdock__o { position: relative; cursor: pointer; }
/* ô đánh dấu thật bị giấu: trạng thái thể hiện bằng chính hình dáng cái ô */
.mdock__o input { position: absolute; opacity: 0; pointer-events: none; }
/* biểu tượng đã bỏ từ lúc chuyển sang nút chữ */
.mdock__o-ic { display: none; }
/* nhóm chưa có địa điểm nào: không bấm được */
.mdock__o.is-rong { opacity: .35; cursor: default; }
/*gcm-dock-cats-end*/

/*gcm-mpop-start*/
/* Thẻ xem nhanh địa điểm — hiện khi bấm ghim trên bản đồ.
   Dán đáy bản đồ, ngang, bo tròn; bấm TÊN mới chuyển sang trang địa điểm. */
.mpop {
	position: absolute; z-index: 22;
	/* Dán đáy, canh giữa. Khi có thanh 5 loại địa điểm (chế độ toàn màn hình),
	   main.js đo thanh đó rồi ghi đè `bottom` để thẻ ngồi ngay bên trên. */
	left: 12px; right: 12px; bottom: 16px;
	max-width: 380px; margin: 0 auto;
	padding: 11px 12px;
	border-radius: 20px;
	background: rgba(255, 255, 255, .93);
	-webkit-backdrop-filter: saturate(180%) blur(15px);
	backdrop-filter: saturate(180%) blur(15px);
	box-shadow: 0 -6px 34px rgba(40, 40, 36, .2);
	color: var(--md-chu, #35342f);
	animation: mpop-len .22s cubic-bezier(.32, .72, 0, 1);
}
/* Hiện lên bằng ĐỘ MỜ, không kèm dịch chuyển: main.js đo vị trí thật của thẻ
   ngay sau khi hiện để canh với viên pill tìm kiếm, mà đang chạy hiệu ứng dịch
   thì số đo lệch đúng bằng quãng dịch. */
@keyframes mpop-len { from { opacity: 0; } }

.mpop__top { display: flex; align-items: center; gap: 11px; }
/* ô vuông ảnh đại diện bên trái */
.mpop__anh {
	flex: 0 0 auto; width: 66px; height: 66px;
	object-fit: cover; border-radius: 12px;
	background: #efe9dc;
}
.mpop__chu { flex: 1 1 auto; min-width: 0; padding-right: 30px; align-self: center; }
.mpop__ten {
	display: block;
	font: 800 17px/1.25 var(--font-serif, Georgia, serif);
	color: var(--c-green-deep, #0b4a34);
	text-decoration: none;
	overflow-wrap: anywhere;
}
.mpop__ten:hover { text-decoration: underline; }
.mpop__mo {
	margin: 5px 0 0;
	font-size: 13px; line-height: 1.45;
	color: rgba(123, 79, 57, .82);
	/* mô tả dài thì cắt còn 3 dòng, thẻ luôn giữ chiều cao gọn */
	display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
	overflow: hidden;
}

/* Một nút duy nhất ở góc phải trên: thêm vào lịch trình.
   Không có nút đóng — thẻ tự tắt khi bấm ra bản đồ, bấm ghim khác, hoặc Esc. */
.mpop__them {
	position: absolute; top: 10px; right: 10px;
	width: 28px; height: 28px; padding: 0;
	border: 0; border-radius: 50%;
	display: grid; place-items: center; cursor: pointer;
	background: rgba(60, 60, 58, .1);
}
.mpop__them svg {
	width: 16px; height: 16px;
	fill: none; stroke: var(--md-mo, #8a8880);
	stroke-width: 2.4; stroke-linecap: round;
}
.mpop__them:hover { background: rgba(60, 60, 58, .18); }
/* ĐÃ THÊM VÀO LỊCH TRÌNH = DẤU TICK MỜ, không phải dấu ×.
   Dấu × đọc ra là "xoá" hoặc "đóng thẻ", trong khi ý cần nói là "chỗ này có
   trong giỏ rồi". Tick xám nhạt trên nền xám nhạt: đủ để xác nhận, không mời
   gọi bấm thêm. Bấm lại vẫn bỏ được — chuyển về dấu cộng ngay. */
.mpop__them .i-xong { display: none; }
.mpop.da-them .mpop__them .i-them { display: none; }
.mpop.da-them .mpop__them .i-xong { display: block; }
.mpop.da-them .mpop__them {
	background: rgba(60, 60, 58, .08);
}
.mpop.da-them .mpop__them svg { stroke: rgba(60, 60, 58, .42); }
.mpop.da-them .mpop__them:hover { background: rgba(60, 60, 58, .16); }
.mpop.da-them .mpop__them:hover svg { stroke: rgba(60, 60, 58, .62); }
.mpop__them svg { transition: stroke .2s ease; }
/* nhịp tick khi vừa thêm xong */
.mpop.da-them .mpop__them .i-xong { animation: gcm-tick .26s cubic-bezier(.34, 1.4, .64, 1); }
@keyframes gcm-tick { from { transform: scale(.6); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
	.mpop.da-them .mpop__them .i-xong { animation: none; }
}

@media (max-width: 480px) {
	.mpop { padding: 10px 10px; border-radius: 16px; }
	.mpop__anh { width: 58px; height: 58px; border-radius: 11px; }
	.mpop__chu { padding-right: 28px; }
	.mpop__ten { font-size: 15.5px; }
	.mpop__mo { font-size: 12.5px; -webkit-line-clamp: 2; }
}
/*gcm-mpop-end*/

/* Dòng khoảng cách trong thẻ xem nhanh — nhạt hơn mô tả một nấc để nó là thông
   tin phụ, nhưng vẫn đọc được ngay mà không phải tìm. */
.mpop__xa {
	margin: 4px 0 0;
	font: 600 12.5px/1.35 var(--font-sans, sans-serif);
	color: rgba(123, 79, 57, .62);
	font-variant-numeric: tabular-nums;
}
.mpop__xa[hidden] { display: none; }
@media (max-width: 600px) { .mpop__xa { font-size: 12px; } }








/*gcm-cham-start*/
/* Ghim quán ăn / cà phê ở mức zoom xa: thu về một CHẤM TRÒN, không tên không ảnh.
   Hai nhóm này đông hơn hẳn (157 quán ăn, 40 cà phê) và dồn trong vài con phố,
   để nguyên nhãn thì nhìn cả thành phố chỉ thấy một mảng chữ chồng chữ. */
#ml-map .ml-marker.is-cham .ml-marker__txt,
#ml-map .ml-marker.is-cham .ml-marker__thumb,
#ml-map .ml-marker.is-cham .ml-marker__tail { display: none; }
#ml-map .ml-marker.is-cham .ml-marker__label {
	display: block;
	width: 11px; height: 11px;
	min-width: 0; min-height: 0; padding: 0; gap: 0;
	border-radius: 50%;
	border: 2px solid #fff;
	background: var(--cham-mau, #8a8880);
	box-shadow: 0 1px 5px rgba(30, 30, 28, .38);
	overflow: hidden;
}
/* Màu chấm theo nhóm, khớp đúng ô nhóm trên thanh dock (bảng Deep Sea). */
#ml-map .ml-marker--food.is-cham { --cham-mau: #e03a26; }
#ml-map .ml-marker--cafe.is-cham { --cham-mau: #7b4f39; }
/* Chấm nhỏ nên vùng bấm phải nới ra, không thì phải chọc rất khéo mới trúng. */
#ml-map .ml-marker.is-cham { padding: 9px; margin: -9px; }
#ml-map .ml-marker.is-cham:hover .ml-marker__label { transform: scale(1.35); }
#ml-map .ml-marker__label { transition: transform .15s ease; }
/*gcm-cham-end*/
















/*gcm-mset-start*/
/* ============================================================================
   BẢNG CÀI ĐẶT RỜI (.mset) + VIÊN PILL TÌM KIẾM RÚT GỌN (.mdock)

   Trước đây cả hai là MỘT tấm dán đáy, kéo lên mới thấy bộ lọc. Không ai đoán
   ra thao tác kéo đó, còn trên máy tính thì kéo bằng chuột rất dở. Nay tách:
     • pill tìm kiếm giữ NGUYÊN chỗ cũ ở đáy, gõ vào thì kết quả mọc lên trên;
     • bộ lọc & tuỳ chỉnh thành một bảng vuông nổi GIỮA bản đồ, mở bằng nút bánh
       răng bên phải (ngay dưới nút phóng to), đóng bằng nút × hoặc phím Esc.
   Khối này đặt CUỐI file để đè lên các luật nấc kéo cũ phía trên.
   ========================================================================== */

/* ---- thanh 5 loại địa điểm (thay chỗ ô tìm kiếm cũ) ---- */
.mdock,
.mdock[data-nac] {
	height: auto;
	max-height: none;
	bottom: 16px;
	width: auto;
	max-width: calc(100% - 24px);
	border-radius: 22px;
	transform: translate(-50%, 0);
	padding: 7px;
	touch-action: auto;
	box-shadow: 0 8px 26px rgba(40, 40, 36, .2);
	overflow: visible;
}
/* Năm nút một hàng, rộng theo chữ chứ không chia đều: tên loại dài ngắn khác
   nhau, chia đều thì ô "Cà phê" thừa chỗ còn ô "Vui chơi & đảo" lại chật. */
.mdock .mdock__cats {
	display: flex; gap: 4px;
}
.mdock .mdock__o {
	aspect-ratio: auto;
	flex: 0 1 auto;
	display: flex; align-items: center;
	padding: 8px 13px;
	border-radius: 15px;
	background: none;
}
/* chỉ còn chữ: biểu tượng đơn sắc phải đoán mới ra nghĩa, tên loại thì đọc là hiểu */
.mdock .mdock__o-ic { display: none; }
.mdock .mdock__o { background: rgba(120, 120, 128, .13); }
.mdock .mdock__o:hover { background: rgba(120, 120, 128, .22); }
.mdock__o-ten {
	font-size: 13px; font-weight: 600; line-height: 1.15;
	white-space: nowrap; color: var(--md-chu);
}
/* ĐANG BẬT — KÍNH PHÁT SÁNG, chữ trắng (đúng mẫu chủ site gửi).
   Ánh màu đậm ở giữa rồi loang ra mép, viền là một sợi màu rõ nét bao quanh —
   nhìn như có đèn màu đặt dưới tấm kính bo tròn.
   Đậm ở giữa là điều kiện để CHỮ TRẮNG đọc được: chữ nằm đúng vùng đặc nhất.
   Mép nhạt dần nên ô vẫn ra chất kính chứ không thành nút màu đặc. */
.mdock .mdock__o.is-bat {
	/* Mép ô phải ĐỦ ĐẶC. Bản trước để mép mờ tới .3 cho ra chất kính, nhưng phía
	   dưới là bản đồ đang chạy: mô hình 3D hay con đường sẫm màu trôi qua là lộ
	   nguyên một vệt tối trong lòng ô — đúng "vết đen" nhìn thấy. Giữ chuyển sắc
	   để vẫn có chiều sâu, nhưng đáy sàn là màu đặc, không còn nhìn xuyên. */
	background:
		radial-gradient(120% 100% at 50% 62%,
			rgba(var(--o-rgb, 60, 60, 58), 1) 0%,
			rgba(var(--o-rgb, 60, 60, 58), .94) 38%,
			rgba(var(--o-rgb, 60, 60, 58), .86) 72%,
			rgba(var(--o-rgb, 60, 60, 58), .82) 100%),
		rgb(var(--o-rgb, 60, 60, 58));
	-webkit-backdrop-filter: blur(8px) saturate(1.5);
	backdrop-filter: blur(8px) saturate(1.5);
	/* KHÔNG viền ngoài. Sợi màu bao quanh làm ô trông như cái nút bấm dán lên
	   bản đồ; bỏ đi thì ánh sáng tự loang ra mép và ô đọc như một vệt sáng nằm
	   dưới lớp kính — đúng chất mẫu chủ site gửi. */
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .28);
}
/* ánh sáng vắt chéo mặt kính, dừng trước khi chạm chữ */
.mdock .mdock__o.is-bat::before {
	content: ''; position: absolute; inset: 0;
	pointer-events: none; border-radius: inherit;
	background: linear-gradient(122deg,
		rgba(255, 255, 255, .42) 0%,
		rgba(255, 255, 255, .1) 32%,
		rgba(255, 255, 255, 0) 52%);
}
/* Chữ trắng, kèm một bóng cùng màu rất mảnh để rìa chữ không bị loà vào vùng
   sáng của mặt kính. */
.mdock .mdock__o.is-bat .mdock__o-ten {
	color: #fff;
	text-shadow: 0 1px 2px rgba(var(--o-rgb, 60, 60, 58), .55);
}
.mdock .mdock__o.is-bat:hover { filter: saturate(1.1) brightness(1.04); }
.mdock .mdock__o.is-bat:active {
	box-shadow: inset 0 2px 6px rgba(0, 0, 0, .22);
}
.mdock .mdock__o { transition: background .2s ease, box-shadow .18s ease, filter .18s ease; }

/* ---- Nảy + quét gương khi bấm bật/tắt ----
   Vệt sáng là một lớp phủ nằm trong chính nút (overflow ẩn nên nó bị cắt gọn
   theo bo góc), trượt chéo qua đúng một lần rồi tắt. Đặt ở ::after để không phải
   thêm phần tử nào vào DOM. */
.mdock .mdock__o { position: relative; overflow: hidden; }
.mdock .mdock__o::after {
	content: ''; position: absolute; inset: 0;
	pointer-events: none; opacity: 0;
	background: linear-gradient(105deg,
		transparent 36%,
		rgba(255, 255, 255, .55) 47%,
		rgba(255, 255, 255, .12) 56%,
		transparent 66%);
	transform: translateX(-130%);
}
.mdock .mdock__o.is-nhay::after { animation: dockQuet .58s cubic-bezier(.3, .7, .2, 1); }
@keyframes dockQuet {
	0% { transform: translateX(-130%); opacity: 0; }
	14% { opacity: 1; }
	100% { transform: translateX(130%); opacity: 0; }
}
/* Nảy: bật thì nhô lên rồi hạ về đúng chỗ của trạng thái bật (-1px), tắt thì
   chỉ hụp xuống một nhịp rồi về 0 — hai hướng khác nhau nên phải hai keyframes,
   nếu dùng chung nút sẽ giật một cái ở khung cuối. */
.mdock .mdock__o.is-nhay.is-bat { animation: dockNoiBat .44s cubic-bezier(.34, 1.5, .64, 1); }
.mdock .mdock__o.is-nhay:not(.is-bat) { animation: dockNoiTat .34s ease-out; }
/* Nảy bằng CỠ chứ không nhấc lên hạ xuống: nhấc theo trục dọc làm nút rời khỏi
   hàng, nhìn lệch cả thanh. Phóng nhẹ rồi về đúng cỡ thì gọn hơn nhiều. */
@keyframes dockNoiBat {
	0% { transform: scale(.94); }
	52% { transform: scale(1.06); }
	100% { transform: scale(1); }
}
@keyframes dockNoiTat {
	0% { transform: scale(1.03); }
	55% { transform: scale(.975); }
	100% { transform: scale(1); }
}
/* Máy nào bật "giảm chuyển động" thì bỏ hết, chỉ giữ đổi màu. */
@media (prefers-reduced-motion: reduce) {
	.mdock .mdock__o.is-nhay,
	.mdock .mdock__o.is-nhay::after { animation: none; }
}
/* Màu chữ do map-dock.js tính theo độ sáng của nền (xem hàm chuTren): nền đá
   sáng thì chữ xanh mực, nền xanh đậm thì chữ trắng. */

.mdock .mdock__o.is-rong { opacity: .35; }
/* bảng cài đặt vẫn giữ dạng ô vuông 5 cột — ở đó không có thanh ngang để bám */
.mset .mdock__o-ten { display: none; }

/* ---- bảng cài đặt: hình VUÔNG, nổi giữa bản đồ ---- */
.mset {
	position: absolute; z-index: 21;
	left: 50%; top: 50%;
	transform: translate(-50%, -50%);
	width: min(430px, calc(100% - 32px));
	/* vuông: cạnh lấy theo chiều nhỏ hơn của khung bản đồ, nhưng không được cao
	   quá khung — nội dung dài thì cuộn trong thân bảng. */
	height: min(430px, calc(100% - 32px));
	display: flex; flex-direction: column;
	padding: 14px 16px 10px;
	background: rgba(255, 255, 255, .93);
	-webkit-backdrop-filter: saturate(180%) blur(16px);
	backdrop-filter: saturate(180%) blur(16px);
	color: var(--md-chu);
	border-radius: 24px;
	box-shadow: 0 18px 50px rgba(40, 40, 36, .26);
	opacity: 0; scale: .97;
	transition: opacity .18s ease, scale .18s cubic-bezier(.32, .72, 0, 1);
}
.mset.is-mo { opacity: 1; scale: 1; }
.mset[hidden] { display: none; }
.mset__than {
	flex: 1 1 auto; min-height: 0;
	overflow-y: auto; -webkit-overflow-scrolling: touch;
	overscroll-behavior: contain;
	padding-bottom: 6px;
}
/* Các luật chữ/thẻ vốn viết cho .mdock__body — chép sang thân bảng mới. */
.mset .mdock__dau { margin: 0 0 10px; }
.mset__than h4, .mset__than .mset__nhom {
	margin: 18px 2px 7px; font-size: 12px; font-weight: 700;
	letter-spacing: .04em; text-transform: uppercase; color: var(--md-mo);
	display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.mset__than h4:first-of-type, .mset__than .mset__nhom:first-of-type { margin-top: 2px; }

@media (max-width: 600px) {
	.mdock, .mdock[data-nac] { max-width: calc(100% - 16px); padding: 5px; }
	.mdock .mdock__o { padding: 7px 9px; }
	.mdock__o-ten { font-size: 11.5px; }
	/* Cụm nút bên phải THU CÒN MỘT NỬA trên điện thoại: 28px thay cho 44px của
	   máy tính. Trên màn hình hẹp, ba nút 44px xếp dọc chiếm cả một cột bản đồ,
	   che mất đúng phần phố xá mà người ta đang nhìn. 28px vẫn đủ rộng để ngón
	   tay bấm trúng khi các nút dính liền nhau thành một khối. */
	#ml-map .ml-ctrl-extra button.ml-ctrl-btn,
	#ml-map .ml-ctrl-fs button.ml-ctrl-btn { width: 28px; height: 28px; }
	#ml-map .ml-ctrl-extra button.ml-ctrl-btn svg,
	#ml-map .ml-ctrl-fs button.ml-ctrl-btn svg { width: 14px; height: 14px; }
	#ml-map .ml-ctrl-extra button.ml-ctrl-btn--3d { font-size: 10.5px; }
	#ml-map .maplibregl-ctrl-group.ml-ctrl-extra,
	#ml-map .maplibregl-ctrl-group.ml-ctrl-fs { border-radius: 11px; }
	#ml-map .ml-ctrl-fs { margin-top: 6px !important; }
	#ml-map .ml-ctrl-cai { margin-bottom: 6px !important; }
	#ml-map .maplibregl-ctrl-top-right { margin: 6px 6px 0 0; }
	/* Điện thoại: bảng chỉ chiếm một PHẦN khung bản đồ chứ không phủ kín. Phủ kín
	   thì mất hẳn cảm giác đang đứng trên bản đồ — người xem không còn thấy chỗ
	   mình vừa lọc thay đổi ra sao, mà đó mới là lý do mở bảng. Nội dung dài hơn
	   thì cuộn trong thân bảng. */
	.mset {
		/* Đo theo KHUNG NHÌN chứ không theo % khung bản đồ: #ml-map có lúc báo
		   chiều rộng 0 (nó nằm tuyệt đối trong .vista__map), phần trăm của số 0
		   thì bảng teo lại thành một sợi. vw/vh thì luôn có số thật.
		   72vw chừa mỗi bên ~52px — đủ để cụm nút bên phải không bị bảng lấn. */
		width: min(72vw, 300px);
		height: min(58vh, 380px);
		padding: 12px 13px 8px;
		border-radius: 20px;
	}
	/* Chữ trong bảng cỡ vừa phải: bảng đã nhỏ lại thì cỡ chữ của bản máy tính
	   trông quá khổ, mỗi hàng ăn hết một mảng bảng. */
	.mset .mdock__dau h3, .mset .mdock__tieu { font-size: 16px; }
	.mset__than h4, .mset__than .mset__nhom { font-size: 11px; margin: 14px 2px 6px; }
	.mset .mdock__nhan { font-size: 13px; }
	.mset .mdock__r { padding: 8px 10px; }
	.mset .mdock__ico { width: 26px; height: 26px; border-radius: 7px; }
	.mset .mdock__ico svg { width: 15px; height: 15px; }
	.mset .mdock__ghi { font-size: 11.5px; }
	.mset .mdock__reset { font-size: 11px; }
}
/* ---- Cụm nút bên phải: CÙNG MỘT NGÔN NGỮ với thanh dock ----
   Trước đây mỗi cụm một kiểu: ba nút trắng vuông góc, nút phóng to xanh đậm to
   hơn hẳn, nút cài đặt lại nằm riêng — nhìn như ba món ghép tạm. Nay tất cả
   dùng chung nền kính mờ, cùng bo góc, cùng cỡ, chỉ khác nhau ở trạng thái. */
#ml-map .maplibregl-ctrl-group.ml-ctrl-extra {
	background: rgba(255, 255, 255, .86);
	-webkit-backdrop-filter: saturate(180%) blur(14px);
	backdrop-filter: saturate(180%) blur(14px);
	border: 1px solid rgba(60, 60, 58, .10);
	border-radius: 18px;
	overflow: hidden;
	box-shadow: 0 8px 24px rgba(40, 40, 36, .18) !important;
}
#ml-map .ml-ctrl-extra button.ml-ctrl-btn {
	width: 44px; height: 44px;
	background: none;
	color: var(--c-green-deep, #0b4a34);
	border-radius: 0;
	transition: background .18s ease, color .18s ease;
}
/* vạch tóc thụt lề giữa các nút cùng cụm, đúng kiểu các hàng trong bảng cài đặt */
#ml-map .ml-ctrl-extra button.ml-ctrl-btn + button.ml-ctrl-btn {
	box-shadow: inset 0 1px 0 rgba(60, 60, 58, .12);
}
#ml-map .ml-ctrl-extra button.ml-ctrl-btn:hover { background: rgba(120, 120, 128, .14); }
#ml-map .ml-ctrl-extra button.ml-ctrl-btn:active { background: rgba(120, 120, 128, .22); }
/* Nút phóng to hết cỡ: cùng nền kính như mọi nút, không còn khối xanh đậm to
   đùng — nó chỉ là một lệnh xem, không phải nút hành động chính của trang. */
#ml-map .ml-ctrl-fs button.ml-ctrl-btn {
	width: 44px; height: 44px;
	background: none;
	color: var(--c-green-deep, #0b4a34);
}
#ml-map .ml-ctrl-fs button.ml-ctrl-btn:hover { background: rgba(120, 120, 128, .14); }
#ml-map .ml-ctrl-fs { margin-top: 10px !important; }
#ml-map .ml-ctrl-cai { margin-bottom: 10px !important; }
/* trạng thái bật (nút 3D, nút định vị đang theo dõi): tô vàng như cũ nhưng nằm
   gọn trong khối bo góc */
#ml-map .ml-ctrl-extra button.ml-ctrl-btn.is-on {
	background: var(--c-gold, #d9a441);
	color: var(--c-green-deep, #0b4a34);
}
/* Mở bảng cài đặt thì MỌI thứ khác trên bản đồ lui hết: cụm 3 nút, nút phóng
   to, nút bánh răng và cả thanh 5 loại dưới đáy. Lúc đang chỉnh thì bảng là
   thứ duy nhất cần thấy; đóng bảng đã có nút × của chính nó và phím Esc. */
body.mset-mo #ml-map .maplibregl-ctrl-group.ml-ctrl-extra,
body.mset-mo #ml-map .mdock {
	opacity: 0; pointer-events: none;
}
#ml-map .maplibregl-ctrl-group.ml-ctrl-extra,
#ml-map .mdock { transition: opacity .18s ease; }
/* Dòng bản quyền OSM sau khi dọn vào bảng: chỉ là một dòng chữ mờ, không còn
   nền trắng và nút tròn của MapLibre. */
.mset .maplibregl-ctrl-attrib {
	background: none; margin: 12px 0 0; padding: 0;
	font-size: 11.5px; line-height: 1.5; color: var(--md-mo, #8a8880);
}
.mset .maplibregl-ctrl-attrib .maplibregl-ctrl-attrib-button { display: none; }
.mset .maplibregl-ctrl-attrib summary { display: none; }
.mset .maplibregl-ctrl-attrib-inner { display: block; }
.mset .maplibregl-ctrl-attrib a { color: var(--md-coral, #0f5e7c); text-decoration: none; }
.mset .maplibregl-ctrl-attrib a:hover { text-decoration: underline; }
/*gcm-mset-end*/





















/*gcm-mmon-start*/
/* ============================================================================
   DẢI LỌC THEO MÓN — nổi ngay trên thanh 5 loại địa điểm.
   CHỈ CÓ CHỮ, một hàng cuộn ngang. Đã thử 2 hàng cho thấy được nhiều món hơn mỗi màn, nhưng
   khối cao gấp đôi che mất một mảng bản đồ và trông nặng nề — chủ site chốt một
   hàng. Chỉ hiện khi nhóm "Ăn local" đang bật.
   ========================================================================== */
.mmon {
	position: absolute; z-index: 19;
	left: 50%; bottom: 70px;   /* sát ngay trên thanh 5 loại: hai thanh là một cụm điều khiển, hở nhiều thì rời rạc */
	transform: translateX(-50%);
	/* Khoá bề ngang bằng thanh 5 loại bên dưới thay vì để tràn gần hết bản đồ:
	   một dải dài suốt màn che mất chính cái bản đồ mà nó đang lọc. */
	width: max-content;
	max-width: min(380px, calc(100% - 24px));
	display: flex;
	flex-direction: column;
	padding: 8px 6px 6px;   /* 8px trên chừa cho tay kéo, xem .mmon__keo */
	background: rgba(255, 255, 255, .95);
	-webkit-backdrop-filter: saturate(180%) blur(14px);
	backdrop-filter: saturate(180%) blur(14px);
	border: 1px solid rgba(60, 60, 58, .14);
	border-radius: 20px;
	box-shadow: 0 8px 24px rgba(40, 40, 36, .18);
	transition: max-width .28s cubic-bezier(.32, .72, 0, 1), border-radius .28s ease;
}
.mmon[hidden] { display: none; }

/* ---- Tay kéo: MỘT dấu hiệu duy nhất ----
   Chỉ một vạch ngang kiểu bottom-sheet. Đã thử thêm mũi tên đổi chiều: hai dấu
   hiệu cho cùng một việc, mà xếp cạnh nhau lại đọc thành công tắc gạt.
   Vùng chạm cao 18px chứ không phải chỉ mấy pixel của cái vạch. */
.mmon__keo {
	/* Nằm ĐÈ lên mép trên chứ không chiếm một hàng riêng: dải chỉ cao thêm 8px
	   thay vì 18px, mà vùng chạm vẫn 14px nhờ tràn xuống một chút qua chip. */
	position: absolute; top: 0; left: 0; right: 0;
	height: 14px;
	display: flex; align-items: flex-start; justify-content: center;
	padding-top: 3px;
	cursor: grab; touch-action: none;
	color: rgba(60, 60, 58, .42);
}
.mmon__keo:active { cursor: grabbing; }
.mmon__keo i {
	width: 26px; height: 3px; border-radius: 3px;
	background: rgba(60, 60, 58, .26);
}
/* vạch dài ra một chút khi đang mở rộng — thay đổi duy nhất về hình dáng, đủ
   để biết trạng thái mà không thêm ký hiệu nào */
.mmon.is-rong .mmon__keo i { width: 36px; background: rgba(60, 60, 58, .34); }

/* ---- Danh sách chip ----
   Thu: một hàng cuộn ngang. Rộng: xuống hàng, cuộn dọc. */
.mmon__ds {
	display: flex;
	gap: 4px;
	/* KHÔNG cuộn ngang. Dải chỉ có một cử chỉ duy nhất: vuốt lên để mở rộng rồi
	   chọn. Trước đây vừa cuộn ngang vừa kéo dọc nên trên iPhone hai cử chỉ
	   giành nhau, mà cuộn ngang thì cũng chẳng ai đoán được còn bao nhiêu món
	   nằm khuất bên phải. */
	overflow: hidden;
	/* Mở/thu bằng chiều cao có chuyển động, để cảm giác là tấm trượt lên chứ
	   không phải một cái công tắc bật cái tách. */
	max-height: 42px;
	transition: max-height .3s cubic-bezier(.32, .72, 0, 1);
}
/* Đang kéo thì TẮT chuyển động: có chuyển động thì tấm chạy trễ sau ngón tay,
   thành ra vừa kéo vừa thấy nó đuổi theo. Thả ra mới bật lại để chạy nốt về nấc. */
.mmon.is-keo .mmon__ds { transition: none; }
.mmon.is-keo { transition: none; }
.mmon.is-rong { max-width: min(560px, calc(100% - 24px)); }
.mmon.is-rong .mmon__ds {
	flex-wrap: wrap;
	justify-content: center;
	overflow-x: hidden;
	overflow-y: auto;
	max-height: min(46vh, 320px);   /* khớp caoRong() trong map-dock.js */
	row-gap: 5px;
}

.mmon__o {
	display: flex; align-items: center;
	padding: 5px 12px;
	border: 0; border-radius: 13px;
	background: rgba(120, 120, 128, .13);
	cursor: pointer;
	font: inherit; color: var(--md-chu, #35342f);
	white-space: nowrap;
	transition: background .16s ease, color .16s ease;
}
/* Ảnh món đã bỏ: chip chỉ còn chữ nên dải ngắn hơn hẳn và đọc lướt nhanh hơn. */
.mmon__anh { display: none; }
.mmon__o:hover { background: rgba(120, 120, 128, .22); }
/* ĐANG CHỌN: tô nền bằng đúng màu nhóm "Ăn local" trong bảng màu đang dùng, chữ
   trắng. Trước đây chỉ khác nhau ở độ mờ nên nhìn lướt không biết đang lọc món
   nào; màu đặc thì thấy ngay từ xa, và trùng màu chấm quán ăn trên bản đồ nên
   chip với ghim đọc chung một mã màu. */
.mmon__o.is-chon {
	background: #e03a26;
	color: #fff;
}
.mmon__o.is-chon:hover { background: #9d3f2c; }
.mmon__ten { font-size: 12px; font-weight: 600; }
/* Số quán bỏ khỏi chip: chip chỉ còn đúng tên món cho ngắn và dễ đọc lướt.
   Số vẫn nằm trong tooltip (title) nên rê chuột vẫn biết món đó có mấy quán. */
.mmon__dem { display: none; }
/* "Tất cả" dùng chung màu đỏ với chip món: một trạng thái "đang chọn" thì phải
   có một màu, hai màu khác nhau khiến người xem đi tìm nghĩa của sự khác biệt. */

/* mở bảng cài đặt thì dải cũng lui như mọi thứ khác trên bản đồ */
body.mset-mo #ml-map .mmon { opacity: 0; pointer-events: none; }
/* Thẻ xem nhanh ngồi ngay trên dải món nên hai thứ chồng nhau — giấu dải trong
   lúc thẻ mở, trả lại khi đóng. */
body.the-mo #ml-map .mmon,
/* ...và cả cụm nút bên phải lẫn nút cài đặt: thẻ xem nhanh là lúc người ta đang
   đọc về MỘT chỗ, mọi nút điều khiển bản đồ lúc đó chỉ là nhiễu — mà trên màn
   hình hẹp chúng còn nằm đè lên mép thẻ. Dùng chung cách với lúc mở bảng cài
   đặt (body.mset-mo) để hai trạng thái hành xử giống nhau. */
body.the-mo #ml-map .maplibregl-ctrl-group.ml-ctrl-extra { opacity: 0; pointer-events: none; }
#ml-map .maplibregl-ctrl-group.ml-ctrl-extra { transition: opacity .18s ease; }
#ml-map .mmon { transition: opacity .18s ease; }

@media (max-width: 600px) {
	.mmon {
		bottom: 60px;
		max-width: min(300px, calc(100% - 16px));
	}
	.mmon.is-rong { max-width: calc(100% - 16px); }
	.mmon.is-rong .mmon__ds { max-height: min(46vh, 320px); }
	.mmon { padding: 8px 5px 5px; border-radius: 17px; }
	.mmon__ds { gap: 3px; }
	.mmon__o { padding: 4px 9px; gap: 5px; border-radius: 12px; }
	.mmon__ten { font-size: 11.5px; }
	.mmon__dem { font-size: 10px; }
}
/* Mở rộng dải món thì cụm nút bên phải (cài đặt, 3D, về nhà, định vị, phóng to)
   lui đi: dải chiếm gần hết bề ngang nên mấy nút đó nằm đè lên đúng vùng chip.
   Vẫn giữ chỗ trong bố cục, chỉ mờ đi và không bấm được — thu dải lại là chúng
   trở về ngay, không có cú nhảy layout nào. */
body.mon-rong #ml-map .maplibregl-ctrl-group.ml-ctrl-extra {
	opacity: 0;
	pointer-events: none;
}
/*gcm-mmon-end*/

/* Dải lúc thu: chỉ nhận cử chỉ dọc, mép phải mờ dần để lộ ra rằng còn món nữa
   ở phía sau — vuốt lên là thấy hết. */
.mmon, .mmon__ds { touch-action: none; }   /* dọc là của mình, ngang không còn dùng */
.mmon:not(.is-rong) .mmon__ds {
	-webkit-mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent 100%);
	mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent 100%);
}
.mmon.is-rong .mmon__ds { touch-action: pan-y; -webkit-mask-image: none; mask-image: none; }













/*gcm-mbao-start*/
/* Lời báo nổi giữa bản đồ (ví dụ: chọn quá 5 món). Không phải hộp thoại — không
   có nút bấm, không chặn thao tác, tự tắt sau vài giây. */
.mbao {
	position: absolute; z-index: 24;
	left: 50%; top: 50%;
	transform: translate(-50%, -50%) scale(.96);
	max-width: min(320px, calc(100% - 40px));
	padding: 12px 16px;
	border-radius: 16px;
	background: rgba(28, 33, 31, .92);
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
	color: #fff;
	font-size: 13.5px; font-weight: 600; line-height: 1.45;
	text-align: center;
	box-shadow: 0 14px 40px rgba(20, 20, 18, .3);
	opacity: 0; pointer-events: none;
	transition: opacity .16s ease, transform .16s cubic-bezier(.32, .72, 0, 1);
}
.mbao.is-hien { opacity: 1; transform: translate(-50%, -50%) scale(1); }
/*gcm-mbao-end*/

/*gcm-thumb-start*/
/* Nhãn của địa điểm ĐANG CÓ landmark thì bỏ ô ảnh nhỏ bên trái: cái ly, dĩa món
   hay mô hình công trình đứng ngay đó đã nói đủ, giữ thêm ô ảnh chỉ làm nhãn dài
   ra và chồng lên nhãn bên cạnh. Địa điểm chưa có landmark vẫn giữ ô ảnh. */
/* Quán đã có landmark (tô súp / ly cà phê) thì nhãn vẫn giữ Ô ẢNH NHỎ BÊN TRÁI
   dòng chữ như mọi ghim khác — đó là chỗ hợp lý duy nhất cho tấm ảnh.
   ĐÃ THỬ VÀ BỎ HẾT, đừng làm lại: lát ảnh vào lòng tô (miệng tô che); popup tròn
   bằng sprite 3D (lơ lửng); ô vuông đè lên nhãn (nhãn cao gấp đôi); ảnh to thay
   cho chấm ở zoom xa (bốn tô sát nhau thì không biết ảnh của tô nào); huy hiệu
   dán chân tô (vẫn là một vật thừa cạnh mô hình). */
#ml-map .ml-marker.is-co-landmark .ml-marker__thumb { display: block; }
/*gcm-thumb-end*/

/*gcm-de-start*/
/* ĐÃ BỎ toàn bộ luật .is-de (thu nhãn bị đè về chấm). Xem ghi chú trong main.js:
   phép đo nhãn chồng nhau tự sinh ra dao động, nay thay bằng "bấm thẳng vào
   landmark để mở thẻ".

   ---- Chỗ đã có landmark thì KHÔNG vẽ chấm ----
   Ly cà phê hay dĩa món đứng sẵn tại đó rồi; thêm một chấm dưới chân là đánh dấu
   hai lần cùng một quán. Class is-co-landmark do main.js gắn đúng lúc mô hình
   thật sự hiện, nên nhìn xa hơn mốc đó chấm vẫn còn. Chấm vẫn bắt được cú bấm,
   chỉ là trong suốt. */
#ml-map .ml-marker.is-co-landmark.is-cham .ml-marker__label {
	opacity: 0;
	box-shadow: none;
	border-color: transparent;
}
/*gcm-de-end*/

/*gcm-khongchon-start*/
/* Trên bản đồ: KHÔNG bôi đen chữ, KHÔNG bong bóng chú thích.
   Kéo bản đồ bằng chuột rất dễ quét trúng nhãn ghim rồi bôi đen cả cụm chữ; trên
   điện thoại thì giữ lâu một ghim là bật menu sao chép. Cả hai đều là thao tác
   người dùng không hề định làm.
   (Bong bóng title đã gỡ ở phía JS — thay bằng aria-label để trình đọc màn hình
   vẫn dùng được.) */
#ml-map, #ml-map * {
	-webkit-user-select: none;
	user-select: none;
	-webkit-touch-callout: none;
}
/* Trừ ô nhập liệu — nếu sau này có lại ô tìm kiếm thì vẫn gõ và chọn chữ được. */
#ml-map input, #ml-map textarea {
	-webkit-user-select: text;
	user-select: text;
}
/*gcm-khongchon-end*/

/*gcm-nhanmau-start*/
/* ---- Nhãn ghim mang MÀU CỦA NHÓM ----
   Trước đây mọi nhãn đều một màu xanh rêu đậm (--c-green-deep): nhìn bản đồ
   không phân biệt được đâu là điểm tham quan, đâu là quán ăn, trong khi thanh
   lọc bên dưới lại tô năm màu khác nhau — hai nơi nói hai thứ tiếng.
   Nay nhãn, đuôi nhãn và chấm đều lấy đúng màu nhóm. Đây là bộ màu DUY NHẤT
   cho nhóm; đổi màu chỉ cần sửa ở đây và trong CATS của map-dock.js.
   (Quán nhà giữ nguyên nhãn vàng riêng — nó không thuộc bảng màu nhóm.) */
/* Tham quan là nhóm ĐÔNG NHẤT trên bản đồ, nên nhãn của nó phải chịu được việc
   hiện hàng chục cái một lúc: xanh #2fa6ef sáng quá, cả vùng chói lên và nuốt
   mất mấy nhóm kia. Hạ xuống bản đậm hơn hai tông — vẫn cùng sắc xanh với ô
   "Tham quan" trên thanh lọc, chỉ trầm hơn. */
#ml-map .ml-marker--checkin.ml-marker--near .ml-marker__label { background: #17618f; }
#ml-map .ml-marker--checkin.ml-marker--near .ml-marker__tail { border-top-color: #17618f; }
#ml-map .ml-marker--checkin.ml-marker--near:hover .ml-marker__label { background: #114f75; }

#ml-map .ml-marker--tour.ml-marker--near .ml-marker__label { background: #b268dd; }
#ml-map .ml-marker--tour.ml-marker--near .ml-marker__tail { border-top-color: #b268dd; }
#ml-map .ml-marker--tour.ml-marker--near:hover .ml-marker__label { background: #9d53c9; }

/* Lục "Lân cận" cũng hạ tông như xanh "Tham quan": bản #22bd77 tươi quá, đứng
   trên nền bản đồ kem thì rực lên như đèn báo. */
#ml-map .ml-marker--xa.ml-marker--near .ml-marker__label { background: #147a4c; }
#ml-map .ml-marker--xa.ml-marker--near .ml-marker__tail { border-top-color: #147a4c; }
#ml-map .ml-marker--xa.ml-marker--near:hover .ml-marker__label { background: #0e633c; }

/* Quán ăn & cà phê KHÔNG có nền nhãn (xem khối gcm-nhan-tran ở cuối tệp) — màu
   nhóm chuyển vào màu CHỮ. Giữ nguyên hai lớp .--food.--near ở đây để cùng độ
   ưu tiên với các nhóm khác, chứ viết một lớp thì luật này lại thua. */
#ml-map .ml-marker--food.ml-marker--near .ml-marker__label { background: none; box-shadow: none; }
#ml-map .ml-marker--food.ml-marker--near:hover .ml-marker__label { background: none; color: #6f2717; }

#ml-map .ml-marker--cafe.ml-marker--near .ml-marker__label { background: none; box-shadow: none; }
#ml-map .ml-marker--cafe.ml-marker--near:hover .ml-marker__label { background: none; color: #4a2c1e; }

/* Quán nhà (nhãn vàng) phải thắng luật màu nhóm ở trên — nó là điểm neo của cả
   cẩm nang, không phải một mục trong bộ lọc. */
#ml-map .ml-marker--home.ml-marker--near .ml-marker__label { background: var(--c-gold, #e9b949); }
#ml-map .ml-marker--home.ml-marker--near .ml-marker__tail { border-top-color: var(--c-gold, #e9b949); }
/* BỎ ĐỔ BÓNG DƯỚI NHÃN.
   Bóng vốn để tách nhãn khỏi nền bản đồ, nhưng nhãn nay đã là khối màu đặc có
   đuôi nhọn — tự nó đã tách rồi. Khi hàng chục nhãn đứng cạnh nhau, mỗi cái một
   quầng tối phía dưới thì cả vùng trung tâm bị ám xám. */
#ml-map .ml-marker__label,
#ml-map .ml-marker--near .ml-marker__label,
#ml-map .ml-marker--home .ml-marker__label { box-shadow: none; }
/*gcm-nhanmau-end*/

/*gcm-gio-start*/
/* ---- Giỏ lịch trình: góc TRÁI TRÊN của bản đồ ----
   Đặt trái để không đụng cụm nút bên phải. Cùng chất kính mờ với thanh dock nên
   nhìn ra là cùng một hệ điều khiển. */
#ml-map .gio { position: absolute; z-index: 21; left: 12px; top: 12px; }
#ml-map .gio__nut {
	position: relative;
	width: 44px; height: 44px; padding: 0;
	display: grid; place-items: center;
	border: 1px solid rgba(60, 60, 58, .10);
	border-radius: 18px;
	background: rgba(255, 255, 255, .86);
	-webkit-backdrop-filter: saturate(180%) blur(14px);
	backdrop-filter: saturate(180%) blur(14px);
	box-shadow: 0 8px 24px rgba(40, 40, 36, .18);
	cursor: pointer;
	color: var(--c-green-deep, #0b4a34);
}
#ml-map .gio__nut svg {
	width: 21px; height: 21px; fill: none; stroke: currentColor;
	stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round;
}
/* Số đếm: chấm đỏ gạch của nhóm Ăn local… không, đây là lịch trình nên lấy xanh
   thương hiệu để không lẫn với nhóm nào trên bản đồ. */
#ml-map .gio__dem {
	position: absolute; top: -5px; right: -5px;
	min-width: 19px; height: 19px; padding: 0 5px;
	border-radius: 10px;
	background: var(--c-green-deep, #0b4a34); color: #fff;
	font: 700 11px/19px var(--font-sans, sans-serif); text-align: center;
	box-shadow: 0 2px 6px rgba(11, 74, 52, .4);
}
#ml-map .gio.is-rong .gio__dem { background: rgba(60, 60, 58, .45); }
/* nảy một nhịp mỗi lần thêm/bớt để biết cú bấm đã ăn */
#ml-map .gio__nut.is-nhay { animation: gioNhay .42s cubic-bezier(.34, 1.5, .64, 1); }
@keyframes gioNhay { 0% { transform: scale(1); } 45% { transform: scale(1.16); } 100% { transform: scale(1); } }

/* ---- Bảng xổ ra ---- */
#ml-map .gio__bang {
	position: absolute; left: 0; top: 52px;
	width: min(280px, calc(100vw - 40px));
	padding: 10px 10px 8px;
	border-radius: 18px;
	background: rgba(255, 255, 255, .95);
	-webkit-backdrop-filter: saturate(180%) blur(16px);
	backdrop-filter: saturate(180%) blur(16px);
	border: 1px solid rgba(60, 60, 58, .12);
	box-shadow: 0 14px 40px rgba(40, 40, 36, .24);
	color: var(--md-chu, #35342f);
}
#ml-map .gio__bang[hidden] { display: none; }
#ml-map .gio__dau {
	display: flex; align-items: center; justify-content: space-between;
	font-size: 13.5px; margin-bottom: 8px;
}
#ml-map .gio__dong {
	border: 0; background: none; cursor: pointer;
	font-size: 19px; line-height: 1; color: var(--md-mo, #8a8880); padding: 0 2px;
}
#ml-map .gio__ds { max-height: 46vh; overflow-y: auto; overscroll-behavior: contain; }
#ml-map .gio__d {
	display: flex; align-items: center; gap: 8px;
	padding: 5px 4px; border-radius: 11px;
}
#ml-map .gio__d + .gio__d { box-shadow: inset 0 1px 0 rgba(60, 60, 58, .1); }
#ml-map .gio__d img, #ml-map .gio__no {
	width: 34px; height: 34px; flex: 0 0 auto;
	border-radius: 9px; object-fit: cover; background: rgba(60, 60, 58, .1);
}
#ml-map .gio__ten {
	flex: 1 1 auto; min-width: 0; font-size: 12.5px; font-weight: 600;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#ml-map .gio__bo {
	flex: 0 0 auto; width: 22px; height: 22px; padding: 0;
	border: 0; border-radius: 50%; cursor: pointer;
	background: rgba(60, 60, 58, .09); color: var(--md-mo, #8a8880);
	font-size: 15px; line-height: 1;
}
#ml-map .gio__bo:hover { background: rgba(182, 74, 52, .16); color: #b64a34; }
#ml-map .gio__trong { margin: 6px 4px 10px; font-size: 12px; color: var(--md-mo, #8a8880); line-height: 1.5; }
#ml-map .gio__mo {
	display: block; margin-top: 8px; padding: 9px;
	border-radius: 12px; text-align: center; text-decoration: none;
	background: var(--c-green-deep, #0b4a34); color: #fff;
	font-size: 13px; font-weight: 700;
}
#ml-map .gio.is-rong .gio__mo { opacity: .45; pointer-events: none; }

/* mở bảng cài đặt / dải món rộng thì giỏ lui như mọi thứ khác */
body.mset-mo #ml-map .gio { opacity: 0; pointer-events: none; }
#ml-map .gio { transition: opacity .18s ease; }
/*gcm-gio-end*/

/*gcm-nhan-tran-start*/
/* QUÁN ĂN & CÀ PHÊ: NHÃN CHỈ CÒN CHỮ, BỎ NỀN.
   Hai nhóm này đông nhất (153 quán ăn, 34 cà phê) nên viên nhãn có nền đặc của
   chúng phủ kín cả khu trung tâm, che mất đường sá và cả mô hình 3D bên dưới.
   Chữ trần + viền trắng mỏng thì vẫn đọc rõ trên nền bản đồ sáng, mà nhìn tổng
   thể nhẹ hẳn. Các nhóm còn lại (tham quan, chơi, lân cận) ít ghim nên giữ
   nguyên viên nhãn — chúng là điểm nhấn chính của bản đồ. */
#ml-map .ml-marker--food.ml-marker--near .ml-marker__label,
#ml-map .ml-marker--cafe.ml-marker--near .ml-marker__label {
	background: none; box-shadow: none; padding: 2px 2px 2px 0; gap: 5px;
	text-shadow:
		0 0 3px #fff, 0 0 3px #fff,
		1px 1px 0 rgba(255, 255, 255, .95), -1px -1px 0 rgba(255, 255, 255, .95),
		1px -1px 0 rgba(255, 255, 255, .95), -1px 1px 0 rgba(255, 255, 255, .95);
}
#ml-map .ml-marker--food.ml-marker--near .ml-marker__label { color: #8f3423; }
#ml-map .ml-marker--cafe.ml-marker--near .ml-marker__label { color: #633d2b; }
/* Chữ đã trần thì cái đuôi nhọn thành một tam giác lạc lõng */
#ml-map .ml-marker--food .ml-marker__tail,
#ml-map .ml-marker--cafe .ml-marker__tail { display: none; }
/* Ô ảnh nhỏ giữ lại nhưng thêm viền trắng, vì nay nó nằm thẳng trên nền bản đồ */
#ml-map .ml-marker--food .ml-marker__thumb,
#ml-map .ml-marker--cafe .ml-marker__thumb {
	box-shadow: 0 0 0 2px #fff, 0 2px 5px rgba(30, 30, 28, .28);
}
#ml-map .ml-marker--food .ml-marker__dist,
#ml-map .ml-marker--cafe .ml-marker__dist { color: inherit; opacity: .78; }
/* CHẤM TRÒN Ở ZOOM XA VẪN PHẢI CÓ MÀU.
   Cái chấm dùng chính phần tử nhãn (thu về hình tròn 11px), nên luật "bỏ nền"
   ở trên vô tình làm nó rỗng ruột — nhìn ra một vòng tròn trắng vô nghĩa.
   Trả nền màu nhóm lại cho riêng trạng thái .is-cham, độ ưu tiên cao hơn một
   lớp để không phải phụ thuộc thứ tự dòng. */
#ml-map .ml-marker--food.ml-marker--near.is-cham .ml-marker__label,
#ml-map .ml-marker--cafe.ml-marker--near.is-cham .ml-marker__label {
	background: var(--cham-mau, #8a8880);
	box-shadow: 0 1px 5px rgba(30, 30, 28, .38);
}
#ml-map .ml-marker--food.ml-marker--near.is-cham:hover .ml-marker__label,
#ml-map .ml-marker--cafe.ml-marker--near.is-cham:hover .ml-marker__label {
	background: var(--cham-mau, #8a8880);
}
/* QUÁN NHÀ PHẢI NỔI HẲN LÊN.
   Gỏi Cá Mai Cô Hằng cũng mang lớp --food nên bị luật "nhãn trần" ở trên quét
   trúng: nền vàng biến mất, chữ mọc viền trắng, đứng lẫn giữa 153 quán khác.
   Nó là điểm neo của cả cẩm nang chứ không phải một mục trong bộ lọc — trả lại
   nền vàng đặc, chữ xanh KHÔNG viền, thêm vệt gương quét ngang để mắt bắt được
   ngay giữa một rừng chữ trần. Ba lớp trong bộ chọn để chắc chắn thắng. */
#ml-map .ml-marker--home.ml-marker--near.ml-marker--food .ml-marker__label,
#ml-map .ml-marker--home.ml-marker--near .ml-marker__label {
	background: var(--c-gold, #e9b949);
	color: var(--c-green-deep, #0b4a34);
	text-shadow: none;
	padding: 8px 16px;
	box-shadow: 0 4px 16px rgba(233, 185, 73, .5);
	position: relative; overflow: hidden;
}
#ml-map .ml-marker--home.ml-marker--near .ml-marker__dist { color: rgba(11, 74, 52, .72); }
/* Không ô ảnh bên trái: ngay trên nhãn đã là mô hình dĩa gỏi, thêm tấm ảnh nhỏ
   của chính dĩa gỏi đó là nói hai lần cùng một thứ mà nhãn lại dài thêm. */
#ml-map .ml-marker--home.ml-marker--near .ml-marker__thumb { display: none; }
/* Không mũi nhọn: nhãn quán nhà nằm ngay dưới chân mô hình dĩa gỏi rồi, thêm
   tam giác chỉ xuống là chỉ vào mặt đường trống. */
#ml-map .ml-marker--home.ml-marker--near .ml-marker__tail { display: none; }
/* Vệt gương: chỉ lướt qua mỗi vài giây, không phải nhấp nháy liên tục — nhấp
   nháy thì thành biển quảng cáo, mà mắt cũng chóng mệt. */
#ml-map .ml-marker--home.ml-marker--near .ml-marker__label::after {
	content: ''; position: absolute; inset: 0; pointer-events: none;
	background: linear-gradient(104deg,
		rgba(255, 255, 255, 0) 36%,
		rgba(255, 255, 255, .78) 50%,
		rgba(255, 255, 255, 0) 64%);
	transform: translateX(-130%);
	animation: gcm-quet-guong 4.2s cubic-bezier(.4, 0, .2, 1) infinite;
}
@keyframes gcm-quet-guong {
	0%, 62% { transform: translateX(-130%); }
	100%    { transform: translateX(130%); }
}
@media (prefers-reduced-motion: reduce) {
	#ml-map .ml-marker--home.ml-marker--near .ml-marker__label::after { animation: none; opacity: 0; }
}
/* Ở mức pins-icon (zoom < 15) bản đồ giấu hết chữ, nhãn chỉ còn ô ảnh. Quán nhà
   vừa bị bỏ ô ảnh nên nhãn của nó rỗng ruột — ra một viên vàng trống trơn, đúng
   cái fen thấy. Ở mức đó cho nó thu về CHẤM VÀNG luôn. */
#ml-map.pins-icon .ml-marker--home.ml-marker--near .ml-marker__label,
#ml-map.pins-md .ml-marker--home.ml-marker--near .ml-marker__label {
	width: 13px; height: 13px; padding: 0; gap: 0; overflow: hidden;
	border-radius: 50%; border: 2px solid #fff;
	background: var(--c-gold, #e9b949);
	box-shadow: 0 1px 6px rgba(30, 30, 28, .4);
}
#ml-map.pins-icon .ml-marker--home .ml-marker__txt,
#ml-map.pins-md .ml-marker--home .ml-marker__txt,
#ml-map.pins-icon .ml-marker--home .ml-marker__tail,
#ml-map.pins-md .ml-marker--home .ml-marker__tail { display: none; }
#ml-map.pins-icon .ml-marker--home .ml-marker__label::after,
#ml-map.pins-md .ml-marker--home .ml-marker__label::after { display: none; }

/* QUÁN NHÀ Ở ZOOM XA CŨNG PHẢI LÀ CHẤM.
   Luật nhãn vàng ở trên đặt cả padding lẫn nền, độ ưu tiên cao hơn luật thu về
   chấm, nên khi zoom ra nó thành một viên vàng rỗng không chữ. Trả lại đúng
   hình chấm, giữ màu vàng để vẫn nhận ra ngay giữa các chấm đỏ/nâu. */
#ml-map .ml-marker--home.ml-marker--near.is-cham .ml-marker__label,
#ml-map .ml-marker--home.ml-marker--near.ml-marker--food.is-cham .ml-marker__label {
	width: 13px; height: 13px; padding: 0; gap: 0;
	border-radius: 50%; border: 2px solid #fff;
	background: var(--c-gold, #e9b949);
	box-shadow: 0 1px 6px rgba(30, 30, 28, .4);
}
#ml-map .ml-marker--home.ml-marker--near.is-cham .ml-marker__label::after { display: none; }
/*gcm-nhan-tran-end*/

/*gcm-muot-start*/
/* ĐỔI GIỮA "VIÊN CHỮ" VÀ "CHẤM TRÒN" BẰNG MỘT NHỊP MỜ.
   Đã thử cho hai hình thái morph vào nhau (chạy width/padding/background cùng
   lúc): giữa chừng luôn có một vệt màu phình ra rồi thu lại, nhìn như nhãn bị
   tô nền — bỏ. Chớp một nhịp 0.18s thì không có hình trung gian nào để mắt bắt
   lỗi, mà vẫn hết cảm giác "bụp" của bản gốc. */
#ml-map .ml-marker__label.dang-doi {
	animation: gcm-nhan-doi .18s cubic-bezier(.32, .72, 0, 1);
}
@keyframes gcm-nhan-doi {
	from { opacity: 0; transform: scale(.94); }
	to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
	#ml-map .ml-marker__label.dang-doi { animation: none; }
}
/* Nhịp rải ghim khi bật một nhóm hoặc một món (xem raiGhim trong map-dock.js).
   Nảy nhẹ 4% rồi về, đủ để mắt thấy "nó vừa đáp xuống" mà không thành nhún nhảy. */
#ml-map .ml-marker.ghim-vao { animation: gcm-ghim-vao .34s cubic-bezier(.34, 1.32, .64, 1) both; }
@keyframes gcm-ghim-vao {
	0%   { opacity: 0; transform: translateY(-6px) scale(.78); }
	60%  { opacity: 1; transform: translateY(0) scale(1.04); }
	100% { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
	#ml-map .ml-marker.ghim-vao { animation: none; }
}
/* Thẻ xem nhanh TRƯỢT LÊN thay vì hiện đánh bụp. 14px là quãng vừa đủ để đọc ra
   hướng chuyển động mà không thành cú nhảy. */
#ml-map .mpop:not([hidden]) { animation: gcm-pop-len .2s cubic-bezier(.32, .72, 0, 1); }
@keyframes gcm-pop-len {
	from { opacity: 0; transform: translateY(14px) scale(.985); }
	to   { opacity: 1; transform: none; }
}
/* Ghim lún xuống khi bấm — phản hồi tức thì cho ngón tay, trước cả khi thẻ mở */
#ml-map .ml-marker:active .ml-marker__label { transform: scale(.94); }
/* Số trong giỏ nảy khi thêm/bớt điểm */
#ml-map .gio__dem.nhay { animation: gcm-gio-nhay .34s cubic-bezier(.34, 1.5, .64, 1); }
@keyframes gcm-gio-nhay {
	0%   { transform: scale(1); }
	38%  { transform: scale(1.42); }
	100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
	#ml-map .mpop:not([hidden]),
	#ml-map .gio__dem.nhay { animation: none; }
	#ml-map .ml-marker:active .ml-marker__label { transform: none; }
}
/*gcm-muot-end*/

/*gcm-fs-start*/
/* ============================================================================
   TOÀN MÀN HÌNH — MỘT LUẬT DUY NHẤT CHO MỌI TRANG

   Hai lỗi cùng một gốc: mỗi trang tự viết luật toàn màn hình của mình, mà luật
   nào cũng thua luật nền `#ml-map { height: var(--map-h) }`.

   - Trang địa điểm: `.map-pane:fullscreen #ml-map { height: 100% }` chỉ có hai
     lớp, thua bộ chọn một ID. Bản đồ vào toàn màn hình mà vẫn cao đúng 72vh,
     phần dưới bị cắt cụt.
   - Trang lịch trình: khung `.plan-map` được ép 100vw/100vh nhưng con bên trong
     giữ nguyên bo góc và lề, thành ra tràn ra ngoài mép.

   Luật dưới đây dùng `:fullscreen #ml-map` — một ID cộng một pseudo-class, nên
   thắng mọi luật chiều cao mặc định, và không cần biết trang nào bọc bản đồ
   bằng khung gì. Viết ở map-dock.css vì tệp này nạp trên mọi trang có bản đồ. */
:fullscreen, :-webkit-full-screen {
	width: 100vw; height: 100vh; max-height: 100vh;
	margin: 0; padding: 0; border-radius: 0; overflow: hidden;
	background: var(--c-cream, #f7f6f2);
}
:fullscreen #ml-map,
:-webkit-full-screen #ml-map,
#ml-map:fullscreen,
#ml-map:-webkit-full-screen {
	position: absolute; inset: 0;
	width: 100%; height: 100%; max-height: none;
	border-radius: 0;
}
/* Bản dự phòng cho iPhone (không có Fullscreen API): dùng class thay pseudo. */
body.map-is-fs #ml-map,
body.map-is-fs .map-pane #ml-map {
	position: fixed; inset: 0;
	width: 100%; height: 100dvh; max-height: none;
	border-radius: 0; z-index: 9999;
}
/* Trang lịch trình bọc bản đồ trong .plan-map và CHÍNH KHUNG ĐÓ được ghim fixed
   (xem planner.css), nên bản đồ bên trong chỉ cần lấp đầy khung. */
body.map-is-fs .plan-map #ml-map {
	position: absolute; inset: 0;
	width: 100%; height: 100%; border-radius: 0;
}
/*gcm-fs-end*/

/*gcm-nut-nho-start*/
/* CỤM NÚT BÊN PHẢI THU NHỎ TRÊN ĐIỆN THOẠI — ĐẶT Ở CUỐI TỆP.
   Đã viết luật này trong khối @media ở giữa tệp, nhưng luật gốc `width: 44px`
   nằm SAU nó vài chục dòng; hai bên cùng độ ưu tiên nên cái viết sau thắng —
   chữ nhỏ đi (luật chữ không bị đè) mà nút vẫn to nguyên. Chuyển xuống cuối là
   xong, không cần !important. */
@media (max-width: 600px) {
	#ml-map .ml-ctrl-extra button.ml-ctrl-btn,
	#ml-map .ml-ctrl-fs button.ml-ctrl-btn { width: 28px; height: 28px; }
	#ml-map .ml-ctrl-extra button.ml-ctrl-btn svg,
	#ml-map .ml-ctrl-fs button.ml-ctrl-btn svg { width: 14px; height: 14px; }
	#ml-map .ml-ctrl-extra button.ml-ctrl-btn--3d { font-size: 10.5px; }
	#ml-map .maplibregl-ctrl-group.ml-ctrl-extra,
	#ml-map .maplibregl-ctrl-group.ml-ctrl-fs,
	#ml-map .maplibregl-ctrl-group.ml-ctrl-cai { border-radius: 11px; }
	#ml-map .ml-ctrl-fs { margin-top: 6px !important; }
	#ml-map .ml-ctrl-cai { margin-bottom: 6px !important; }
	#ml-map .maplibregl-ctrl-top-right { margin: 6px 6px 0 0; }
}
/*gcm-nut-nho-end*/

/* ==========================================================================
   MÀN CHỜ KHI MỞ BẢN ĐỒ                                     (gcm-man-cho-start)
   Che trọn quãng dựng dở: nền be -> biển lật xanh -> đường -> nhãn. Nền màn chờ
   lấy đúng màu nền của bản đồ nên lúc tan không có bậc màu nào.
   ========================================================================== */
#ml-map { background: #f4f1e9; }

.ml-nap {
	position: absolute; inset: 0; z-index: 6;
	display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
	background: #f4f1e9;
	transition: opacity .42s ease;
}
.ml-nap.la-tan { opacity: 0; pointer-events: none; }

.ml-nap__vong {
	width: 30px; height: 30px; border-radius: 50%;
	border: 2.5px solid rgba(11, 74, 52, .16);
	border-top-color: var(--md-nhan, #1c864d);
	animation: ml-quay .8s linear infinite;
}
@keyframes ml-quay { to { transform: rotate(360deg); } }

.ml-nap__chu {
	font: 600 13px/1 var(--font-sans, sans-serif);
	color: rgba(11, 74, 52, .55);
	letter-spacing: .01em;
}

/* Canvas và cụm nút vẫn hiện dần bên dưới màn chờ, để lúc màn tan ra thì thứ
   phía sau đã ở trạng thái đầy đủ chứ không bật thêm một nhịp nữa. */
#ml-map.gcm-dang-nap .maplibregl-canvas-container,
#ml-map.gcm-dang-nap canvas { opacity: 0; }
#ml-map .maplibregl-canvas-container,
#ml-map canvas { transition: opacity .45s ease; }
#ml-map.gcm-dang-nap .maplibregl-control-container,
#ml-map.gcm-dang-nap .ml-ctrl-extra { opacity: 0; }
#ml-map .maplibregl-control-container,
#ml-map .ml-ctrl-extra { transition: opacity .45s ease; }

@media (prefers-reduced-motion: reduce) {
	.ml-nap__vong { animation-duration: 2.4s; }
	#ml-map .maplibregl-canvas-container,
	#ml-map canvas,
	#ml-map .maplibregl-control-container,
	#ml-map .ml-ctrl-extra { transition: none; }
}
/*gcm-man-cho-end*/

/*gcm-goiy-keo-start*/
/* ==========================================================================
   HƯỚNG DẪN KÉO DẢI MÓN — chạy một lần mỗi lượt tải trang, ngay khi người xem
   tự bật nhóm "Ăn local" (map-dock.js: goiYKeoMon).

   Ba lớp cùng nói một việc: nhãn chữ nói bằng lời, vòng ngón tay diễn cử chỉ,
   và dải tự mở hé để cho thấy kết quả. Bản trước chỉ nhún lên xuống — thấy động
   nhưng không hiểu phải làm gì.
   ========================================================================== */

/* ---- 1. Nhãn chữ nổi trên dải ---- */
.mmon.is-goi-y::before {
	content: var(--goiy-chu, "Kéo lên để xem thêm món");
	position: absolute;
	left: 50%; bottom: calc(100% + 12px);
	transform: translateX(-50%);
	white-space: nowrap;
	padding: 7px 15px;
	border-radius: 999px;
	background: rgba(35, 34, 31, .93);
	-webkit-backdrop-filter: blur(6px);
	backdrop-filter: blur(6px);
	color: #fff;
	font-size: 12.5px; font-weight: 600; letter-spacing: .01em;
	box-shadow: 0 8px 22px rgba(40, 40, 36, .3);
	pointer-events: none;
	animation: goiYNhan 3.7s ease both;
}
/* mũi nhọn nhỏ chỉ xuống dải, để nhãn dính vào đúng đối tượng nó đang nói */
.mmon.is-goi-y::after {
	content: '';
	position: absolute;
	left: 50%; bottom: calc(100% + 6px);
	width: 0; height: 0;
	transform: translateX(-50%);
	border: 6px solid transparent;
	border-top-color: rgba(35, 34, 31, .93);
	pointer-events: none;
	animation: goiYNhan 3.7s ease both;
}
@keyframes goiYNhan {
	0%        { opacity: 0; transform: translate(-50%, 8px); }
	8%, 88%   { opacity: 1; transform: translate(-50%, 0); }
	100%      { opacity: 0; transform: translate(-50%, -5px); }
}

/* ---- 2. Vòng "ngón tay" trượt lên từ chỗ tay kéo ---- */
.mmon.is-goi-y .mmon__keo::after {
	content: '';
	position: absolute;
	left: 50%; top: 0;
	width: 24px; height: 24px;
	margin-left: -12px;
	box-sizing: border-box;
	border-radius: 50%;
	border: 2px solid rgba(224, 58, 38, .6);
	background: radial-gradient(circle at 50% 50%, rgba(224, 58, 38, .3), rgba(224, 58, 38, 0) 68%);
	pointer-events: none;
	animation: goiYNgonTay 1.3s cubic-bezier(.32, .72, 0, 1) 3;
}
@keyframes goiYNgonTay {
	0%   { opacity: 0; transform: translateY(10px) scale(.6); }
	16%  { opacity: 1; transform: translateY(4px) scale(1); }
	64%  { opacity: .9; transform: translateY(-26px) scale(1); }
	100% { opacity: 0; transform: translateY(-38px) scale(.92); }
}

/* ---- 3. Vạch kéo sáng lên theo cùng nhịp ---- */
.mmon.is-goi-y .mmon__keo i {
	animation: goiYVach 1.3s cubic-bezier(.32, .72, 0, 1) 3;
}
@keyframes goiYVach {
	0%, 100% { width: 26px; background: rgba(60, 60, 58, .26); }
	40%      { width: 46px; background: #e03a26; }
}

/* ---- 4. Mở hé THẬT: dùng lại đúng bố cục và chuyển động của .is-rong,
   nhưng là lớp RIÊNG nên không ghi trạng thái, không làm cụm nút bên phải lui.
   Chỉ hé ~3 hàng — mở hết thì hết cái để người ta tự kéo. ---- */
.mmon.is-xem-truoc { max-width: min(560px, calc(100% - 24px)); }
.mmon.is-xem-truoc .mmon__ds {
	flex-wrap: wrap;
	justify-content: center;
	overflow: hidden;
	max-height: 128px;
	row-gap: 5px;
}

@media (max-width: 600px) {
	.mmon.is-xem-truoc { max-width: calc(100% - 16px); }
	.mmon.is-xem-truoc .mmon__ds { max-height: 112px; }
	.mmon.is-goi-y::before { font-size: 11.5px; padding: 6px 12px; }
}

@media (prefers-reduced-motion: reduce) {
	.mmon.is-goi-y::before, .mmon.is-goi-y::after,
	.mmon.is-goi-y .mmon__keo::after, .mmon.is-goi-y .mmon__keo i { animation: none; }
	.mmon.is-goi-y .mmon__keo::after { display: none; }
}
/*gcm-goiy-keo-end*/



/*gcm-chup-start*/
/* ---- Hộp xem trước ảnh bản đồ ----
   Chụp xong KHÔNG tải thẳng về máy: người xem phải thấy ảnh rồi mới quyết định.
   Một tệp lặng lẽ rơi vào thư mục Tải về là thứ khó chịu nhất của các nút chụp. */
.ml-chup {
	position: fixed; inset: 0; z-index: 10000;
	display: flex; align-items: center; justify-content: center;
	padding: 20px;
	background: rgba(20, 20, 18, .58);
	-webkit-backdrop-filter: blur(4px);
	backdrop-filter: blur(4px);
	animation: mlChupVao .18s ease both;
}
@keyframes mlChupVao { from { opacity: 0; } }
.ml-chup__hop {
	width: min(880px, 100%);
	max-height: 100%;
	display: flex; flex-direction: column;
	background: #fff;
	border-radius: 18px;
	box-shadow: 0 24px 60px rgba(20, 20, 18, .4);
	overflow: hidden;
	animation: mlHopVao .24s cubic-bezier(.32, .72, 0, 1) both;
}
@keyframes mlHopVao { from { opacity: 0; transform: translateY(12px) scale(.98); } }
.ml-chup__dau {
	display: flex; align-items: center; justify-content: space-between;
	gap: 10px; padding: 13px 16px;
	border-bottom: 1px solid rgba(60, 60, 58, .12);
	font-size: 15px;
}
.ml-chup__dong {
	border: 0; background: rgba(120, 120, 128, .14);
	width: 30px; height: 30px; border-radius: 50%;
	cursor: pointer; font-size: 14px; line-height: 1;
	color: var(--md-chu, #35342f);
}
.ml-chup__dong:hover { background: rgba(120, 120, 128, .24); }
.ml-chup__xem {
	padding: 14px; overflow: auto;
	background: repeating-conic-gradient(rgba(0,0,0,.035) 0 25%, transparent 0 50%) 0 0 / 18px 18px;
}
.ml-chup__nut {
	display: flex; gap: 9px; justify-content: flex-end;
	padding: 12px 16px;
	border-top: 1px solid rgba(60, 60, 58, .12);
}
.ml-chup__phu, .ml-chup__chinh {
	border: 0; border-radius: 11px; padding: 10px 20px;
	font: inherit; font-weight: 700; font-size: 14px; cursor: pointer;
}
.ml-chup__phu { background: rgba(120, 120, 128, .14); color: var(--md-chu, #35342f); }
.ml-chup__phu:hover { background: rgba(120, 120, 128, .24); }
.ml-chup__chinh { background: #e03a26; color: #fff; }
.ml-chup__chinh:hover { background: #b93520; }
/* nút đang chụp: mờ đi cho biết đang bận, chặn bấm lần hai */
.ml-ctrl-btn.is-busy { opacity: .5; pointer-events: none; }
@media (max-width: 600px) {
	.ml-chup { padding: 12px; }
	.ml-chup__nut { justify-content: stretch; }
	.ml-chup__phu, .ml-chup__chinh { flex: 1 1 0; }
}
/*gcm-chup-end*/

/*gcm-bang-mau-start*/
/* ---- Bảng màu dựng sẵn ----
   Mỗi thẻ là một dải bốn ô màu + tên. Dải màu nói nhanh hơn tên gọi: mắt chọn
   theo màu chứ không đọc chữ "Hoàng hôn" rồi tưởng tượng. */
.mbang__luoi {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 7px;
}
.mbang {
	display: flex; flex-direction: column; align-items: stretch; gap: 5px;
	padding: 6px 6px 7px;
	border: 1.5px solid transparent;
	border-radius: 12px;
	background: rgba(120, 120, 128, .1);
	cursor: pointer;
	font: inherit;
	transition: background .16s ease, border-color .16s ease, transform .16s ease;
}
.mbang:hover { background: rgba(120, 120, 128, .18); transform: translateY(-1px); }
.mbang.is-chon { border-color: #e03a26; background: rgba(224, 58, 38, .1); }
.mbang__oo {
	display: flex; height: 26px; border-radius: 7px; overflow: hidden;
	/* Viền mảnh để bộ nào cũng thấy được rìa ô, kể cả bộ gần trắng. */
	box-shadow: inset 0 0 0 1px rgba(60, 60, 58, .12);
}
.mbang__oo i { flex: 1 1 0; display: block; }
/* Ô ĐẦU (nền) rộng gấp đôi: nền là thứ chiếm phần lớn bản đồ, ô xem trước nên
   phản ánh đúng tỉ lệ đó thay vì chia đều bốn phần bằng nhau. */
.mbang__oo i:first-child { flex: 2 1 0; }
.mbang__ten {
	font-size: 10.5px; font-weight: 600; line-height: 1.15;
	color: var(--md-chu, #35342f);
	text-align: center;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Thẻ "Nguyên bản" đứng đầu, đánh dấu bằng nét đứt cho khác hẳn các bộ dựng sẵn
   — nó là đường lùi chứ không phải một lựa chọn thẩm mỹ ngang hàng. */
.mbang--goc { border-style: dashed; border-color: rgba(60, 60, 58, .28); }
.mbang--goc.is-chon { border-style: solid; border-color: #e03a26; }
@media (max-width: 600px) {
	.mbang__ten { font-size: 10px; }
}
/*gcm-bang-mau-end*/
