/* =============================================================
   BASE — reset, chữ nền, tiện ích khung trang, hiện dần khi cuộn
   ============================================================= */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 4.5rem;      /* chừa chỗ cho nav dính */
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--f-body);
  font-size: var(--t-body);
  font-weight: 300;
  line-height: 1.75;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

/* ---------- THỚ GIẤY ----------
   Mọi khối tự sơn nền riêng nên nhiễu phải dán lên TỪNG mặt, không thể
   phủ một lớp chung: một lớp position:fixed thì thớ đứng yên trong khi
   chữ chạy qua -> đọc ra bụi trên màn hình chứ không ra mặt giấy.

   Danh sách này phải khớp với danh sách khối có `background` riêng
   trong sections.css. Thêm khối có nền mới thì thêm vào đây, không thì
   giữa trang sẽ có đúng một mảng láng bóng lộ ra.

   background-attachment mặc định (scroll) là CỐ Ý: thớ giấy phải trôi
   cùng nội dung.

   BẪY: các khối đó phải khai báo `background-color`, KHÔNG được viết
   tắt `background:`. Viết tắt sẽ đặt lại background-image về none, mà
   sections.css nạp sau base.css nên nó thắng — mất thớ, không báo lỗi. */
body, .std, .det, .alb, .cd, .gift, .wish, .foot {
  background-image: var(--noise);
  background-size: 160px 160px;
}
/* Hướng sáng: một vệt rất nhạt từ trái trên, nhại đúng ánh sáng rèm
   cửa của tấm phông trong hero. Chỉ trên nền giấy — trên nền mực và
   nền rêu thì vệt trắng đọc ra như lỗi đổ màu. */
body {
  background-image: var(--noise),
    radial-gradient(128% 88% at 10% -6%, #FFFFFF 0%, rgba(255,255,255,0) 58%);
  background-size: 160px 160px, cover;
  background-repeat: repeat, no-repeat;
  background-attachment: scroll, fixed;
}

img, svg { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
button, input, textarea, select { font: inherit; color: inherit; }
h1, h2, h3, h4, p, figure, blockquote, ul { margin: 0; }
ul { padding: 0; list-style: none; }

:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* Playfair mặc định dùng chữ số kiểu cổ (old-style, có chân thò lên
   thụt xuống). Đẹp trong văn bản chạy, nhưng ngày tháng và đồng hồ
   đếm ngược thì phải thẳng hàng -> ép sang lining. */
.lin { font-variant-numeric: lining-nums; }

/* ---------- KHUNG TRANG ---------- */

.wrap   { width: var(--wrap); margin-inline: auto; }
.sec    { padding-block: var(--sec); position: relative; }
.grid12 { display: grid; grid-template-columns: repeat(12, 1fr); column-gap: var(--gut); }

/* ---------- HIỆN DẦN KHI CUỘN ----------
   Trang có ĐÚNG HAI động từ, và hai động từ đó nói hai chất liệu khác
   nhau — chứ không phải một hiệu ứng dùng chung cho ba mươi khối:

     .rv          CHỮ được ĐẶT XUỐNG   -> dâng lên + hiện
     .rv--shot    ẢNH đang HIỆN HÌNH   -> lộ dần từ trên xuống, đứng yên

   Chữ đi lên, ảnh đi xuống. Hai chiều ngược nhau nên khi một khối có
   cả hai, mắt đọc ra hai vật thể chứ không phải một mảng trượt.

   .rv là móc DUY NHẤT motion.js quan sát; ba lớp --shot/--line/--car
   chỉ đổi động từ. Muốn thêm kiểu hiện mới thì thêm modifier, đừng
   thêm móc mới.

   --i = số thứ tự trong nhóm lặp (render.js gán). Trễ dần theo --stag
   để nhóm đọc ra MỘT cử chỉ có sức nặng, không phải bốn ô nhảy cùng lúc. */

.rv {
  opacity: 0;
  transform: translateY(26px);
  /* MỘT đường cong cho CẢ HAI thuộc tính. Bản trước để opacity chạy
     `ease` còn transform chạy expo-out: transform xong quãng đường của
     nó từ rất sớm, opacity thì mới đi được một phần ba -> chữ đáp
     xuống đúng chỗ rồi mới lờ mờ hiện lên. Đó là chỗ "không mượt",
     không phải ở thời lượng. */
  transition:
    opacity   var(--dur) var(--ease),
    transform var(--dur) var(--ease);
  transition-delay: calc(var(--i, 0) * var(--stag));
  /* Nhấc sẵn lên lớp riêng để khung hình ĐẦU TIÊN của chuyển cảnh
     không phải dừng lại vẽ lớp. Tự huỷ ở `.in` bên dưới — để nguyên
     will-change trên hàng chục phần tử là tự bắn vào chân mình. */
  will-change: opacity, transform;
}
.rv.in { opacity: 1; transform: none; will-change: auto; }

/* Ảnh: KHÔNG dịch chuyển, chỉ mở dần khung nhìn. Hai số âm ở phải và
   đáy là để chừa chỗ cho đường viền lệch của .shot (translate 10–14px)
   — cắt đúng bằng 0 thì viền đó bị xén mất vĩnh viễn.

   Mép phải giữ NGUYÊN -24px ở cả hai đầu, chỉ mép đáy chạy. Bản trước
   để phải chạy 0 -> -24px nên trong lúc lộ xuống ảnh còn nở ngang một
   nhịp: hai hướng chuyển động trong một cử chỉ, mắt đọc ra rung. */
.rv--shot {
  opacity: 1;
  transform: none;
  clip-path: inset(0 -24px 100% 0);
  transition: clip-path var(--dur-slow) var(--ease);
  transition-delay: calc(var(--i, 0) * var(--stag));
}
.rv--shot.in { clip-path: inset(0 -24px -24px 0); }

/* Vạch chuyển chương: mở ra từ giữa như kéo màn. Chỉ dùng MỘT lần
   trên cả trang, ở chỗ nền đổi từ giấy sang mực. */
.rv--line { opacity: 1; transform: none; }

/* Phải liệt kê cả biến thể `.in`: `.rv--shot.in` ở trên có độ đặc
   hiệu (0,2,0), viết trơ `.rv--shot` ở đây chỉ được (0,1,0) nên
   không đè nổi. Hiện tại clip kết thúc là inset ÂM (không cắt gì)
   nên vô hại, nhưng ai đó đổi trạng thái kết thúc là chế độ giảm
   chuyển động hỏng lặng lẽ. */
@media (prefers-reduced-motion: reduce) {
  .rv, .rv--shot, .rv.in, .rv--shot.in {
    opacity: 1; transform: none; clip-path: none; transition: none;
  }
}

/* Chỉ đọc bằng trình đọc màn hình */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip {
  position: absolute; left: -9999px; z-index: 300;
  background: var(--ink); color: var(--paper);
  padding: .7rem 1.2rem;
}
.skip:focus { left: 1rem; top: 1rem; }
