/* Chuyển động DOM — Direction v2.
   Vật thể thì analog: bản vẽ máy không bao giờ glitch. Chuyển động sống ở
   bóng (engine/glitch.js — giật aperiodic 2–6s), ở nhịp vào trang của 00,
   và ở các cú dấu câu được kịch bản chỉ định. Cường độ giảm dần từ trên
   xuống — không khối nào ồn hơn khối trước nó. */

/* ===== Nhịp quan trọng nhất của cả trang — panel 00 =====
   t=200–600ms  bản vẽ máy wipe từ trên xuống, như tờ giấy đang nạp vào máy
   t=640ms      BÓNG TỚI MUỘN 40ms, vọt quá 6px rồi mới lùi về đúng chỗ      */
.js-motion #poster .machine {
  clip-path: inset(0 0 100% 0);
  animation: may-wipe 0.4s linear 0.2s both;
}
@keyframes may-wipe {
  to { clip-path: inset(0 0 0 0); }
}

.js-motion #poster .shadow-layer {
  opacity: 0;
  animation: bong-toi-muon 0.3s cubic-bezier(0.2, 0.9, 0.3, 1) 0.64s both;
}
@keyframes bong-toi-muon {
  0% {
    opacity: 0;
    transform: translate(calc(var(--sx, 0px) + 26px), calc(var(--sy, 0px) + 22px));
  }
  55% {
    /* vọt quá 6px — cái bóng dừng không chuẩn. Đừng làm mượt nó. */
    opacity: 0.9;
    transform: translate(calc(var(--sx, 0px) - 6px), calc(var(--sy, 0px) - 6px));
  }
  100% {
    opacity: 0.9;
    transform: translate(var(--sx, 0px), var(--sy, 0px));
  }
}

/* t=1100ms — nút và QR hiện cuối */
.js-motion #poster .cta-block {
  opacity: 0;
  animation: hien-cuoi 0.45s ease 1.1s both;
}
@keyframes hien-cuoi {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

/* t=900ms — tiêu đề glitch cắt lát đúng MỘT lần, ≤200ms (JS gắn lớp) */
.glitching {
  animation: misprint 0.2s steps(2, jump-none) 1;
}
@keyframes misprint {
  0% {
    clip-path: inset(0 0 66% 0);
    transform: translateX(5px);
  }
  33% {
    clip-path: inset(33% 0 33% 0);
    transform: translateX(-6px);
  }
  66% {
    clip-path: inset(66% 0 0 0);
    transform: translateX(4px);
  }
  100% {
    clip-path: inset(0 0 0 0);
    transform: none;
  }
}

/* ===== 01a — bốn con số ĐÓNG DẤU xuống, lần lượt, không fade =====
   thu nhỏ cứng trong 60ms + gợn giấy 2px quanh chỗ đóng (JS gắn .is-stamped
   so le 220ms; trước đó khung chờ ở trạng thái nhấc lên) */
.js-motion .strike {
  opacity: 0;
  transform: rotate(var(--tilt, 0deg)) scale(1.14);
}
.js-motion .strike.is-stamped {
  opacity: 1;
  transform: rotate(var(--tilt, 0deg)) scale(1);
  transition: transform 60ms steps(2, jump-end), opacity 30ms steps(1, jump-end);
}
.js-motion .strike.is-stamped::after {
  /* gợn giấy quanh chỗ vừa đóng */
  content: "";
  position: absolute;
  inset: -2px;
  border: 1px solid var(--rule);
  animation: paper-ripple 0.35s ease-out 1 both;
  pointer-events: none;
}
@keyframes paper-ripple {
  from { opacity: 0.9; transform: scale(1); }
  to { opacity: 0; transform: scale(1.04); }
}

/* (cú glitch trùm cả khối lúc bấm chọn tờ đã BỎ 26/08 — giật cả trang) */
/* bóng của tờ bị bỏ lại DỪNG chuyển động thay vì tan — wobble chỉ chạy khi
   chưa chốt; .is-passed/.is-chosen gỡ animation */
.js-motion .sheet {
  animation: sheet-wobble 5.2s ease-in-out infinite;
}
.js-motion .sheet[data-sheet="b"] { animation-duration: 6.4s; animation-delay: -2s; }
.js-motion .sheet.is-chosen,
.js-motion .sheet.is-passed { animation: none; }
@keyframes sheet-wobble {
  0%, 100% { box-shadow: 5px 6px 0 var(--bong); }
  50% { box-shadow: 7px 4px 0 var(--bong); }
}

/* ===== 04b — câu gõ dần lên tờ giấy; caret của máy */
.typed-line::after {
  content: "";
  display: inline-block;
  width: 0.55em;
  height: 1.05em;
  vertical-align: text-bottom;
  background: var(--ink);
  margin-left: 1px;
  animation: caret 1.05s steps(1, jump-none) infinite;
}
.typed-line.is-done::after { display: none; }
@keyframes caret {
  50% { opacity: 0; }
}

/* ===== prefers-reduced-motion: trang kể được trọn câu chuyện khi không có
   một pixel nào động — bóng khớp sẵn, dấu đã đóng, câu đã gõ xong ===== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .glitching { animation: none; }
  .marquee-track { animation: none; }
  .sheet { animation: none; }
  .typed-line::after { display: none; }
  body { transition: none; }
}
