/* =========================================================================
   LAYOUT — tầng KHUNG của theme (file 1/2, nạp TRƯỚC style.css)

   Hợp đồng 2 file (triage 2026-08-22):
   • layout.css  = KHUNG: site frame, grid, và toàn bộ máy móc overlay/bar/dock
                   (modal .layer/#actions, bottom bar + filter/destinations
                   popup, chat teaser/window). Không style component ở đây.
   • style.css   = BASIC + ENHANCE: token, base, component, trang, WC overrides;
                   đuôi file là khối ENHANCE (các cụm skin chuyển từ ut.css cũ,
                   giữ nguyên thứ tự gốc — vị trí CUỐI là cố ý, vài rule thắng
                   nhờ cascade: Book Now var(--color), inclusion padding 15px).
   Thứ tự nạp do dependency 'tb-layout' → 'tb-main' đảm bảo (functions.php +
   inc/enqueue.php), không dựa thứ tự đăng ký.

   Mục lục:
     1. Site wrapper / Header–Footer placeholder / Grid / Stack / PAGE
     2. Loop <ul> khung (ul.products block + center)
     3. #actions: layer docked ↔ popup, tab bar
     4. Bottom bar trang loop: in-flow ↔ dock, filter popup (.ut-fpop) + busy
        ring, destinations inline/in-flow/popup
     5. Layer scroll polish (mask + scrollbar)
     6. Chat teaser + chat window height (overlay của ut-assistant)

   Cụm nhòe đã CHỐT (triage 22/08): base .layer (vỏ backdrop fixed), chiều cao
   modal 88% và loop card 35/65 Ở LẠI style.css — chúng là DESIGN của owner;
   file này chỉ giữ máy móc ĐỔI VAI (docked ↔ popup, in-flow ↔ dock, popup
   position). Sửa hình dạng modal/card → style.css; sửa cơ chế bay/neo → đây.

   ⚠️ CẤM viết chuỗi kiểu hàm calc/min/max/clamp kèm ngoặc mở trong COMMENT —
   regex hide-calc của Autoptimize ăn xuyên comment (đã cắn 2026-08-09).
   ========================================================================= */

.wid {width: 1200px !important; max-width: calc(100% - 40px) !important; margin: 0 auto !important;}

/* -------- Site wrapper -------- */
.site {
	display: flex;
	flex-direction: column;
	min-height: 100vh;
}

.site-main {
	flex: 1 0 auto;
}

/* -------- Header (placeholder — your custom design overrides this) -------- */
.site-header {
	position: relative;
	background-color: var(--color-bg);
	border-bottom: 1px solid var(--color-border);
}

/* -------- Footer (placeholder — your custom design overrides this) -------- */
.site-footer {
	background-color: var(--color-bg-dark);
	color: var(--color-text-inverse);
}

/* -------- Grid utilities -------- */
.grid {
	display: grid;
	gap: var(--space-5);
}

.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 1024px) {
	.grid-4 { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 768px) {
	.grid-3, .grid-4 { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 480px) {
	.grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
}

/* -------- Stack (vertical spacing helper) -------- */
.stack > * + * {
	margin-top: var(--space-4);
}

.stack-lg > * + * {
	margin-top: var(--space-6);
}

/* -------- PAGE -------- */

.entry-header,
body.page .site-content {padding: 80px 150px; background: #fff; border-radius: 10px; width: 1200px; max-width: calc(100% - 40px); margin: 30px auto;}

@media screen and (max-width: 1200px) {
	body.page .site-content {padding: 40px 80px; width: 1000px;}
}
@media screen and (max-width: 900px) {
	body.page .site-content {padding: 20px; border-radius: 0; margin: 0; max-width: 100%;}
}

body.page #page.site {background: #f8f8f8;}
body.page.page-template-page-fullwidth #page.site {background: unset;}

body.page.page-template-page-fullwidth .site-content .entry-content > * {width: 1200px; max-width: calc(100% - 40px); margin: 0 auto; display: block;}

body.page #page.site .page-header {background: #eee;}


body {background: #fff}
body.archive.woocommerce,
body.single.woocommerce {background: #eee}
header.site-header {background: #fff; height: 100px;}

.site-content {width: 100%; max-width: 100%; margin: 0 auto;}


.s-wrap,
.woocommerce-tabs {width: var(--wid); max-width: var(--max); margin: 0 auto;}


@media screen and (max-width: 1250px) {
	.woocommerce-tabs {max-width: 100%;}
}

@media screen and (max-width: 650px) {
	.woocommerce-tabs {max-width: 100%;}
}
@media screen and (max-width: 500px) {
	.woocommerce-tabs {max-width: 100%;}
}




/* ---------------------------------------------------------------------------
   WooCommerce loop: the razzi-child loop design lives in style.css. The
   scaffold's competing grid/card block was removed from
   assets/css/woocommerce.css so style.css governs the loop. Here we only keep
   the <ul> a plain block (full-width horizontal cards) and center it.
   --------------------------------------------------------------------------- */
.woocommerce ul.products,
.woocommerce-page ul.products,
ul.products {
  display: block;
  margin: 0 auto 30px auto;
}





/* ─── #actions DOCKED (2026-08-04): cùng MỘT node hai vai — ngồi inline cuối
   phần mô tả (is-docked) / bay lên popup (.open, flow cũ nguyên byte vì JS gỡ
   is-docked trước khi thêm open). Vỏ .layer vốn LÀ backdrop đen fixed 0×0 nên
   docked phải trung hoà trọn bộ vỏ. ── */
.layer.is-docked {position: static; width: auto; height: auto; opacity: 1;
	overflow: visible; background: none; backdrop-filter: none; display: block;
	transition: none; margin: 30px 0 0;     background-image: linear-gradient(125deg, #6492b2, #d2e6f6);
    padding: 150px 20px;
    margin: 0 auto;
    border-radius: 10px;}

@media screen and (max-width: 500px) {
	.layer.is-docked {padding: 50px 20px;}
}

.layer.is-docked .layer-header {overflow: hidden;}


.layer.is-docked .layer-body {opacity: 1; width: 100%; max-width: 100%; display: flex; flex-direction: column; background: #fff; border-radius: 5px; max-height: none; overflow: visible; margin: 0 auto;}
.layer.is-docked .layer-content {overflow: visible;}
.layer.is-docked .layer-close {display: none;} /* không có gì để đóng khi docked */
/* Popup phủ luôn bottom bar (bar fixed z-1000, trước đây hoà z và thắng nhờ
   DOM order — owner chốt backdrop đè bar). ID nên thắng mọi thứ tự nạp css. */
#actions {z-index: 1001;}

/* ─── Modal chung #actions (2026-07-21): tab bar giả lập button bottom-bar ── */
#actions .layer-body {width: 700px;}
#actions .layer-header {align-items: stretch;}
.ut-actions-tabs {display: flex; flex: 1; min-width: 0; overflow-x: auto;}
.ut-actions-tab {display: flex; flex-direction:column; align-items: center; padding: 10px 12px; background: transparent; border: none; font-size: 11px; font-weight: bold; text-transform: uppercase; color: var(--color-dark-blue, #16324c); cursor: pointer; white-space: nowrap; gap: 5px;}
.ut-svg-icon {flex: 0 0 auto; display: inline-block; vertical-align: middle;}
/* #tool: icon trong vòng tròn .wr — trắng như filter-white cũ của PNG. */
#tool .wr .ut-svg-icon {color: #fff; display: block;}
.bottom-bar .rg > * .ut-svg-icon {margin-right: 4px;}
.ut-actions-tab .ut-svg-icon {margin-right: 5px;}
.ut-actions-tab.is-active {background: var(--color-dark-blue, #16324c); color: #fff;}

.ut-actions-panel {display: none;}
.ut-actions-panel.is-active {display: block;}
#actions .layer-content {padding: 50px; width: 100%; box-sizing: border-box;
	/* Equal height theo TAB CAO NHẤT — JS đo lúc mở modal và set min-height
	   cho từng panel (footer.php equalizeActionPanels): modal không đổi cao
	   khi chuyển tab, không có không gian chết. Trần chiều cao đã do
	   max-height của layer-body gate; quá trần thì cuộn bên trong. */
	overflow-y: auto;}
@media screen and (max-width: 781px) {
	#actions .layer-content {padding: 25px 14px;}
	.ut-actions-tab {padding: 9px 9px;}
}

/* Animation chuyển tab trong #actions: panel mới fade + trượt nhẹ lên.
   Dùng animation (không phải transition) vì panel đi từ display:none —
   keyframes vẫn chạy khi class .is-active được gắn. */
.ut-actions-tab {transition: background .18s, color .18s;}
.ut-actions-panel.is-active {animation: utActionsPanelIn .28s ease;}
@keyframes utActionsPanelIn {
	from {opacity: 0; transform: translateY(8px);}
	to {opacity: 1; transform: none;}
}
@media (prefers-reduced-motion: reduce) {
	.ut-actions-panel.is-active {animation: none;}
	.ut-actions-tab {transition: none;}
}

/* ==================== BOTTOM BAR TRANG LOOP (2026-07-21) ==================== */
/* Nút Filter + Destinations bên trái thay chỗ giá — pill giống các button .rg
   (style.css). */
/* BAR LOOP CHỈ CÒN DẠNG DOCKED (2026-08-29, owner) — vị trí/hiện-ẩn do luật
   chung của .bottom-bar (style.css: fixed đáy, ẩn tới khi .stick) lo; ở đây
   chỉ còn phần TRANG TRÍ riêng của bar loop. Bản 03/08 dựng bar trong dòng
   chảy rồi mới dock (.is-docked + chỗ trống .ut-barslot) đã bỏ hẳn: một chế
   độ thì popup Filter/Destinations cũng chỉ còn một kiểu neo. */
.bottom-bar.loop-bar {box-shadow: 0px 0px 20px 0px rgba(0,0,0,.2); border-radius: 6px 6px 0 0;}

.bottom-bar.loop-bar .lf {display: flex; align-items: stretch;}
.bottom-bar .lf .ut-loop-filter,
.bottom-bar .lf .ut-loop-dest {padding: 5px 10px; display: flex; flex-direction: column;
	align-items: center; justify-content: center; gap: 3px; font-size: 11px;
	font-weight: bold; text-transform: uppercase; color: var(--color-darker-blue);
	white-space: nowrap; border-right: 1px solid #ccc; cursor: pointer;}
.bottom-bar .lf .ut-loop-filter:hover,
.bottom-bar .lf .ut-loop-filter.on,
.bottom-bar .lf .ut-loop-dest:hover,
.bottom-bar .lf .ut-loop-dest.on {background: #ddd;}

@media screen and (max-width: 450px) {
	.bottom-bar .ut-from-price__body {flex-direction: row-reverse; gap: 8px;}
}


.wpc-edit-filter-set {display: none !important;}

/* ── Popup filter: FADE MỘT CHỖ TRÊN WRAPPER (2026-08-30, owner) ─────────
   Lịch sử: slide (transition trên từng con) → fade, nhưng tàn dư slide ở lại
   khiến head tự fade riêng CHỒNG lên fade wrapper (opacity nhân nhau) → head
   hiện trễ. Dọn lại một mối:
   - Đóng (không .ut-fpop): wrapper tự zero-footprint (height 0 + hidden) —
     máy collapse trên con đã gỡ ở style.css nên wrapper phải tự ẩn.
   - Mở: .ut-fpop đặt chỗ (fixed) + .on fade opacity/visibility trên wrapper.
   - RÀNG BUỘC: phần tử con KHÔNG mang transition/opacity mở-đóng riêng —
     tất cả thừa kế wrapper. Thêm animation cho con là tái nhiễm double-fade.
   - Duration .25s — JS đóng 2 nhịp trong archive-product.php đợi 300ms khớp
     con số này (đổi một bên phải đổi bên kia). */
.few {visibility: hidden; opacity: 0; height: 0; overflow: hidden; margin: 0; padding: 0;}
.few.ut-fpop {position: fixed; bottom: 64px;
	left: 0; right: 0;
	height: auto; max-height: calc(100vh - 140px);
	/* wrapper là CHỦ CUỘN duy nhất — popup có thể dài (terms filter) */
	overflow-y: auto; overscroll-behavior: contain;
	z-index: 1001; background: #fff;
	border-radius: 10px;
	box-shadow: 0px 0px 25px 0px rgba(0,0,0,.3); padding: 10px;
	display: block;
	transition: opacity .25s ease, visibility .25s ease;}
.few.ut-fpop.on {visibility: visible; opacity: 1; background: #f6f6f6;}

/* Heading bar của popup: title trái + nút close phải, sticky trên đỉnh
   scrollport. Thuần layout — mọi fade thừa kế từ wrapper. */
.few .ut-fpop-head {display: none;}
.few.ut-fpop .ut-fpop-head {display: flex; position: sticky; top: 0; z-index: 5;
	align-items: center; justify-content: space-between; gap: 10px;
	padding: 0 10px;}
/* Popup ĐI THEO BAR (2026-08-29, owner): bar ẩn khi chưa cuộn quá ngưỡng thì
   popup — vốn neo bottom:64px vào chỗ bar đứng — cũng phải ẩn, nếu không nó
   treo lơ lửng ở đáy màn hình một mình. CHỈ ẨN, KHÔNG ĐÓNG: class .on giữ
   nguyên nên cuộn xuống lại là popup hiện tiếp đúng trạng thái cũ (bản trước
   phải force-close vì có hai vị trí hiển thị; giờ một vị trí thì không cần).
   Thuần CSS nhờ .few là sibling ngay sau #bottombar; specificity (1,3,0)
   thắng .few.ut-fpop.on nên không cần !important. Popup Destinations không
   cần rule tương tự — nó nằm TRONG bar nên thừa kế visibility sẵn. */
#bottombar:not(.stick) ~ .few.ut-fpop {opacity: 0; visibility: hidden; pointer-events: none;}
/* Busy state: no curtain, no cursor games — just a ring beside the word FILTER.
   FE Pro's own signals were a full-screen overlay that swallowed clicks and a
   spinner parked away from what the user was looking at. Both are switched off
   in the plugin's settings (use_loader, dark_overlay); the two rules below are
   the belt to that braces, because the overlay ALSO has an unconditional
   `html.is-active` rule of its own — turning the "dark" option off only changes
   its colour, it still covers the page and still blocks the click.

   Interaction stays live throughout: filtering is fast and idempotent, and a
   second click during a request simply supersedes the first. Nothing needs
   protecting from the user here. */
.wpc-filters-overlay {display: none !important;}
.wpc-spinner {display: none !important;}

/* The ring lives inside the title, so the feedback appears where the eye
   already is. Its space is reserved at all times — an indicator that pushes the
   heading sideways as it appears reads as a glitch, not as progress. */
.ut-fpop-head__title {display: inline-flex; align-items: center; gap: 8px;}
.ut-fpop-head__title::after {content: ""; width: 13px; height: 13px; flex: 0 0 auto;
	border-radius: 50%; border: 2px solid rgba(0,0,0,.16); border-top-color: #2766ad;
	opacity: 0; transition: opacity .15s ease;}
/* `html.is-active` is FE Pro's own in-flight flag (filter-everything.js sets it
   when a request starts and clears it when the markup is back), so this tracks
   the real request rather than guessing at a duration. */
html.is-active .ut-fpop-head__title::after {opacity: 1; animation: ut-fpop-spin .7s linear infinite;}
@keyframes ut-fpop-spin {to {transform: rotate(360deg);}}
@media (prefers-reduced-motion: reduce) {
	html.is-active .ut-fpop-head__title::after {animation: none; border-top-color: rgba(0,0,0,.16); background: #2766ad;
		width: 7px; height: 7px; border: 0;}
}

.ut-fpop-head__title {font-size: 14px; font-weight: bold; text-transform: uppercase;
	letter-spacing: .5px; color: var(--color-dark-blue, #16324c);}
.ut-fpop-close {display: flex; align-items: center; justify-content: center;
	width: 32px; height: 32px; padding: 0; border: 0; border-radius: 50%;
	color: #000; font-size: 25px; line-height: 1; cursor: pointer; background: transparent;
	flex-shrink: 0;}
.ut-fpop-close:hover {color: #c90000;}

/* Destinations INLINE giữa bottom bar ở màn rộng (2026-07-22): ≥800px menu
   hiện mặc định trong khoảng trống giữa bar; nút Destinations thu/phóng qua
   class ut-dest-collapsed trên #bottombar (max-width transition). <800px các
   override này không áp → quay về popup .ut-cpop bên dưới. */
@media screen and (min-width: 800px) {
	.bottom-bar .caw {flex: 1; display: flex; justify-content: center; min-width: 0;
		overflow: hidden; max-width: 100%; opacity: 1;
		transition: max-width .3s ease, opacity .3s ease;}
	.bottom-bar.ut-dest-collapsed .caw {max-width: 0; opacity: 0;}
	.bottom-bar .caw .cm {position: static; opacity: 1; visibility: visible;
		background: none; padding: 0; justify-content: center; transition: none;}
	.bottom-bar .catbar {width: auto; max-width: none; background: none;
		box-shadow: none; padding: 0; font-size: 13px; border-radius: 0;
		backdrop-filter: none;}
	.bottom-bar .catbar ul {flex-wrap: nowrap; justify-content: center;}
	.bottom-bar .catbar ul li {width: auto; font-weight: normal; white-space: nowrap;}
}

/* Destinations popup từ bottom bar (<800px): .ut-cpop đổi .cm từ absolute
   (neo .caw) sang fixed ngay trên bar, mép trái khớp mép bar như popup filter;
   hiện/ẩn vẫn qua .caw.on (style.css). */
.caw .cm.ut-cpop {position: fixed; top: auto; right: auto; bottom: 64px;
	left: max(30px, calc((100% - var(--wid, 1170px)) / 2));
	max-width: calc(100vw - 60px); z-index: 1001; justify-content: flex-start;
	/* base .caw .cm để transition: all → đổi vị trí (left 0 → mép bar) cũng bị
	   animate thành slide ngang khi mở. Chỉ giữ fade. */
	transition: opacity .5s, visibility .5s;}

/* ========= LAYER SCROLL POLISH (2026-08-11) ========= */
/* Hộp cuộn thật là .layer-content bên trong .layer-body (bo góc + clip).
   1) Scrollbar mảnh, bo tròn, lùi vào trong — không đè lên góc bo của body.
   2) "Độ thở": nội dung mờ dần ~10px trước hai mép trên/dưới thay vì bị cắt
      phẳng đúng mép (mask áp cả lên scrollbar nên thanh cuộn cũng thở theo).
   Chỉ áp cho trạng thái popup (.open), KHÔNG áp khi is-docked (inline). */
.layer.open .layer-content {
	-webkit-mask-image: linear-gradient(180deg, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
	mask-image: linear-gradient(180deg, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
}
.layer.open .layer-content::-webkit-scrollbar {width: 8px;}
.layer.open .layer-content::-webkit-scrollbar-track {background: transparent; margin: 12px 0;}
.layer.open .layer-content::-webkit-scrollbar-thumb {background: #d5d5d8; border-radius: 8px; border: 2px solid #fff;}
.layer.open .layer-content::-webkit-scrollbar-thumb:hover {background: #bfbfc4;}
.layer.open .layer-content {scrollbar-width: thin; scrollbar-color: #d5d5d8 transparent;}

/* ========= CHAT TEASER (2026-08-11) ========= */
/* Bubble "Have some questions? Chat now." neo trên nút Chat của bottom bar.
   Nằm TRONG .bottom-bar nên thừa kế opacity/visibility theo .stick. */
.bottom-bar .ut-chat-teaser {
	position: absolute;
	bottom: calc(100% + 14px);
	right: 20px;
	background: #fff;
	color: #1d2327;
	border: 2px solid #1d2327;
	border-radius: 12px;
	padding: 10px 16px;
	font-size: 13px;
	font-weight: 600;
	line-height: 1.3;
	white-space: nowrap;
	cursor: pointer;
	box-shadow: 0 6px 20px rgba(0, 0, 0, .15);
	opacity: 0;
	transform: translateY(6px);
	transition: opacity .3s, transform .3s;
}
.bottom-bar .ut-chat-teaser.is-on {opacity: 1; transform: none;}
.bottom-bar .ut-chat-teaser:hover {background: #f5f8fb;}
/* Đuôi bubble chỉ xuống nút Chat: 2 lớp tam giác tạo viền như ảnh mẫu */
.bottom-bar .ut-chat-teaser::after {
	content: "";
	position: absolute;
	top: 100%;
	right: 26px;
	border: 9px solid transparent;
	border-top-color: #1d2327;
	border-left-width: 12px;
	border-right-width: 4px;
}
.bottom-bar .ut-chat-teaser::before {
	content: "";
	position: absolute;
	top: calc(100% - 3px);
	right: 28px;
	border: 7px solid transparent;
	border-top-color: #fff;
	border-left-width: 9px;
	border-right-width: 3px;
	z-index: 1;
}
.bottom-bar .ut-chat-teaser:hover::before {border-top-color: #f5f8fb;}
.ut-chat-teaser__close {
	position: absolute;
	top: -10px;
	right: -10px;
	width: 22px;
	height: 22px;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0;
	border: 2px solid #1d2327;
	border-radius: 50%;
	background: #fff;
	color: #1d2327;
	font-size: 14px;
	line-height: 1;
	cursor: pointer;
}
.ut-chat-teaser__close:hover {background: #1d2327; color: #fff;}

/* ========= CHAT WINDOW HEIGHT (2026-08-11) ========= */
/* Theme timeless của assistant chỉ đặt max-height (trần) cho khung hội thoại
   nên phiên MỚI (ít tin nhắn, vd ẩn danh) khung lùn theo nội dung; phiên có
   lịch sử dài mới chạm trần. Ép cao cố định = --uta-maxHeight (admin set,
   đang 60vh) để mọi khách thấy khung cùng cỡ. Fullscreen giữ flex riêng. */
.uta-timeless-theme.uta-window:not(.uta-fullscreen) .uta-body {
	height: var(--uta-maxHeight);
}
.uta-timeless-theme.uta-window:not(.uta-fullscreen) .uta-conversation {
	flex: 1 1 auto;
	max-height: none;
	min-height: 0;
}
