/*
 * Cụm nút nổi — T11.3.
 *
 * Chỉ dùng biến của theme, mọi biến đều có giá trị dự phòng để block chạy được
 * trên theme mặc định của WordPress.
 *
 * NÚT TRÒN CHỈ CÓ ICON KHI NGHỈ, NỞ RA THÀNH VIÊN THUỐC KHI RÊ CHUỘT.
 * Nhãn luôn có trong HTML và luôn là `aria-label`, nên trình đọc màn hình đọc
 * được kể cả lúc chữ đang bị giấu. Giấu bằng cách cắt bề rộng chứ không
 * `display: none`: phần tử bị `display: none` thì trình đọc màn hình cũng bỏ qua.
 */

.nd-floating {
	--nd-floating-gap: var( --wp--preset--spacing--md, 1.5rem );
	--nd-floating-step: var( --wp--preset--spacing--2-xs, 0.5rem );

	position: fixed;
	inset-block-end: calc( var( --nd-floating-gap ) + var( --nd-floating-lift, 0px ) );
	z-index: 60;
	display: flex;
	flex-direction: column;

	/*
	 * Ẩn cho tới khi vượt ngưỡng cuộn. `visibility` chứ không chỉ `opacity`:
	 * chỉ hạ độ mờ thì nút vẫn bấm được và vẫn nhận phím Tab — một cái bẫy vô
	 * hình vì mắt không thấy gì cả.
	 */
	opacity: 0;
	visibility: hidden;
	transform: translateY( 0.5rem );
	transition: opacity var( --wp--custom--motion--duration-base, 200ms ) ease,
		transform var( --wp--custom--motion--duration-base, 200ms ) ease,
		visibility var( --wp--custom--motion--duration-base, 200ms );
}

.nd-floating.is-visible {
	opacity: 1;
	visibility: visible;
	transform: translateY( 0 );
}

/*
 * KHOẢNG CÁCH GIỮA CÁC NÚT LÀ `margin`, KHÔNG PHẢI `gap`. Đây là điều kiện để
 * nút lên đầu trang co lại thành zero mà không để lại lỗ.
 *
 * Nút lên đầu có ngưỡng cuộn riêng, nên có lúc nó ẩn trong khi hotline vẫn hiện.
 * `gap` thì vẫn tính khoảng cách cho một phần tử cao 0 — cụm nút để lại một
 * quãng trống 8px ở đáy, và hotline lơ lửng cao hơn nó phải ở.
 *
 * `margin-block-start` thì thu về 0 được, và thu ĐƯỢC MƯỢT: nút lên đầu lớn dần
 * từ 0 lên 44px trong khi lề của nó giãn ra, nên hotline trượt lên chứ không
 * nhảy một phát 52px.
 */
.nd-floating > * + * {
	margin-block-start: var( --nd-floating-step );
}

.nd-floating--right {
	inset-inline-end: var( --nd-floating-gap );
	align-items: flex-end;
}

.nd-floating--left {
	inset-inline-start: var( --nd-floating-gap );
	align-items: flex-start;
}

/*
 * VÌ SAO NÚT TRÒN LẠI RA HÌNH BẦU DỤC — và vì sao ba dòng dưới đây phải đi cùng nhau.
 *
 * Đo trên site thật: nút ở trạng thái nghỉ ra **68×46**, lệch 22px. Ba thứ cộng
 * dồn, không thứ nào một mình đủ gây ra:
 *
 * 1. `box-sizing` ở đây là `content-box` — nd-base không đặt `border-box` cho
 *    phần tử này. Nghĩa là `min-inline-size: 2.75rem` và `block-size: 2.75rem`
 *    áp cho HỘP NỘI DUNG, rồi padding và viền cộng thêm bên ngoài. Con số 44px
 *    viết trong luật không phải kích thước thật của nút.
 * 2. `padding-inline` cộng 22,4px theo chiều ngang nhưng không cộng gì theo
 *    chiều dọc — bất đối xứng nằm ngay đây.
 * 3. `gap` vẫn tính giữa icon và chữ KỂ CẢ KHI CHỮ RỘNG 0. Một phần tử flex bề
 *    rộng 0 vẫn là một phần tử flex; chỉ `display: none` mới bỏ khoảng cách, mà
 *    `display: none` thì trình đọc màn hình cũng bỏ luôn cái nhãn.
 *
 * Cách sửa: khai `border-box` tại chỗ để 2,75rem là kích thước NGOÀI, bỏ `gap`
 * và chuyển khoảng cách icon–chữ vào `padding-inline-start` của chính chữ (nằm
 * trong phần bị `max-inline-size: 0` cắt, nên lúc nghỉ nó bằng 0 thật), rồi thu
 * `padding-inline` xuống 0,6rem để tổng bề ngang lúc nghỉ (2 + 19,2 + 21,6 =
 * 42,8px) nằm dưới sàn 44px — lúc đó `min-inline-size` quyết định, và bề ngang
 * bằng đúng bề cao.
 */
.nd-floating__button {
	box-sizing: border-box;
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;

	/*
	 * Khoảng cách icon–chữ bằng 0 lúc nghỉ, mở ra lúc rê chuột.
	 *
	 * Thử trước bằng `padding` trên chính chữ rồi trông chờ `max-inline-size: 0`
	 * cắt đi — KHÔNG được: kể cả với `border-box`, một hộp không bao giờ hẹp hơn
	 * padding cộng viền của nó, nên chữ vẫn chiếm 8px và nút vẫn méo, chỉ méo ít
	 * hơn. `column-gap` thì animate được và về 0 là mất hẳn.
	 */
	column-gap: 0;

	/* 44px là vùng bấm tối thiểu cho ngón tay — WCAG 2.5.8. Nay là kích thước NGOÀI. */
	min-inline-size: 2.75rem;
	block-size: 2.75rem;
	padding-inline: 0.6rem;
	border: 1px solid var( --wp--preset--color--line, #d8dce3 );
	border-radius: 62.4375rem;
	background: var( --wp--preset--color--brand, #1f2328 );
	color: var( --wp--preset--color--fg-on-brand, #fff );
	box-shadow: var( --wp--preset--shadow--md, 0 2px 4px -1px rgb( 0 0 0 / 0.12 ) );
	text-decoration: none;
	cursor: pointer;
	overflow: hidden;
	transition: background var( --wp--custom--motion--duration-fast, 120ms ) ease,
		column-gap var( --wp--custom--motion--duration-base, 200ms ) ease;
}

/*
 * TÊN LỚP LẶP HAI LẦN, VÀ PHẢI KHAI LẠI `color` Ở ĐÂY.
 *
 * Nút liên hệ là một thẻ `<a>`. Global styles của theme sinh ra một luật đại ý
 * `:root :where(a:not(.wp-element-button)):hover { color: … }` — nặng đúng hai
 * bậc, bằng `.nd-floating__button:hover`, và nó đứng sau trong tài liệu nên nó
 * thắng. Luật cũ ở đây chỉ đổi `background`, không đổi `color`, nên lúc rê chuột
 * màu chữ nhảy về màu liên kết của theme.
 *
 * Đo được: nền `rgb(69,40,213)` và màu chữ cũng `rgb(69,40,213)` — icon và chữ
 * vẫn nằm đó, vẫn `opacity: 1`, chỉ trùng màu với nền. Nút rỗng ruột khi rê
 * chuột, và không có gì trong console để lần ra.
 *
 * Lặp lớp là nặng thêm một bậc mà không phải `!important` (CLAUDE.md §1.5).
 */
.nd-floating__button.nd-floating__button:hover,
.nd-floating__button.nd-floating__button:focus-visible {
	background: var( --wp--custom--color--brand-hover, #000 );
	color: var( --wp--preset--color--fg-on-brand, #fff );
	text-decoration: none;
}

/*
 * Vòng focus phải thấy được trên cả nền sáng lẫn nền tối: nút nổi lơ lửng trên
 * bất kỳ nội dung nào của trang. Một màu viền thì trên nửa số nền nó biến mất,
 * nên có thêm quầng tối bao ngoài.
 */
.nd-floating__button:focus-visible {
	outline: 2px solid var( --wp--preset--color--fg-on-brand, #fff );
	outline-offset: 2px;
	box-shadow: 0 0 0 4px rgb( 0 0 0 / 0.45 );
}

.nd-floating__icon {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	justify-content: center;
	inline-size: 1.35rem;
	block-size: 1.35rem;
}

.nd-floating__icon svg,
.nd-floating__icon img {
	display: block;
	inline-size: 100%;
	block-size: 100%;
	object-fit: contain;
}

/*
 * LOGO TRÒN THÌ ĐỂ NÓ LÀ CÁI NÚT.
 *
 * Logo Zalo, Messenger, TikTok đều là một đĩa tròn đầy đủ, có màu nền riêng.
 * Thu nhỏ chúng đặt vào giữa một đĩa màu thương hiệu cho ra hai vòng tròn lồng
 * nhau; trên một site cam như RETI thì đĩa cam của Zalo lẫn luôn vào nền cam
 * của nút và gần như không nhìn ra.
 *
 * Ở chế độ này nút bỏ nền, bỏ viền, bỏ padding — ảnh phủ trọn 44×44. Lúc rê
 * chuột, luật `:hover` nặng ba bậc ở trên trả nền lại, nên chữ nở ra vẫn đọc
 * được; chỉ cần trả thêm padding bên phải cho chữ có chỗ thở.
 */
.nd-floating__button.has-fill-image {
	padding-inline: 0;
	border: 0;
	background: transparent;
}

.nd-floating__button.has-fill-image:hover,
.nd-floating__button.has-fill-image:focus-visible {
	padding-inline-end: 0.6rem;
}

.nd-floating__button.has-fill-image .nd-floating__icon {
	inline-size: 2.75rem;
	block-size: 2.75rem;
	border-radius: 50%;
	overflow: hidden;
}

.nd-floating__button.has-fill-image .nd-floating__icon img {
	object-fit: cover;
}

.nd-floating__text {
	max-inline-size: 0;
	overflow: hidden;
	white-space: nowrap;
	opacity: 0;
	transition: max-inline-size var( --wp--custom--motion--duration-base, 200ms ) ease,
		opacity var( --wp--custom--motion--duration-base, 200ms ) ease;
}

.nd-floating__button.nd-floating__button:hover,
.nd-floating__button.nd-floating__button:focus-visible {
	column-gap: var( --wp--preset--spacing--2-xs, 0.5rem );
}

.nd-floating__button:hover .nd-floating__text,
.nd-floating__button:focus-visible .nd-floating__text {
	max-inline-size: 12rem;
	opacity: 1;
}

/*
 * NÚT LÊN ĐẦU TRANG HIỆN/ẨN RIÊNG, KHÔNG THEO CỤM.
 *
 * Thu về `block-size: 0` chứ không chỉ hạ `opacity`: cụm nút neo ở mép dưới màn
 * hình và mọc lên trên, nên một phần tử ẩn mà vẫn chiếm 44px sẽ đẩy hotline lên
 * cao hơn chỗ nó phải ở, suốt cả lúc chưa cuộn.
 *
 * Chuyển tiếp đặt trên `block-size` và `margin-block-start` nữa, nên nút lớn dần
 * lên trong khi lề giãn ra và hotline TRƯỢT lên thay vì nhảy một phát 52px. Đây
 * là lý do khoảng cách giữa các nút phải là `margin` chứ không phải `gap`.
 *
 * Quãng 1,25rem và nhịp `duration-slow` lấy từ `nd/back-to-top` — cùng cú trồi
 * lên mà khách đã quen ở plugin `reti-back-to-top`.
 */
.nd-floating__button--top.nd-floating__button--top {
	block-size: 0;
	min-block-size: 0;
	margin-block-start: 0;

	/*
	 * Viền cũng phải về 0. `box-sizing: border-box` không cho hộp hẹp hơn viền
	 * cộng padding, nên `block-size: 0` một mình vẫn để lại 2px — cụm nút cao
	 * hơn nó cần đúng chừng đó, và nếu có ngày `opacity` không kịp áp thì đó là
	 * một vạch mờ nằm dưới hotline mà không ai hiểu ở đâu ra.
	 *
	 * `padding-block` cũng vậy, và chỗ này mới là chỗ bất ngờ: nút không khai
	 * padding dọc, nhưng theme cấp cho mọi `<button>` 1px trên dưới — đo được
	 * `padding-top: 1px` trên site thật. Với `border-box` thì hộp không hẹp hơn
	 * padding cộng viền, nên còn đúng 2px.
	 */
	border-block-width: 0;
	padding-block: 0;
	overflow: hidden;
	opacity: 0;
	visibility: hidden;
	transform: translateY( 1.25rem );
	transition: block-size var( --wp--custom--motion--duration-slow, 320ms )
			var( --wp--custom--motion--ease-entrance, ease-out ),
		margin-block-start var( --wp--custom--motion--duration-slow, 320ms )
			var( --wp--custom--motion--ease-entrance, ease-out ),
		opacity var( --wp--custom--motion--duration-slow, 320ms )
			var( --wp--custom--motion--ease-entrance, ease-out ),
		transform var( --wp--custom--motion--duration-slow, 320ms )
			var( --wp--custom--motion--ease-entrance, ease-out ),
		visibility var( --wp--custom--motion--duration-slow, 320ms ),
		column-gap var( --wp--custom--motion--duration-base, 200ms ) ease,
		background var( --wp--custom--motion--duration-fast, 120ms ) ease;
}

.nd-floating__button--top.nd-floating__button--top.is-top-visible {
	block-size: 2.75rem;
	opacity: 1;
	visibility: visible;
	transform: translateY( 0 );
}

/* Lề chỉ mọc lại khi nút hiện VÀ có nút khác đứng trên nó. */
.nd-floating > * + .nd-floating__button--top.is-top-visible {
	margin-block-start: var( --nd-floating-step );
}

/*
 * Vòng tiến độ đọc.
 *
 * Vẽ Ở BÊN TRONG nút vì nền của nó khi đó luôn là màu thương hiệu đã biết —
 * `currentColor` chắc chắn tương phản đủ. Một vòng vẽ quanh mép ngoài thì phải
 * chọi lại bất cứ thứ gì người ta cuộn qua, kể cả một tấm ảnh.
 *
 * Kích thước CỐ ĐỊNH và neo vào mép trước, không phải `inset: 0.2rem`: lúc rê
 * chuột nút nở ngang thành viên thuốc, và một vòng `inset` đều bốn phía sẽ kéo
 * dài thành hình bầu dục. Neo vào mép trước thì nó đi theo icon.
 */
.nd-floating__ring {
	position: absolute;
	inset-block-start: 0.2rem;
	inset-inline-start: 0.2rem;
	inline-size: 2.35rem;
	block-size: 2.35rem;
	border-radius: 50%;
	pointer-events: none;

	/* Dự phòng cho trình duyệt chưa có color-mix: rãnh xám trung tính. */
	background: conic-gradient(
		currentColor var( --nd-floating-progress, 0% ),
		rgb( 128 128 128 / 0.35 ) 0
	);
	background: conic-gradient(
		currentColor var( --nd-floating-progress, 0% ),
		color-mix( in srgb, currentColor 22%, transparent ) 0
	);
	-webkit-mask: radial-gradient(
		farthest-side,
		transparent calc( 100% - 0.14rem ),
		#000 calc( 100% - 0.14rem )
	);
	mask: radial-gradient(
		farthest-side,
		transparent calc( 100% - 0.14rem ),
		#000 calc( 100% - 0.14rem )
	);
}

/*
 * Màn hẹp: nút bám sát mép hơn và KHÔNG nở chữ.
 *
 * Ở 360px, một nút nở ra 12rem chiếm gần hết bề ngang và che mất nội dung ngay
 * dưới ngón tay đang chạm. Trên cảm ứng cũng không có trạng thái "rê chuột" để
 * xem trước, nên chữ nở ra chỉ gây vướng.
 */
@media ( max-width: 480px ) {

	.nd-floating {
		--nd-floating-gap: var( --wp--preset--spacing--sm, 1rem );
	}

	.nd-floating__button.nd-floating__button:hover,
	.nd-floating__button.nd-floating__button:focus-visible {
		column-gap: 0;
	}

	.nd-floating__button:hover .nd-floating__text,
	.nd-floating__button:focus-visible .nd-floating__text {
		max-inline-size: 0;
		opacity: 0;
	}
}

@media ( prefers-reduced-motion: reduce ) {

	.nd-floating,
	.nd-floating__button,
	.nd-floating__text {
		transition: none;
	}
}
