/* ============================================================
   loading.css — Màn hình chờ (preloader)
   FILE RỜI — KHÔNG @import vào input.css (yêu cầu: có session khác
   đang sửa song song input.css/tokens.css, tách biệt để tránh đụng).

   Cách ghép: <link rel="stylesheet"> file này thẳng trong <head>
   index.html, sau thẻ load output.css (không bắt buộc thứ tự vì
   không có class nào trùng tên với output.css, nhưng để sau cho dễ
   tra khi đọc DevTools). Xem LOADING-README.md.

   Vẫn theo đúng chuẩn design system dù không đi qua Tailwind:
   - CHỈ rem, không px.
   - Màu/bo góc/easing LẤY LẠI biến của tokens.css bằng var(), có giá
     trị dự phòng phía sau dấu phẩy. tokens.css khai trong @theme nên
     Tailwind biên dịch chúng thành custom property trên :root ngay
     trong theme/css/output.css — trang thật load output.css nên các
     biến này CÓ SẴN ở runtime, file loading.css chỉ việc var() lại,
     không hard-code màu riêng một bộ thứ hai dễ lệch tông.
   - line-height không áp dụng ở đây vì không có đoạn văn bản dài.
   ============================================================ */

.site-preloader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  /* Nền màu thương hiệu, KHÔNG dùng trắng trơn — soi 4 site bất động sản
     tham khảo (goldencity/sengroup/dreamville/goldensun) thì cả 4 đều
     dùng 1 màu nền riêng cho màn chờ, không bao giờ để trắng phau. Dùng
     brand-soft (nhạt) chứ không phải navy đậm như họ, vì icon vốn đã có
     màu nhạt/vàng kem — nền tối sẽ làm lớp --base (bản mờ) gần như chìm
     mất, ngược hẳn mục đích "vẫn thấy khung icon trước khi tô màu". */
  background: var(--color-brand-soft, #c4e7fb);
  opacity: 1;
  /* Tách riêng property/duration/timing (không viết shorthand transition) —
     bài học ghi trong CLAUDE.md 4.7: shorthand ở ngoài @layer sẽ thắng và
     xoá mất mọi transition-delay nếu sau này có ai thêm delay tại đây. */
  transition-property: opacity;
  transition-duration: 0.4s;
  transition-timing-function: var(--ease-brand, cubic-bezier(0.22, 1, 0.36, 1));
}

/* Không có JS thì không được phép che nội dung: main.js (và loading.js,
   phòng khi main.js chưa kịp chạy) gắn class "js" lên <html>. Không JS
   -> preloader ẩn hẳn ngay từ CSS, không chờ script gỡ. */
html:not(.js) .site-preloader {
  display: none;
}

.site-preloader.is-hiding {
  opacity: 0;
  pointer-events: none;
}

/* ---------- Khối logo: icon fill màu dần + chữ tĩnh bên dưới ----------
   Logo gốc (logo-kto.webp) là 1 khối ngang icon+chữ ghép sẵn. Icon cắt
   riêng thành ảnh MỚI bằng ffmpeg (giữ nguyên pixel, không vẽ lại):
     logo-kto-icon.webp  514x592  — chỉ khối tượng tròn nhiều màu
   Phần CHỮ thì KHÔNG dùng ảnh cắt ra — 3 dòng chữ trong logo gốc canh
   TRÁI, so le phải (dòng "DU LỊCH HÀN QUỐC" dài nhất quyết định bề rộng
   khung ảnh, dòng "TỔNG CỤC" ngắn hơn nằm lệch trái trong khung đó) nên
   dù khung ảnh căn giữa, mắt vẫn thấy chữ lệch trái — đã thử và bị chê.
   Thay bằng CHỮ HTML THẬT + `text-align: center`: mỗi dòng tự canh giữa
   độc lập, không lệ thuộc bounding-box ảnh. Font "Plus Jakarta Sans" có
   sẵn qua @font-face của tokens.css (output.css nạp trước loading.css).
   Xếp icon trên / chữ dưới bằng flex column — không phải bố cục có sẵn
   trong ảnh gốc (ảnh gốc xếp ngang), ghép lại ở layer CSS. */
.site-preloader__brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  /* Logo không đứng yên ngay từ khung hình đầu — 4 site tham khảo đều cho
     logo "xuất hiện" (vẽ nét dần hoặc mờ+phóng to) chứ không tĩnh ngay từ
     đầu. Ta không có path vector để vẽ nét (logo KTO là ảnh nhiều gradient,
     xem lý do ở khối icon bên dưới), nên mô phỏng cảm giác "xuất hiện" đó
     bằng mờ dần + thu nhỏ nhẹ (0.92 -> 1). `both` giữ trạng thái "from"
     trước khi animation chạy, tránh loé khung hình đầy đủ rồi mới lùi lại. */
  animation: preloader-brand-in 0.5s var(--ease-brand, cubic-bezier(0.22, 1, 0.36, 1)) both;
  /* Cùng bộ thuộc tính này còn dùng lại lúc ẩn (xem .is-hiding bên dưới) —
     tách riêng property, không viết transition: shorthand (lý do xem đầu file). */
  transition-property: opacity, scale, filter;
  transition-duration: 0.5s;
  transition-timing-function: var(--ease-brand, cubic-bezier(0.22, 1, 0.36, 1));
}

@keyframes preloader-brand-in {
  from {
    opacity: 0;
    scale: 0.92;
  }
  to {
    opacity: 1;
    scale: 1;
  }
}

/* Thoát KHÔNG chỉ mờ phẳng — 3/4 site tham khảo cho logo mờ dần + phóng to
   nhẹ + blur khi màn chờ tắt (như máy ảnh kéo nét ra xa), mượt hơn hẳn một
   cú cắt opacity. Chỉ áp cho khối logo, KHÔNG áp cho .site-preloader (nền
   toàn màn hình) — blur/scale cả nền trắng phía sau icon không có ý nghĩa
   gì, chỉ tốn hiệu năng composite thêm. */
.site-preloader.is-hiding .site-preloader__brand {
  opacity: 0;
  scale: 1.06;
  filter: blur(0.375rem);
}

/* 2 <img> CÙNG MỘT src (logo-kto-icon.webp) chồng lên nhau: lớp dưới xám
   mờ làm "khung nền", lớp trên giữ nguyên màu gốc nhưng bị clip-path cắt,
   rồi CHẠY BẰNG CSS ANIMATION (không phải JS) từ ẩn hoàn toàn -> hiện đủ
   để lộ dần từ trái sang phải (xem @keyframes preloader-icon-fill bên
   dưới). Dùng clip-path thay vì SVG mask/marker vì chạy được trên toàn bộ
   trình duyệt mục tiêu, không cần cú pháp mới — trình duyệt chỉ tải ảnh 1
   lần (cache), 2 thẻ <img> không tốn thêm request.

   Khung ép VUÔNG (width = height), không để height ăn theo tỉ lệ ảnh
   (514x592, cao hơn rộng) như bản trước — vòng tiến trình bọc quanh
   (.site-preloader__ring bên dưới) là hình tròn thật, khung không vuông
   sẽ kéo nó méo thành elip. object-fit: contain giữ icon không méo dù
   khung là vuông còn ảnh thì không.

   QUAN TRỌNG: khung này CHÍNH LÀ kích thước cả vòng tròn (ring lấp đầy
   100% khung, xem .site-preloader__ring bên dưới) — icon nằm NHỎ HƠN,
   thụt vào giữa bằng inset dương. Bản trước làm ngược lại (khung = kích
   thước icon, vòng tràn RA NGOÀI bằng inset ÂM) nên vòng không thật sự
   chiếm chỗ trong layout: `gap` giữa icon-wrap và chữ bên dưới chỉ đo tới
   mép khung icon, phần vòng tràn ra ngoài dễ đè lên chữ nếu tăng to thêm
   — đó là lý do trước đó không dám tăng mạnh. Giờ khung = vòng nên tăng
   to bao nhiêu, `gap` vẫn tính đúng từ mép NGOÀI CÙNG của vòng, không
   bao giờ đè chữ. */
.site-preloader__icon-wrap {
  position: relative;
  width: 14rem;
  height: 14rem;
}

@media (max-width: 26.5625rem) {
  .site-preloader__icon-wrap {
    width: 10.5rem;
    height: 10.5rem;
  }
}

.site-preloader__icon {
  /* Ép width/height CỐ ĐỊNH bằng số (không phải "auto") — <img> là phần
     tử "replaced", với absolute + inset + width:auto trình duyệt KHÔNG
     giãn nó lấp khoảng trống giữa các inset như <div> thường, mà lại tính
     theo kích thước ẢNH GỐC (514x592px ≈ 32x37rem) rồi tràn ra ngoài
     khung — đúng lỗi đã xảy ra (icon phình to lấn qua cả vòng tròn).
     Cặp inset:0 + margin:auto + width/height cố định là cách căn giữa an
     toàn cho mọi loại phần tử (kể cả "replaced"), không phụ thuộc thuật
     toán auto-sizing riêng của ảnh. */
  position: absolute;
  inset: 0;
  margin: auto;
  width: 9rem; /* nhỏ hơn khung/vòng (14rem) để còn thấy viền vòng tròn xung quanh */
  height: 9rem;
  object-fit: contain;
}

@media (max-width: 26.5625rem) {
  .site-preloader__icon {
    width: 6.5rem; /* khung/vòng mobile 10.5rem */
    height: 6.5rem;
  }
}

.site-preloader__icon--base {
  /* Bản mờ làm "khung" phía sau cho lớp tô màu quét qua.

     CHỈ hạ opacity — TUYỆT ĐỐI không grayscale/filter đổi màu. Bản trước
     dùng grayscale(1) để "nhìn rõ hình dạng dù chưa tô màu": đó là đổi màu
     logo KTO, không được phép, dù chỉ hiện 1.8 giây. Logo là bộ nhận diện
     của khách, mình chỉ được đặt chứ không được sửa.

     Bù lại bằng cách nâng opacity 0.22 -> 0.3: mất grayscale thì bản nền
     nhạt hơn về mặt tương phản hình khối, nâng độ đục lên là đủ thấy rõ
     mà vẫn tách bạch với lớp tô màu đầy đủ ở trên. */
  opacity: 0.3;
}

/* Chạy MỘT LẦN, thật sự từ 0% -> 100% bằng CSS animation cố định thời
   lượng — KHÔNG còn dùng JS tick từng khung hình + biến --fill nữa (bản
   trước: JS ước lượng % theo ảnh tải xong / thời gian trôi qua, nên nếu
   trang load nhanh thì preloader chỉ kịp chạy tới giữa chừng rồi bị JS
   nhảy cụt lên 100% — người dùng không thấy được trọn vẹn cả quãng đường
   0->100%). Giờ animation TỰ chạy đủ ANIM_MS (khớp hằng số cùng tên trong
   loading.js) mỗi khi phần tử xuất hiện, không phụ thuộc tốc độ tải thật;
   loading.js chỉ đợi animation này phát xong (bắt sự kiện `animationend`)
   VÀ trang tải xong/hết giờ chờ — cái nào lâu hơn — rồi mới cho ẩn. */
.site-preloader__icon--fill {
  clip-path: inset(0 100% 0 0);
  animation: preloader-icon-fill 1.8s var(--ease-brand, cubic-bezier(0.22, 1, 0.36, 1)) forwards;
}

@keyframes preloader-icon-fill {
  from {
    clip-path: inset(0 100% 0 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}

/* ---------- Vòng tiến trình bao quanh icon ----------
   Học từ 4 site tham khảo: logo không đứng yên trong lúc chờ mà có một
   chuyển động "đang vẽ/đang chạy" ăn khớp với tiến trình thật (bên kia họ
   vẽ nét chính logo bằng stroke-dasharray vì logo của họ là 1 màu, có
   path vector sẵn). Logo KTO là ảnh raster nhiều gradient — không có path
   để vẽ nét theo đúng hình, nên KHÔNG vẽ theo hình logo (vẽ ẩu sẽ méo
   hình chính thức). Thay bằng 1 vòng tròn generic (không mang hình logo)
   bọc quanh icon, tự "đầy" dần theo đúng 1 nhịp animation cố định (không
   phải % tải trang thật — trình duyệt không có API đó, xem loading.js) —
   vẫn đúng tinh thần "có gì đó đang vẽ dần" mà không đụng tới hình logo.
   Dùng transform: rotate() (không phải translate/scale) — an toàn vì SVG
   này không có class Tailwind rotate-*/scale-* nào khác cộng dồn vào,
   khác với các phần tử trong index.html mà CLAUDE.md mục 4.7 cảnh báo. */
.site-preloader__ring {
  position: absolute;
  /* Lấp đầy TOÀN BỘ icon-wrap (icon-wrap giờ chính là kích thước vòng,
     xem comment ở .site-preloader__icon-wrap) — không còn inset âm/overflow. */
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg); /* bắt đầu vẽ từ đỉnh 12 giờ, không phải 3 giờ */
}

.site-preloader__ring-track {
  fill: none;
  stroke: var(--color-paper, #ffffff);
  stroke-width: 4;
}

.site-preloader__ring-progress {
  fill: none;
  stroke: var(--color-brand, #1f97e7);
  stroke-width: 4;
  stroke-linecap: round;
  /* 289 ≈ chu vi đường tròn r=46 trong viewBox 100x100 (2 * PI * 46) —
     rỗng hoàn toàn lúc bắt đầu. Cùng animation, cùng thời lượng 1.8s với
     icon--fill ở trên để 2 hiệu ứng "đầy" cùng lúc, nhìn như 1 khối thống
     nhất chứ không lệch nhịp nhau. */
  stroke-dasharray: 289;
  stroke-dashoffset: 289;
  animation: preloader-ring-fill 1.8s var(--ease-brand, cubic-bezier(0.22, 1, 0.36, 1)) forwards;
}

@keyframes preloader-ring-fill {
  from {
    stroke-dashoffset: 289;
  }
  to {
    stroke-dashoffset: 0;
  }
}

/* Chữ "Tổng cục Du lịch Hàn Quốc" — đứng yên (không tham gia hiệu ứng fill
   của icon), canh giữa thật sự bằng text-align (không phải ảnh nên không
   bị lệch trái theo dòng dài/ngắn — xem lý do bỏ ảnh chữ ở trên). */
.site-preloader__wordmark {
  margin: 0;
  /* 23rem (không phải 20rem như bản trước): đo thật bằng Range API trong
     Chrome thì dòng phụ đề (nowrap, 1.125rem + letter-spacing 0.1em) rộng
     tới 330px trong khi khung 20rem chỉ còn 288px chỗ chứa (20rem - 2rem
     padding) — chữ TRÀN khung, mà tràn kiểu nowrap+overflow chỉ tràn về
     MỘT PHÍA (phải) chứ không chia đều 2 bên, nên text-align:center mất
     tác dụng, chữ bị lệch tâm thấy rõ (đo được: tâm chữ lệch phải 19px so
     với tâm mọi thứ khác). Nới khung đủ rộng để phụ đề luôn NẰM LỌT bên
     trong (330px < 23rem - 2rem = 336px) thì text-align:center mới canh
     đúng — không cố "ép vừa" bằng nowrap nữa mà né hẳn tình huống tràn. */
  max-width: 23rem;
  padding-inline: 1rem;
  text-align: center;
  font-family: var(--font-sans, "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif);
  line-height: 1.4; /* chuẩn dự án: line-height 1.4 cho mọi bậc chữ */
}

/* Dòng chính — tô ĐÚNG MÀU CHỮ TRONG LOGO: #717173.

   Lấy bằng cách quét pixel logo-kto.webp (1776x672), vùng chữ x >= 35%:
   màu chiếm áp đảo ở CẢ hai dòng (Việt và Anh) đều là rgb(113,113,115),
   ~59.000 px cho dòng Việt và ~16.000 px cho dòng Anh. Hai dòng trong
   logo dùng CHUNG một màu, nhìn dòng trên đậm hơn chỉ vì nó in đậm và
   cỡ lớn hơn, không phải vì màu khác.

   ĐÃ BỎ hiệu ứng chữ chạy màu cầu vồng (shimmer brand/pink-hi/accent).
   Đừng thêm lại: khối chữ này là WORDMARK — phần chữ của bộ nhận diện
   KTO, đi liền ngay dưới biểu tượng. Tô nó bằng dải màu tự chọn là sửa
   bộ nhận diện của khách, cùng loại lỗi với việc đổi màu logo (xem
   CLAUDE.md 6.7). Biểu tượng phía trên đã có hiệu ứng quét màu rồi,
   phần chữ đứng yên là đúng vai. */
.site-preloader__wordmark-vi {
  font-size: 1.75rem; /* to hẳn — không khớp đúng 1 bậc nào trong thang 6 bậc của tokens.css vì tiêu đề này nằm ngoài pipeline Tailwind, chọn giá trị nằm giữa --text-xl (1.25) và --text-3xl (2) cho vừa bề rộng preloader */
  font-weight: bold; /* dự án chỉ có 2 mức đậm: thường / bold, không font-semibold */
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: #717173;
}

@media (max-width: 26.5625rem) {
  /* 1.75rem chữ hoa có dấu trên màn ~375px trở xuống dễ vỡ dòng xấu (rơi
     đúng giữa 1 từ) — hạ về 1.25rem, vẫn to hơn hẳn bản gốc 0.6875rem. */
  .site-preloader__wordmark-vi {
    font-size: 1.25rem;
  }
}

.site-preloader__wordmark-en {
  margin-top: 0.375rem;
  /* Bản trước dùng letter-spacing 0.3em để "kéo dài" — quá tay, đủ rộng
     để tự vỡ dòng thành 2 dòng, ngược lại ý muốn "1 dòng". Đổi cách: ép
     KHÔNG được xuống dòng (white-space: nowrap) + tăng font-size vừa đủ
     để bề ngang một dòng gần bằng dòng tiêu đề phía trên, letter-spacing
     hạ về mức bình thường (chỉ để tách chữ nhẹ, không dùng để kéo dài nữa). */
  font-size: 1.125rem;
  /* Cùng #717173 với dòng trên — đúng như logo, KHÔNG dùng --color-muted
     (#828282): lệch một chút nhưng đặt ngay cạnh nhau là thấy hai dòng
     không cùng tông. */
  color: #717173;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  white-space: nowrap;
}

@media (max-width: 26.5625rem) {
  .site-preloader__wordmark-en {
    /* Giữ đúng tỉ lệ với dòng tiêu đề đã hạ xuống 1.25rem ở trên — không
       hạ theo sẽ gần bằng cỡ tiêu đề, mất phân cấp chính/phụ trên mobile. */
    font-size: 0.8125rem;
  }
}

/* Chữ dành cho screen reader, ẩn mắt thường — không dùng "sr-only" của
   Tailwind vì lớp này sống ngoài pipeline build, tự định nghĩa cho chắc. */
.site-preloader__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Khoá cuộn trang lúc preloader hiện. Đặt tên riêng "preloader-lock",
   KHÔNG dùng lại class "overflow-hidden" mà main.js gắn cho drawer menu
   — hai cơ chế khác nhau bật/tắt cùng class dễ đá nhau (đóng preloader
   lỡ tay gỡ luôn khoá cuộn của drawer đang mở, hoặc ngược lại). */
body.preloader-lock {
  overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .site-preloader,
  .site-preloader__brand,
  .site-preloader__icon--fill,
  .site-preloader__ring-progress,
  .site-preloader__wordmark-vi {
    transition: none;
    animation: none;
  }
  /* Tắt animation thì clip-path/stroke-dashoffset rơi về giá trị TĨNH khai
     trong rule gốc — mà giá trị đó là trạng thái BẮT ĐẦU (0%, rỗng), tức
     icon/vòng sẽ đứng yên ở dạng "chưa tô màu" mãi mãi nếu không ép lại.
     Ép thẳng về trạng thái CUỐI (đầy đủ) ở đây — cùng nguyên tắc với khối
     reduced-motion trong input.css: không chỉ tắt animation mà còn phải
     tự tay đặt lại kết quả cuối cùng. */
  .site-preloader__icon--fill {
    clip-path: inset(0 0 0 0);
  }
  .site-preloader__ring-progress {
    stroke-dashoffset: 0;
  }
  .site-preloader.is-hiding {
    opacity: 0;
  }
  .site-preloader.is-hiding .site-preloader__brand {
    opacity: 0;
    scale: 1;
    filter: none;
  }
}
