/* ==========================================================================
   Align 2026 — components + animation primitives
   Mô hình animation học pear.no: scroll là timeline. JS chỉ ghi một biến
   --p (0→1) cho mỗi scene; mọi chuyển động tính bằng calc() trong CSS.
   Không thư viện.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Scene được ghim (pinned) — khung xương của pear.no
   -------------------------------------------------------------------------- */

.scene {
	position: relative;
	z-index: 2;
	--p: 0;                       /* tiến độ cuộn trong scene, JS ghi vào */
}

.scene__pin {
	position: sticky;
	top: 0;
	height: 100svh;
	overflow: hidden;
}

/* --------------------------------------------------------------------------
   2. Reveal — hiện khi vào khung nhìn
   -------------------------------------------------------------------------- */

/* Dòng chữ trượt lên trong khung cắt (JS bọc mỗi dòng vào .ln > i) */
.ln {
	overflow: hidden;
	display: block;
	/* chừa chỗ cho đuôi chữ g/y/p khỏi bị cắt */
	padding-bottom: var(--roll-tail);
	margin-bottom: calc(var(--roll-tail) * -1);
}
.ln > i {
	display: block;
	font-style: normal;
	transform: translateY(105%);
	transition: transform var(--d-line) var(--ease-out);
	transition-delay: calc(var(--i, 0) * 70ms);
}
.is-in .ln > i { transform: translateY(0); }

/* Chế độ theo TỪ (data-split="words") — mỗi từ trượt lên kèm một cú nghiêng
   rồi đứng thẳng lại, các từ nối đuôi nhau. Học của serious.business. */
.ln > .w {
	display: inline-block;
	transform: translateY(105%) skewX(var(--skew-word));
	transition: transform var(--d-word) var(--ease-out);
	transition-delay: calc(var(--i, 0) * var(--stagger-line) + var(--w, 0) * var(--stagger-word));
	will-change: transform;
}
.is-in .ln > .w { transform: none; }

/* Chế độ theo KÝ TỰ: bọc mỗi từ lại để không bị ngắt dòng giữa chừng, và vì
   .w giờ nằm sâu một cấp nên cần thêm selector. */
.ln .wd { display: inline-block; white-space: nowrap; }
.ln .wd > .w {
	display: inline-block;
	transform: translateY(105%) skewX(var(--skew-char));
	transition: transform var(--d-char) var(--ease-out);
	transition-delay: calc(var(--i, 0) * var(--stagger-line) + var(--w, 0) * var(--stagger-char));
	will-change: transform;
}
.is-in .ln .wd > .w { transform: none; }

/* Khối đơn giản: mờ + dịch lên */
[data-rise] {
	opacity: 0;
	transform: translateY(28px);
	transition: opacity var(--d-rise) var(--ease-out), transform var(--d-rise) var(--ease-out);
	transition-delay: calc(var(--i, 0) * 80ms);
}
.is-in[data-rise],
.is-in [data-rise] { opacity: 1; transform: none; }

/* Media: mở khung + ảnh giãn về 1 */
[data-open] {
	clip-path: inset(0 0 100% 0);
	transition: clip-path 1.3s var(--ease-out);
}
.is-in[data-open],
.is-in [data-open] { clip-path: inset(0 0 0 0); }

/* Dùng longhand `scale` chứ không phải `transform`: ảnh trong khung còn có
   parallax ([data-par], dùng `translate`). Hai thuộc tính riêng thì cộng dồn,
   còn cùng `transform` thì rule nào mạnh hơn sẽ xoá mất rule kia. */
[data-open] > img,
[data-open] > video {
	scale: 1.14;
	transition: scale 1.8s var(--ease-out);
}
.is-in[data-open] > img,
.is-in [data-open] > img,
.is-in[data-open] > video,
.is-in [data-open] > video { scale: 1; }

/* Kẻ ngang tự vẽ ra */
.rule-draw {
	height: 1px;
	background: var(--hairline);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 1.1s var(--ease-out);
}
.rule-draw--strong { height: 2px; background: var(--ink); }
.is-in .rule-draw,
.is-in.rule-draw { transform: scaleX(1); }

/* Parallax: JS ghi --sp (0→1 khi phần tử đi qua khung nhìn) */
[data-par] { translate: 0 calc(var(--sp, 0.5) * var(--par, 60px) - var(--par, 60px) * 0.5); }
/* Ảnh parallax trong khung: cao hơn khung đúng --par, chừa --par/2 mỗi mép,
   để lúc trượt tới ±par/2 vẫn phủ kín khung, không lộ dải trống. */
[data-open] > [data-par] {
	height: calc(100% + var(--par, 60px));
	margin-block: calc(var(--par, 60px) * -0.5);
}

@media (prefers-reduced-motion: reduce) {
	.hdr, .brand__logo, .lg, .lg > path { animation: none !important; }
	.brand__logo, .lg { transition: none !important; }
	.lg { transform: none !important; }
	.ln > i, .ln .w, [data-rise], [data-open], [data-open] > img, [data-open] > video, .rule-draw {
		transform: none !important;
		opacity: 1 !important;
		clip-path: none !important;
		transition: none !important;
	}
	[data-open] > img, [data-open] > video { scale: none !important; }
	[data-par] { translate: none !important; }
}

/* --------------------------------------------------------------------------
   3. Nền: hạt nhiễu + quầng sáng ấm (canvas do JS vẽ)
   -------------------------------------------------------------------------- */

/* Nền hero: cảnh WebGL của align.vn, CHỈ nằm trong hero và bị hero cắt.
   Từ dưới hero trở đi là nền cam phẳng + hạt nhiễu. */
.hero-bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
	/* Không đặt gradient dự phòng: lúc cảnh WebGL chưa tải xong nó loé lên một
	   mảng vàng rồi biến mất. Nền cam phẳng là đủ.
	   Ghim cứng chứ không dùng var(--ground): cảnh WebGL của hero luôn nền cam,
	   đổi theme không được phép chạm vào đây. */
	background: #bf400b;
}
.hero-bg__scene { position: absolute; inset: 0; width: 100%; height: 110%; }

 /* Khai báo bộ lọc #goo (vệt blob ở CTA) — chỉ là kho, không được chiếm chỗ */
svg.goo-def { position: absolute; width: 0; height: 0; pointer-events: none; }

.grain {
	position: fixed;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	mix-blend-mode: soft-light;
	opacity: 0.30;
	background-image: var(--grain);
	background-size: 260px 260px;
}

/* --------------------------------------------------------------------------
   4. Header + nav pill
   -------------------------------------------------------------------------- */

.hdr {
	position: fixed;
	top: 0; left: 0; right: 0;
	z-index: 90;
	padding-block: 1.6rem;
	transition: transform 0.6s var(--ease-out), opacity 0.4s linear;
}
.hdr.is-hidden { transform: translateY(-130%); opacity: 0; }

/* Vào trang: header trượt xuống. Dùng @keyframes chứ không phải transition,
   vì transform của .hdr còn để dành cho trạng thái ẩn khi cuộn xuống. */
@keyframes hdr-in {
	from { transform: translateY(-115%); opacity: 0; }
}
.hdr { animation: hdr-in 1s var(--ease-out) 0.12s backwards; }

.hdr__in {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 2rem;
}

.brand { display: flex; align-items: center; gap: 0.9rem; }

/* --- Logo: gọn ↔ full ------------------------------------------------------
   Dựng lại đúng timeline của file Lottie "Logo animation.json" (1544×1016,
   60fps, 32 frame = 533ms, easing Easy Ease = cubic-bezier(.167,.167,.833,.833)).

   GỌN  = chỉ hai thanh dọc bên trái; mọi thứ khác nằm chồng sau chúng ở x≈334.
   FULL = trượt sang phải và xoè ra, so le: ngoặc trái xong ở frame 4, thanh
          giữa 8, ngoặc phải 12, thanh phải trong 16, thanh phải ngoài 20,
          cuối cùng hai ô vuông tách lên/xuống ở frame 20→32.

   Cuộn ngược lại thì các mốc đảo: phần tử đi xa nhất khởi hành trước, tất cả
   về đích cùng lúc — đúng như phát Lottie ngược. Chỉ cần một cú cuộn là class
   .is-hidden đổi và animation chạy trọn, không gắn với quãng đường cuộn. */
.brand__logo {
	--lw: clamp(58px, 5vw, 84px);
	display: block;
	flex: none;
	width: var(--lw);
	height: calc(var(--lw) / 1.5197);     /* 1544 / 1016 */
}
.brand__logo .logo { display: block; width: 100%; height: 100%; }

/* Một khai báo dùng chung; mỗi phần tử chỉ khai --cx/--cy và mốc thời gian. */
.lg {
	transform-box: view-box;
	transform: translate(var(--x, 0px), var(--y, 0px));
	transition: transform var(--dur, 0.2s) var(--e-lot) var(--del, 0s);
	animation: logo-in var(--dur, 0.2s) var(--e-lot) var(--del, 0s) backwards;
}

/* Độ lệch ở trạng thái gọn (đơn vị user của viewBox) + mốc lúc XOÈ RA */
.lg-b1   { --cx: -218.5px;   --dur: 0.067s; }
.lg-cb   { --cx: -438.375px; --dur: 0.133s; }
.lg-b2   { --cx: -657.5px;   --dur: 0.2s;   }
.lg-r1   { --cx: -876.75px;  --dur: 0.267s; }
.lg-r2   { --cx: -1096px;    --dur: 0.333s; }
.lg-sq   { --cx: -437.75px;  --dur: 0.133s; }
/* --cx: 0 là bắt buộc: <g> con kế thừa --cx của <g> cha nên nếu không chặn
   thì ô vuông bị dịch ngang hai lần. */
.lg-sq-t { --cx: 0px; --cy: 256px;  --dur: 0.2s; --del: 0.333s; }
.lg-sq-b { --cx: 0px; --cy: -248px; --dur: 0.2s; --del: 0.333s; }

/* Header ẩn (cuộn xuống) → rút gọn. Mốc đảo: dur giữ nguyên, del = 0.533s − dur */
.hdr.is-hidden .lg { --x: var(--cx, 0px); --y: var(--cy, 0px); }
.hdr.is-hidden .lg-b1   { --del: 0.467s; }
.hdr.is-hidden .lg-cb   { --del: 0.4s;   }
.hdr.is-hidden .lg-b2   { --del: 0.333s; }
.hdr.is-hidden .lg-r1   { --del: 0.267s; }
.hdr.is-hidden .lg-r2   { --del: 0.2s;   }
.hdr.is-hidden .lg-sq   { --del: 0.4s;   }
.hdr.is-hidden .lg-sq-t,
.hdr.is-hidden .lg-sq-b { --del: 0s;     }

/* Vào trang: chạy đúng một lần chiều xoè ra */
@keyframes logo-in { from { transform: translate(var(--cx, 0px), var(--cy, 0px)); } }

/* Hai cái ngoặc không chỉ dịch chuyển — trong Lottie chính ĐƯỜNG PATH của chúng
   đổi hình: mọc cánh ngang ở frame 4→8 (trái) / 8→12 (phải), giữ nguyên tới
   frame 20, rồi cái chân dài mọc ra hết cỡ ở frame 20→32. Không transition
   được ba chặng nên dùng @keyframes, sinh thẳng từ vertex + tangent của Lottie
   (8 đoạn cubic mỗi hình nên `d` nội suy được). */
.lg-b1 > path { d: path("M 94.05 293.1 C 94.05 293.1 94.05 324.46 94.05 324.46 C 94.05 324.46 -31.05 324.46 -31.05 324.46 C -65.86 324.46 -94.05 295.99 -94.05 260.9 C -94.05 260.9 -94.05 -260.92 -94.05 -260.92 C -94.05 -296.01 -65.86 -324.46 -31.05 -324.46 C -31.05 -324.46 31.36 -324.03 31.36 -324.03 C 31.36 -324.03 31.36 261.76 31.36 261.76 C 31.36 261.76 94.05 293.1 94.05 293.1 Z"); }
.lg-b2 > path { d: path("M -94.05 -293.12 C -94.05 -293.12 -94.05 -324.46 -94.05 -324.46 C -94.05 -324.46 31.06 -324.46 31.06 -324.46 C 65.86 -324.46 94.05 -296 94.05 -260.9 C 94.05 -260.9 94.05 260.92 94.05 260.92 C 94.05 296.01 65.86 324.46 31.06 324.46 C 31.06 324.46 -31.33 324.46 -31.33 324.46 C -31.33 324.46 -31.33 -261.77 -31.33 -261.77 C -31.33 -261.77 -94.05 -293.12 -94.05 -293.12 Z"); }

.lg-b1 > path,
.lg-b2 > path { transition: none; }
.lg-b1 > path { animation: b1-x 0.533s var(--e-lot) backwards; }
.lg-b2 > path { animation: b2-x 0.533s var(--e-lot) backwards; }
.hdr.is-hidden .lg-b1 > path { animation: b1-c 0.533s var(--e-lot) forwards; }
.hdr.is-hidden .lg-b2 > path { animation: b2-c 0.533s var(--e-lot) forwards; }

@keyframes b1-x {
	0%,12.5% { d: path("M 31.05 293.1 C 31.05 293.1 31.05 324.45 31.05 324.45 C 31.05 324.45 -31.05 324.46 -31.05 324.46 C -65.86 324.46 -94.05 295.99 -94.05 260.9 C -94.05 260.9 -94.06 36.08 -94.06 36.08 C -94.06 0.99 -65.87 -27.46 -31.06 -27.46 C -31.06 -27.46 31.35 -27.03 31.35 -27.03 C 31.35 -27.03 31.36 261.76 31.36 261.76 C 31.36 261.76 31.05 293.1 31.05 293.1 Z"); }
	25%,62.5% { d: path("M 94.05 293.1 C 94.05 293.1 94.05 324.46 94.05 324.46 C 94.05 324.46 -31.05 324.46 -31.05 324.46 C -65.86 324.46 -94.05 295.99 -94.05 260.9 C -94.05 260.9 -94.06 36.08 -94.06 36.08 C -94.06 0.99 -65.87 -27.46 -31.06 -27.46 C -31.06 -27.46 31.35 -27.03 31.35 -27.03 C 31.35 -27.03 31.36 261.76 31.36 261.76 C 31.36 261.76 94.05 293.1 94.05 293.1 Z"); }
	100% { d: path("M 94.05 293.1 C 94.05 293.1 94.05 324.46 94.05 324.46 C 94.05 324.46 -31.05 324.46 -31.05 324.46 C -65.86 324.46 -94.05 295.99 -94.05 260.9 C -94.05 260.9 -94.05 -260.92 -94.05 -260.92 C -94.05 -296.01 -65.86 -324.46 -31.05 -324.46 C -31.05 -324.46 31.36 -324.03 31.36 -324.03 C 31.36 -324.03 31.36 261.76 31.36 261.76 C 31.36 261.76 94.05 293.1 94.05 293.1 Z"); }
}
@keyframes b1-c {
	0% { d: path("M 94.05 293.1 C 94.05 293.1 94.05 324.46 94.05 324.46 C 94.05 324.46 -31.05 324.46 -31.05 324.46 C -65.86 324.46 -94.05 295.99 -94.05 260.9 C -94.05 260.9 -94.05 -260.92 -94.05 -260.92 C -94.05 -296.01 -65.86 -324.46 -31.05 -324.46 C -31.05 -324.46 31.36 -324.03 31.36 -324.03 C 31.36 -324.03 31.36 261.76 31.36 261.76 C 31.36 261.76 94.05 293.1 94.05 293.1 Z"); }
	37.5%,75% { d: path("M 94.05 293.1 C 94.05 293.1 94.05 324.46 94.05 324.46 C 94.05 324.46 -31.05 324.46 -31.05 324.46 C -65.86 324.46 -94.05 295.99 -94.05 260.9 C -94.05 260.9 -94.06 36.08 -94.06 36.08 C -94.06 0.99 -65.87 -27.46 -31.06 -27.46 C -31.06 -27.46 31.35 -27.03 31.35 -27.03 C 31.35 -27.03 31.36 261.76 31.36 261.76 C 31.36 261.76 94.05 293.1 94.05 293.1 Z"); }
	87.5%,100% { d: path("M 31.05 293.1 C 31.05 293.1 31.05 324.45 31.05 324.45 C 31.05 324.45 -31.05 324.46 -31.05 324.46 C -65.86 324.46 -94.05 295.99 -94.05 260.9 C -94.05 260.9 -94.06 36.08 -94.06 36.08 C -94.06 0.99 -65.87 -27.46 -31.06 -27.46 C -31.06 -27.46 31.35 -27.03 31.35 -27.03 C 31.35 -27.03 31.36 261.76 31.36 261.76 C 31.36 261.76 31.05 293.1 31.05 293.1 Z"); }
}
@keyframes b2-x {
	0%,25% { d: path("M -31.05 -293.11 C -31.05 -293.11 -31.05 -324.46 -31.05 -324.46 C -31.05 -324.46 31.06 -324.46 31.06 -324.46 C 65.86 -324.46 94.05 -296 94.05 -260.9 C 94.05 -260.9 93.87 -37.08 93.87 -37.08 C 93.87 -1.99 65.67 26.46 30.88 26.46 C 30.88 26.46 -31.51 26.46 -31.51 26.46 C -31.51 26.46 -31.33 -261.77 -31.33 -261.77 C -31.33 -261.77 -31.05 -293.11 -31.05 -293.11 Z"); }
	37.5%,62.5% { d: path("M -94.05 -293.12 C -94.05 -293.12 -94.05 -324.46 -94.05 -324.46 C -94.05 -324.46 31.06 -324.46 31.06 -324.46 C 65.86 -324.46 94.05 -296 94.05 -260.9 C 94.05 -260.9 93.87 -37.08 93.87 -37.08 C 93.87 -1.99 65.67 26.46 30.88 26.46 C 30.88 26.46 -31.51 26.46 -31.51 26.46 C -31.51 26.46 -31.33 -261.77 -31.33 -261.77 C -31.33 -261.77 -94.05 -293.12 -94.05 -293.12 Z"); }
	100% { d: path("M -94.05 -293.12 C -94.05 -293.12 -94.05 -324.46 -94.05 -324.46 C -94.05 -324.46 31.06 -324.46 31.06 -324.46 C 65.86 -324.46 94.05 -296 94.05 -260.9 C 94.05 -260.9 94.05 260.92 94.05 260.92 C 94.05 296.01 65.86 324.46 31.06 324.46 C 31.06 324.46 -31.33 324.46 -31.33 324.46 C -31.33 324.46 -31.33 -261.77 -31.33 -261.77 C -31.33 -261.77 -94.05 -293.12 -94.05 -293.12 Z"); }
}
@keyframes b2-c {
	0% { d: path("M -94.05 -293.12 C -94.05 -293.12 -94.05 -324.46 -94.05 -324.46 C -94.05 -324.46 31.06 -324.46 31.06 -324.46 C 65.86 -324.46 94.05 -296 94.05 -260.9 C 94.05 -260.9 94.05 260.92 94.05 260.92 C 94.05 296.01 65.86 324.46 31.06 324.46 C 31.06 324.46 -31.33 324.46 -31.33 324.46 C -31.33 324.46 -31.33 -261.77 -31.33 -261.77 C -31.33 -261.77 -94.05 -293.12 -94.05 -293.12 Z"); }
	37.5%,62.5% { d: path("M -94.05 -293.12 C -94.05 -293.12 -94.05 -324.46 -94.05 -324.46 C -94.05 -324.46 31.06 -324.46 31.06 -324.46 C 65.86 -324.46 94.05 -296 94.05 -260.9 C 94.05 -260.9 93.87 -37.08 93.87 -37.08 C 93.87 -1.99 65.67 26.46 30.88 26.46 C 30.88 26.46 -31.51 26.46 -31.51 26.46 C -31.51 26.46 -31.33 -261.77 -31.33 -261.77 C -31.33 -261.77 -94.05 -293.12 -94.05 -293.12 Z"); }
	75%,100% { d: path("M -31.05 -293.11 C -31.05 -293.11 -31.05 -324.46 -31.05 -324.46 C -31.05 -324.46 31.06 -324.46 31.06 -324.46 C 65.86 -324.46 94.05 -296 94.05 -260.9 C 94.05 -260.9 93.87 -37.08 93.87 -37.08 C 93.87 -1.99 65.67 26.46 30.88 26.46 C 30.88 26.46 -31.51 26.46 -31.51 26.46 C -31.51 26.46 -31.33 -261.77 -31.33 -261.77 C -31.33 -261.77 -31.05 -293.11 -31.05 -293.11 Z"); }
}

.pill {
	display: flex;
	align-items: center;
	height: max(44px, 3.1vw);
	padding: 0 max(20px, 1.5vw);
	border: 1px solid var(--glass-border);
	border-radius: var(--radius-pill);
	background: var(--glass-bg);
	-webkit-backdrop-filter: blur(var(--glass-blur));
	backdrop-filter: blur(var(--glass-blur));
	gap: max(20px, 1.6vw);
	font-size: var(--t-xs);
}

.nav { display: flex; align-items: center; gap: 0.8rem; }

/* Chữ cuộn 2 lớp khi hover — kỹ thuật của Align */
.roll {
	position: relative;
	display: inline-block;
	overflow: hidden;
	vertical-align: bottom;
	/* padding + margin âm bằng nhau: hộp lề không đổi nên không xê dịch layout,
	   nhưng vùng thấy được rộng thêm đúng chỗ đuôi chữ */
	padding-bottom: var(--roll-tail);
	margin-bottom: calc(var(--roll-tail) * -1);
}
.roll span { display: block; transition: transform var(--d-roll) var(--ease-text); }
.roll span::after {
	content: attr(data-t);
	position: absolute;
	/* Lúc hover, <span> có transform nên NÓ trở thành containing block của
	   ::after (transform tạo containing block cho con absolute). Vì vậy 100%
	   ở đây = chiều cao <span>, phải cộng thêm tail mới khớp quãng đẩy. */
	left: 0; top: calc(100% + var(--roll-tail));
}
a:hover .roll span,
button:hover .roll span { transform: translateY(calc(-100% - var(--roll-tail))); }

/* --------------------------------------------------------------------------
   5. Buttons
   -------------------------------------------------------------------------- */

.btn {
	display: inline-flex;
	align-items: center;
	gap: max(9px, 0.62vw);
	height: max(54px, 3.9vw);
	padding: 0 max(28px, 2.15vw);
	border-radius: var(--radius-pill);
	background: var(--btn-bg);
	color: var(--btn-fg);
	font-size: var(--t-xs);
	line-height: 1;
	white-space: nowrap;
	transition: transform 0.4s var(--ease-out);
}
.btn:hover { transform: scale(0.97); }

.btn--ghost {
	background: var(--glass-bg);
	border: 1px solid var(--glass-border);
	-webkit-backdrop-filter: blur(var(--glass-blur));
	backdrop-filter: blur(var(--glass-blur));
	color: var(--ink);
	height: max(48px, 3.4vw);
	padding: 0 max(22px, 1.7vw);
}

/* Nút trong nav: thấp hơn nút thường cho khớp pill, nhưng vẫn scale theo vw */
.btn--nav {
	height: max(44px, 3.1vw);
	padding: 0 max(22px, 1.65vw);
}

.btn svg { flex: none; }

/* --------------------------------------------------------------------------
   6. Khung ngoặc góc — motif riêng của Align
   -------------------------------------------------------------------------- */

.frame { position: relative; }
.frame > .c {
	position: absolute;
	width: var(--c, 10px);
	height: var(--c, 10px);
	z-index: 3;
	pointer-events: none;
}
/* Dùng class chứ KHÔNG dùng :nth-child — các span góc được chèn sau nội dung
   nên nth-child(1) rơi vào <img>/<svg>, làm mất hẳn góc trái trên. */
.frame > .c--tl { top: 0; left: 0; border-top: 2px solid var(--ink); border-left: 2px solid var(--ink); }
.frame > .c--tr { top: 0; right: 0; border-top: 2px solid var(--ink); border-right: 2px solid var(--ink); }
.frame > .c--bl { bottom: 0; left: 0; border-bottom: 2px solid var(--ink); border-left: 2px solid var(--ink); }
.frame > .c--br { bottom: 0; right: 0; border-bottom: 2px solid var(--ink); border-right: 2px solid var(--ink); }

.media-pad {
	padding: clamp(10px, 1vw, 16px);
	background: var(--media-bg);
	-webkit-backdrop-filter: blur(5px);
	backdrop-filter: blur(5px);
}

/* --------------------------------------------------------------------------
   8. Kẻ dọc dẫn hướng — học pear.no (.gv)
   -------------------------------------------------------------------------- */

.guide {
	position: absolute;
	top: 0;
	width: 1px;
	height: 100%;
	background: var(--hairline);
	z-index: 1;
	pointer-events: none;
}

/* --------------------------------------------------------------------------
   9. Con trỏ tuỳ biến
   -------------------------------------------------------------------------- */

.cursor {
	position: fixed;
	top: 0; left: 0;
	z-index: 9999;
	display: grid;
	place-items: center;
	width: 104px;
	height: 104px;
	border-radius: 50%;
	background: rgba(var(--ink-rgb), 0.18);
	border: 1px solid rgba(var(--ink-rgb), 0.28);
	-webkit-backdrop-filter: blur(4px);
	backdrop-filter: blur(4px);
	font-size: var(--t-xxs);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	white-space: nowrap;
	pointer-events: none;
	transform: translate(-50%, -50%) scale(0);
	transition: transform 0.35s var(--ease-out);
	visibility: hidden;
}
.cursor.is-on { transform: translate(-50%, -50%) scale(1); }
/* Nền sáng: mực là màu tối nên chữ trong con trỏ sẽ đen trên bong bóng nhạt,
   nằm đè lên ảnh thì đọc không ra. Ghim chữ trắng và cho bong bóng tối lại. */
body.is-light .cursor {
	color: #fff;
	background: rgba(13, 16, 17, 0.38);
	border-color: rgba(13, 16, 17, 0.45);
}

/* Chế độ ảnh — dùng ở danh sách người trang About.
   Hai lớp <i> chồng nhau trong một khung cắt: đổi người thì lớp mới trượt vào
   còn lớp cũ bị đẩy ra, chiều lên hay xuống tuỳ hover đi lên hay đi xuống. */
.cursor--img {
	width: max(168px, 13vw);
	height: max(168px, 13vw);
	border-radius: 0;
	border-color: rgba(var(--ink-rgb), 0.42);
	background-color: var(--media-bg);
	-webkit-backdrop-filter: none;
	backdrop-filter: none;
	transition: transform 0.45s var(--ease-out);
}
.cursor__t { display: block; }
.cursor--img .cursor__t { display: none; }

.cursor__m {
	position: absolute;
	inset: 0;
	overflow: hidden;
	display: none;
}
.cursor--img .cursor__m { display: block; }

.cursor__m i {
	position: absolute;
	inset: 0;
	background-size: cover;
	background-position: center;
	transform: translateY(100%);
	/* --ease-out: cubic-bezier(0.16, 1, 0.3, 1) — vọt nhanh rồi trôi chậm dần
	   về đích (ease-out / giảm tốc, cỡ expo-out). */
	transition: transform var(--d-push) var(--ease-out);
	will-change: transform;
}

/* Khung NGANG cho thumbnail dự án (kho việc trang Works) */
.cursor--img.cursor--wide {
	width: max(260px, 21vw);
	height: calc(max(260px, 21vw) * 0.625);
}

/* Chế độ mũi tên — thẻ bài blog: vòng nhỏ hơn hẳn, mang mũi tên thay chữ */
.cursor__a { display: none; width: 34%; }
.cursor__a svg { display: block; width: 100%; height: auto; }
.cursor--arrow { width: 64px; height: 64px; }
.cursor--arrow .cursor__t { display: none; }
.cursor--arrow .cursor__a { display: block; }

@media (min-width: 1100px) and (hover: hover) {
	.cursor { visibility: visible; }
	[data-cursor] { cursor: none; }
	[data-cursor] * { cursor: none; }
	[data-cursor-img] { cursor: none; }
	[data-cursor-img] * { cursor: none; }
}

/* --------------------------------------------------------------------------
   10. Thanh tiến độ trang
   -------------------------------------------------------------------------- */

.progress {
	position: fixed;
	left: 0; top: 0;
	height: 2px;
	width: 100%;
	transform-origin: left;
	transform: scaleX(var(--page, 0));
	background: var(--ink);
	z-index: 95;
}

/* --------------------------------------------------------------------------
   11. Menu mobile
   -------------------------------------------------------------------------- */

.menu-btn {
	display: none;
	position: relative;
	align-items: center;
	justify-content: center;
	width: 48px; height: 44px;
	border: 1px solid var(--glass-border);
	border-radius: var(--radius-pill);
	background: var(--glass-bg);
	-webkit-backdrop-filter: blur(var(--glass-blur));
	backdrop-filter: blur(var(--glass-blur));
	z-index: 95;
}
/* Hai vạch là hai pseudo-element đặt tuyệt đối, lệch đều ±3px quanh tâm.
   Trước đây ::after nằm trong luồng dưới <i> nên cả cụm bị đẩy xuống dưới tâm. */
.menu-btn i {
	position: relative;
	display: block;
	width: 16px; height: 1px;
}
.menu-btn i::before,
.menu-btn i::after {
	content: '';
	position: absolute;
	left: 0;
	width: 16px; height: 1px;
	background: var(--ink);
	transition: transform 0.4s var(--ease-out);
}
.menu-btn i::before { top: -3px; }
.menu-btn i::after { top: 3px; }
.menu-btn.is-open i::before { transform: translateY(3px) rotate(45deg); }
.menu-btn.is-open i::after { transform: translateY(-3px) rotate(-45deg); }

/* Menu mobile — bố cục học stormbrain: thanh trên (logo + đóng), thân cuộn
   được (pill dịch vụ + danh sách link có ô mũi tên), nút CTA dính đáy. */
.sheet {
	/* Menu luôn nền tối ở mọi theme nên tự ghim mực trắng. Phải đặt color tường
	   minh: ghim --ink-rgb chỉ đổi các token, còn color thì thừa hưởng thẳng từ
	   body nên ở nền sáng chữ menu sẽ đen trên nền tối. */
	--ink-rgb: 255, 255, 255;
	color: var(--body);
	position: fixed;
	inset: 0;
	z-index: 94;
	display: flex;
	flex-direction: column;
	background: var(--sheet-bg);
	transform: translateX(100%);
	transition: transform var(--d1) var(--ease-out);
}
.sheet.is-open { transform: none; }

.sheet__top {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding: 1.2rem var(--gutter);
	border-bottom: 1px solid var(--hairline);
}
.sheet__logo img { display: block; width: 62px; height: auto; }

.sheet__close {
	display: grid;
	place-items: center;
	width: 48px; height: 44px;
	border: 1px solid var(--glass-border);
	border-radius: var(--radius-pill);
	background: var(--glass-bg);
	color: var(--ink);
	transition: background 0.3s var(--ease);
}
.sheet__close:hover { background: rgba(var(--ink-rgb), 0.18); }
.sheet__close svg { width: 20px; height: 20px; }

/* Thân cuộn được: menu vẫn dùng được trên máy màn thấp */
.sheet__body {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	display: flex;
	flex-direction: column;
	gap: 1.2rem;
	padding: 1.6rem var(--gutter) 2rem;
}
.sheet__pills { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-bottom: 0.6rem; }

.sheet__nav { display: flex; flex-direction: column; }
.sheet__row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding-block: 1.1rem;
	border-top: 1px solid var(--hairline);
	font-size: var(--t-l);
	line-height: 1.15;
}
.sheet__row:last-child { border-bottom: 1px solid var(--hairline); }
.sheet__go {
	position: relative;
	display: grid;
	place-items: center;
	flex: none;
	width: 38px; height: 38px;
	--c: 5px;
	transition: background 0.3s var(--ease);
}
.sheet__go svg { width: 14px; height: 14px; }
.sheet__row:hover .sheet__go { background: rgba(var(--ink-rgb), 0.12); }

/* margin-top:auto — đẩy email xuống đáy vùng cuộn để màn cao không hở
   một mảng trống giữa danh sách link và nút CTA. */
.sheet__mail { margin-top: auto; padding-top: 1.4rem; font-size: var(--t-xs); color: var(--muted); }

/* Đáy: CTA chạy hết bề ngang + hàng mạng xã hội */
.sheet__bottom {
	display: flex;
	flex-direction: column;
	gap: 1.4rem;
	padding: 1.2rem var(--gutter) max(1.4rem, env(safe-area-inset-bottom));
	border-top: 1px solid var(--hairline);
	background: var(--sheet-bg);
}
.sheet__cta { width: 100%; justify-content: center; }
.sheet__foot { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }

.sheet__soc { display: flex; gap: 0.7rem; }
.soc {
	display: grid;
	place-items: center;
	width: 44px; height: 44px;
	border: 1px solid var(--glass-border);
	border-radius: 50%;
	color: var(--ink);
	transition: background 0.3s var(--ease);
}
.soc:hover { background: rgba(var(--ink-rgb), 0.18); }
.soc svg { width: 21px; height: 21px; }

html.locked, body.locked { overflow: hidden; }

/* --------------------------------------------------------------------------
   Nút đổi nền — góc trái dưới, chỉ hiện khi đã qua hết scene hero
   -------------------------------------------------------------------------- */

/* Thanh điều khiển góc dưới phải: nút đổi ngôn ngữ đứng trước, nút đổi nền
   đứng sau. Gom vào một khung flex nên hai nút tự thẳng hàng, không phải đo
   bề ngang của nút kia để đặt offset. */
.ctl-rail {
	position: fixed;
	right: var(--edge);
	bottom: max(18px, 2vh);
	z-index: 88;
	display: flex;
	align-items: center;
	gap: 8px;
}

.theme-btn {
	/* Tuỳ chọn cho dịu mắt, không phải element chính: cỡ cố định (không scale
	   theo vw như các control khác) để màn càng to nó càng khiêm tốn. */
	display: inline-flex;
	align-items: center;
	gap: 8px;
	height: 34px;
	padding: 0 11px;
	border: 1px solid var(--hairline);
	border-radius: var(--radius-pill);
	background: rgba(var(--ink-rgb), 0.06);
	-webkit-backdrop-filter: blur(var(--glass-blur));
	backdrop-filter: blur(var(--glass-blur));
	color: var(--ink);
	opacity: 0;
	transform: translateY(14px);
	pointer-events: none;
	transition:
		opacity 0.5s var(--ease),
		transform 0.5s var(--ease-out),
		background 0.3s var(--ease);
}
.theme-btn.is-on { opacity: 0.72; transform: none; pointer-events: auto; }
.theme-btn.is-on:hover,
.theme-btn.is-on:focus-visible { opacity: 1; background: rgba(var(--ink-rgb), 0.18); }

/* Nút EN/VI. Cùng vỏ với nút nền để hai cái đọc ra là một bộ. Bản dịch chưa có
   thì nửa kia là <span class="is-off"> — xám và không bấm được, chứ không dẫn
   sang một trang không tồn tại. */
.lang-btn {
	display: inline-flex;
	align-items: center;
	height: 34px;
	padding: 0 3px;
	border: 1px solid var(--hairline);
	border-radius: var(--radius-pill);
	background: rgba(var(--ink-rgb), 0.06);
	-webkit-backdrop-filter: blur(var(--glass-blur));
	backdrop-filter: blur(var(--glass-blur));
	opacity: 0;
	transform: translateY(14px);
	pointer-events: none;
	transition:
		opacity 0.5s var(--ease),
		transform 0.5s var(--ease-out);
}
.lang-btn.is-on { opacity: 0.72; transform: none; pointer-events: auto; }
.lang-btn.is-on:hover,
.lang-btn.is-on:focus-within { opacity: 1; }

.lang-btn > a,
.lang-btn > span {
	display: inline-flex;
	align-items: center;
	height: 24px;
	padding: 0 7px;
	border-radius: var(--radius-pill);
	/* Cỡ CHỮ CỐ ĐỊNH, không đi theo --t-xxs (cái đó nở theo vw, màn to thành
	   ra hai chữ EN/VI to hơn cả nút đổi nền nằm ngay kế bên). */
	font-size: 11px;
	line-height: 1;
	letter-spacing: 0.08em;
	color: var(--ink);
	opacity: 0.55;
	transition: opacity 0.25s var(--ease), background 0.25s var(--ease);
}
.lang-btn > a:hover,
.lang-btn > a:focus-visible { opacity: 1; }
.lang-btn > a.is-on {
	opacity: 1;
	background: rgba(var(--ink-rgb), 0.18);
}
.lang-btn > .is-off { opacity: 0.42; cursor: not-allowed; }

/* Công tắc ba nấc: ba chấm đúng bằng ba nền, nấc đang bật thì to hơn và có vòng
   sáng quanh. Ba mã màu này là MẪU của từng nền nên đóng đinh, không đi theo
   kênh mực — đổi theo theme thì không còn phân biệt được nấc nào là nấc nào. */
.theme-btn__dot {
	width: 10px;
	height: 10px;
	border-radius: 50%;
	flex: none;
	box-shadow: 0 0 0 1px rgba(var(--ink-rgb), 0.35);
	opacity: 0.5;
	transition: opacity 0.3s var(--ease), transform 0.3s var(--ease-out),
		box-shadow 0.3s var(--ease);
}
.theme-btn__dot--ground { background: #bf400b; }
.theme-btn__dot--dark { background: #0d1011; }
.theme-btn__dot--light { background: #f3efe8; }
.theme-btn[data-theme="ground"] .theme-btn__dot--ground,
.theme-btn[data-theme="dark"] .theme-btn__dot--dark,
.theme-btn[data-theme="light"] .theme-btn__dot--light {
	opacity: 1;
	transform: scale(1.22);
	box-shadow: 0 0 0 2px rgba(var(--ink-rgb), 0.85);
}

@media (max-width: 640px) {
	.menu-btn { display: flex; }

	/* Nút đổi nền cố định cỡ nên ở khổ hẹp nó phình to hơn cả chữ quanh nó —
	   đo được 81x34 trong khi "Back to top" chỉ 62x18. Thu lại cho vừa phải. */
	.theme-btn { height: 26px; padding: 0 8px; gap: 6px; }
	.lang-btn { height: 26px; padding: 0 3px; }
	.lang-btn > a,
	.lang-btn > span { height: 20px; padding: 0 6px; font-size: 10px; }
	.theme-btn__dot { width: 8px; height: 8px; }
}

/* --------------------------------------------------------------------------
   12. Đồ hoạ service: vẽ nét khi xuất hiện + trôi theo scroll
   -------------------------------------------------------------------------- */

/* Vào khung nhìn: nét tự vẽ ra (pathLength="1" nên chuẩn hoá được mọi hình) */
.svc__art [stroke] {
	stroke-dasharray: 1;
	stroke-dashoffset: 1;
	transition: stroke-dashoffset 1.7s var(--ease-out);
	transition-delay: calc(var(--k, 0) * 110ms);
}
.is-in .svc__art [stroke] { stroke-dashoffset: 0; }

/* Hình đặc thì hiện bằng scale + mờ */
.svc__art [data-pop] {
	opacity: 0;
	/* Dùng longhand `scale` chứ không phải `transform`: hình nào cũng còn một
	   transform riêng theo scroll, hai thứ này phải nhân với nhau chứ không đè nhau. */
	scale: 0.4;
	transform-origin: center;
	transition: opacity 0.9s var(--ease-out), scale 1.1s var(--ease-out);
	transition-delay: 0.5s;
}
.is-in .svc__art [data-pop] { opacity: 1; scale: 1; }

/* --- Chuyển động khi cuộn: mỗi graphic một ý đồ, không phải parallax ---------
   JS ghi --sp (0 khi vào khung nhìn → 1 khi ra khỏi). Mọi thứ tính bằng calc().
   KHÔNG đặt transition cho mấy thuộc tính chạy theo --sp: --sp đổi MỖI khung
   (cuộn đã được làm mượt sẵn), nên mỗi khung trình duyệt lại huỷ và dựng mới
   một transition cho từng phần tử — riêng hình AI & GEO là 54 chấm × 2 thuộc
   tính. Bỏ đi thì p95 ở hàng đó từ 47.9ms xuống 30.1ms. */

.svc__art svg [data-pop] { transform-box: fill-box; transform-origin: center; }

/* Branding — 3 vòng tròn dồn về tâm.
   --n = -1/0/1. sp=0 → tách ra ±122px (đúng bố cục gốc); sp=1 → chồng khít. */
.art--marks .cv {
	transform-box: view-box;
	transform: translateX(calc(var(--n) * (1 - var(--sp, 0)) * 122px));
}
.art--marks .core {
	transform-box: fill-box;
	transform-origin: center;
	transform: scale(calc(1 + var(--sp, 0) * 0.26));
}

/* Website — các khung siết lại gần nhau.
   sp=0 → lệch nhau (42px, 28px); sp=1 → gần như chồng lên nhau (10px, 7px). */
.art--layers .cv {
	transform-box: view-box;
	transform: translate(
		calc(var(--n) * (10px + (1 - var(--sp, 0)) * 32px)),
		calc(var(--n) * (7px  + (1 - var(--sp, 0)) * 21px)));
}

/* SEO — kết quả sáng leo từ hạng 6 lên hạng 1 (5 hàng × 74px = 370px). */
.art--ranks .climb {
	transform-box: view-box;
	transform: translateY(calc((1 - var(--sp, 0)) * 370px));
}

/* AI & GEO — chấm thay nhau phồng/xẹp, đứng yên tại chỗ.
   Sóng tam giác chạy 3 nhịp trong một lần cuộn qua; --pk là độ lệch pha của
   từng nhóm nên các chấm nối tiếp nhau chứ không phồng cùng lúc.
   Chấm to thì đậm, chấm nhỏ thì mờ — dùng fill-opacity chứ không phải opacity,
   vì opacity đã bị animation lúc xuất hiện ([data-pop]) chiếm. */
.art--lattice .pulse {
	transform-box: fill-box;
	transform-origin: center;
	--ph: mod(calc(var(--sp, 0) * 3 + var(--pk)), 1);   /* 0 → 1, lặp lại */
	--t: calc(1 - 2 * abs(calc(var(--ph) - 0.5)));      /* tam giác 0 → 1 → 0 */
	transform: scale(calc(0.5 + var(--t)));             /* 0.5 ↔ 1.5 */
	fill-opacity: calc(0.25 + 0.75 * var(--t));
}

@media (prefers-reduced-motion: reduce) {
	.svc__art [stroke] { stroke-dashoffset: 0 !important; transition: none !important; }
	.svc__art [data-pop] { opacity: 1 !important; scale: 1 !important; }
	.art--marks .cv, .art--layers .cv, .art--ranks .climb, .art--lattice .pulse {
		transform: none !important;
	}
	.art--lattice .pulse { fill-opacity: 1 !important; }
}
