/* utop-animations.css — runtime cho rich-text animation preset (ADO #121331).
   Editor FE.CkEditor (Jodit) chỉ chèn <span class="anim-{slug}">…</span> (chỉ class, không style/JS).
   Portal (repo này) cung cấp CSS keyframes + trigger theo bàn giao:
   FE.CkEditor/docs/handoff/animation-runtime-contract.md
   Trigger 1 lần qua IntersectionObserver (utop-animations.js) khi phần tử vào 20% viewport.

   Gate `.anim-ready` (JS set trên <html> ngay khi chạy): trạng thái ẩn (opacity:0) CHỈ áp
   khi JS đã sẵn sàng sẽ trigger. JS lỗi/tắt → không có .anim-ready → text hiện bình thường,
   KHÔNG mất nội dung. Prefix keyframe `utop*` để không đụng @keyframes toàn cục (AEM/coreclient). */

/* Trạng thái chờ — chỉ khi JS đã gate */
html.anim-ready :is(
  .anim-fade-in, .anim-slide-in-left, .anim-slide-in-right,
  .anim-zoom-in, .anim-text-reveal, .anim-typewriter
) {
  display: inline-block;      /* cần cho transform (slide/zoom) có hiệu lực */
  opacity: 0;
  will-change: transform, opacity;
}

/* Chạy khi observer add .is-in — `forwards` giữ trạng thái cuối (chạy 1 lần, không replay) */
.anim-fade-in.is-in        { animation: utopFadeIn .8s ease-out forwards; }
.anim-slide-in-left.is-in  { animation: utopSlideInLeft .8s ease-out forwards; }
.anim-slide-in-right.is-in { animation: utopSlideInRight .8s ease-out forwards; }
.anim-zoom-in.is-in        { animation: utopZoomIn .6s ease-out forwards; }
.anim-text-reveal.is-in    { animation: utopTextReveal .9s cubic-bezier(.4, 0, .2, 1) forwards; }

/* Typewriter: duration động theo số ký tự (40ms/ký tự) + bề rộng text đo bằng JS.
   --tw-steps / --tw-duration / --tw-width set inline bởi utop-animations.js; có fallback. */
.anim-typewriter.is-in {
  white-space: nowrap;
  overflow: hidden;
  vertical-align: bottom;
  animation: utopTypewriter var(--tw-duration, 2s) steps(var(--tw-steps, 24)) forwards;
}

@keyframes utopFadeIn       { to { opacity: 1; } }
@keyframes utopSlideInLeft  { from { transform: translateX(-30px); } to { opacity: 1; transform: none; } }
@keyframes utopSlideInRight { from { transform: translateX(30px); }  to { opacity: 1; transform: none; } }
@keyframes utopZoomIn       { from { transform: scale(.8); }         to { opacity: 1; transform: none; } }
@keyframes utopTextReveal   { from { clip-path: inset(0 100% 0 0); } to { opacity: 1; clip-path: inset(0 0 0 0); } }
@keyframes utopTypewriter   { from { width: 0; opacity: 1; }         to { width: var(--tw-width, 100%); opacity: 1; } }

/* Tôn trọng prefers-reduced-motion: bỏ hiệu ứng, hiện thẳng (kể cả trước khi trigger) */
@media (prefers-reduced-motion: reduce) {
  html.anim-ready :is(
    .anim-fade-in, .anim-slide-in-left, .anim-slide-in-right,
    .anim-zoom-in, .anim-text-reveal, .anim-typewriter
  ) {
    opacity: 1 !important;
    animation: none !important;
    width: auto !important;
    clip-path: none !important;
    transform: none !important;
    white-space: normal !important;
  }
}
