/* ZenPn — chuyển động của trang / và nút đổi theme. Xếp sau ui.css.
 * Có cả các trang đăng nhập / đăng ký / quên mật khẩu.
 * Khởi động, hover, nhấn chạy bằng CSS thuần. Trạng thái của phần hiện dần,
 * FAQ, menu mobile và nút lên đầu do motion.js gắn qua thuộc tính data-*.
 * Mọi keyframes dùng fill "backwards" để khi chạy xong không khoá transform,
 * hover vẫn nhấc được phần tử. */

:root {
  --zm-fast: 150ms;
  --zm-base: 250ms;
  --zm-slow: 350ms;
  --zm-ease: cubic-bezier(.2, .8, .2, 1);
  --zm-drawer: 280ms cubic-bezier(.32, .72, 0, 1);
}

@keyframes zm-rise { from { opacity: 0; transform: translateY(12px); } }
@keyframes zm-drop { from { opacity: 0; transform: translateY(-8px); } }
@keyframes zm-zoom { from { opacity: 0; transform: scale(.98); } }
@keyframes zm-reveal { from { opacity: 0; transform: translateY(16px); } }
@keyframes zm-fade { from { opacity: 0; transform: translateY(-4px); } }

/* ── Khởi động: motion.js gắn data-intro="wait" (ẩn) lúc dựng trang, rồi "run"
 * khi font và trang đã vẽ xong, để animation không tranh CPU với việc dựng trang.
 * Các phần nối nhau cách 60ms. ── */
.zc-landing-nav {
  position: relative;
  z-index: 20;
}
.zc-landing[data-intro="wait"] :is(.zc-landing-nav, .zc-landing-copy > *, .zc-product-preview) { opacity: 0; }
.zc-landing[data-intro="run"] .zc-landing-nav { animation: zm-drop var(--zm-slow) var(--zm-ease) backwards; }
.zc-landing[data-intro="run"] .zc-landing-copy > * { animation: zm-rise var(--zm-slow) var(--zm-ease) backwards; }
.zc-landing[data-intro="run"] .zc-landing-copy > :nth-child(1) { animation-delay: 60ms; }
.zc-landing[data-intro="run"] .zc-landing-copy > :nth-child(2) { animation-delay: 120ms; }
.zc-landing[data-intro="run"] .zc-landing-copy > :nth-child(3) { animation-delay: 180ms; }
.zc-landing[data-intro="run"] .zc-landing-copy > :nth-child(4) { animation-delay: 240ms; }
.zc-landing[data-intro="run"] .zc-landing-copy > :nth-child(5) { animation-delay: 300ms; }
.zc-landing[data-intro="run"] .zc-product-preview { animation: zm-zoom 500ms var(--zm-ease) 360ms backwards; }

/* ── Hiện dần khi cuộn: motion.js xếp hàng, đặt animation-delay cho từng khối ── */
[data-reveal]:not([data-shown]) { opacity: 0; }
[data-reveal][data-shown] { animation: zm-reveal var(--zm-slow) var(--zm-ease) backwards; }

/* ── Hover ── */
.zc-landing-primary,
.zc-landing-secondary,
.zc-landing-signup,
.zc-landing-cta button,
.zc-landing-solution-grid > article,
.zc-landing-catalog,
.zc-theme-toggle {
  transition: transform var(--zm-fast) var(--zm-ease), background-color var(--zm-base) var(--zm-ease),
    border-color var(--zm-base) var(--zm-ease), box-shadow var(--zm-base) var(--zm-ease),
    color var(--zm-base) var(--zm-ease);
}
.zc-landing .si-arrow-right {
  display: inline-block;
  transition: transform var(--zm-base) var(--zm-ease);
}
.zc-landing-nav nav button,
.zc-landing-login {
  position: relative;
  transition: color var(--zm-base) var(--zm-ease);
}
.zc-landing-nav nav button::after {
  content: "";
  position: absolute;
  left: 11px;
  right: 11px;
  bottom: 4px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--zm-base) var(--zm-ease);
}
@media (hover: hover) {
  .zc-landing-primary:hover,
  .zc-landing-signup:hover,
  .zc-landing-cta button:hover {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--zc-primary) 86%, #fff);
    background: color-mix(in srgb, var(--zc-primary) 86%, #fff);
    box-shadow: 0 6px 18px rgba(22, 93, 255, .28);
  }
  .zc-landing-secondary:hover {
    transform: translateY(-1px);
    border-color: var(--zc-input-border);
    background: var(--zc-raised);
  }
  .zc-landing-primary:hover .si-arrow-right,
  .zc-landing-cta button:hover .si-arrow-right { transform: translateX(3px); }
  .zc-landing-nav nav button:hover::after { transform: scaleX(1); }
  .zc-landing-solution-grid > article:hover,
  .zc-landing-catalog:hover {
    transform: translateY(-2px);
    border-color: var(--zc-input-border);
  }
}

/* ── Nhấn ── */
.zc-landing button:active,
.zc-theme-toggle:active {
  transform: scale(.97);
  transition-duration: 100ms;
}

/* ── Nút theme: dark hiện mặt trời, light hiện trăng khuyết ── */
.zc-theme-icon {
  display: block;
  overflow: visible;
  transition: transform var(--zm-slow) var(--zm-ease);
}
.zc-theme-core,
.zc-theme-rays,
.zc-theme-bite {
  transform-origin: 12px 12px;
  transition: transform var(--zm-slow) var(--zm-ease), opacity var(--zm-base) var(--zm-ease);
}
.zc-theme-core { transform: scale(.62); }
.zc-theme-bite { transform: translate(10px, 10px); }
:root[data-zenpn-mode="light"] .zc-theme-icon { transform: rotate(-90deg); }
:root[data-zenpn-mode="light"] .zc-theme-core,
:root[data-zenpn-mode="light"] .zc-theme-bite { transform: none; }
:root[data-zenpn-mode="light"] .zc-theme-rays { opacity: 0; transform: rotate(-45deg) scale(.5); }

/* ── Thanh tải trên đầu trang (motion.js progress), kiểu YouTube. ── */
.zc-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2147483001;
  height: 3px;
  pointer-events: none;
  background: var(--zc-primary, #165dff);
  box-shadow: 0 0 8px rgba(22, 93, 255, .6);
  transform: scaleX(0);
  transform-origin: left;
  opacity: 0;
}
.zc-progress[data-active] {
  opacity: 1;
  transition: transform 400ms var(--zm-ease), opacity 150ms linear;
}
.zc-progress[data-active][data-done] {
  opacity: 0;
  transition: transform 200ms ease-out, opacity 300ms ease 200ms;
}

/* ── Tiêu đề header gõ chữ (motion.js typeTitle): con trỏ nháy chạy theo ký tự. ── */
@keyframes zm-caret { 50% { opacity: 0; } }
.v2board-container-title { position: relative; }
.v2board-container-title[data-typing]::after {
  content: "";
  position: absolute;
  top: 18%;
  bottom: 18%;
  left: 0;
  width: 2px;
  background: currentColor;
  animation: zm-caret .5s step-end infinite;
}

/* ── Dòng chào dashboard (motion.js greeter): chữ gốc thu về cỡ 0, câu đang gõ nằm
 * trong span riêng, cỡ chữ theo các mốc của tiêu đề theme. Màn hẹp thì xuống dòng trong
 * khung; motion.js giữ sẵn chiều cao câu cao nhất nên gõ/xóa không làm nhảy bố cục. ── */
.zc-welcome-user h1[data-greeter] { font-size: 0 !important; }
.zc-welcome-user > div:not(.zc-avatar) { min-width: 0; }
.zc-greeter {
  display: block;
  font-size: 28px;
  white-space: normal;
  overflow-wrap: anywhere;
}
@media (min-width: 1800px) { .zc-greeter { font-size: 32px; } }
@media (max-width: 991px) { .zc-greeter { font-size: 23px; } }
@media (max-width: 599px) { .zc-greeter { font-size: 21px; } }
@media (max-width: 374px) { .zc-greeter { font-size: 19px; } }
.zc-greeter::after {
  content: "";
  display: inline-block;
  width: 3px;
  height: .85em;
  margin-left: 4px;
  vertical-align: -.06em;
  background: currentColor;
  animation: zm-caret 1s step-end infinite;
}

/* ── Nút đổi ngôn ngữ trên header: cùng kiểu nút theme (zc-theme-toggle). ── */
.zc-lang-toggle { margin: 0 8px; }
.zc-lang-icon {
  display: block;
  transition: transform var(--zm-slow) var(--zm-ease);
}
@media (hover: hover) {
  .zc-lang-toggle:hover .zc-lang-icon { transform: rotate(25deg); }
}
.zc-lang-toggle.ant-dropdown-open {
  background: var(--zc-hover);
  color: var(--zc-blue);
}

/* ── Đổi theme: crossfade toàn trang của View Transitions (motion.js). Trong lúc
 * đó tắt transition để các nút không tự đổi màu trong ảnh mới: ảnh đứng yên thì
 * card đồ hoạ chỉ việc trộn hai ảnh. Icon theme vẫn biến hình. ── */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 250ms;
  animation-timing-function: ease-out;
}
[data-theme-switching] *:not(.zc-theme-icon, .zc-theme-icon *) {
  transition: none !important;
}

/* ── FAQ ── */
.zc-landing-faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  list-style: none;
  transition: color var(--zm-base) var(--zm-ease);
}
.zc-landing-faq summary::-webkit-details-marker { display: none; }
.zc-landing-faq summary::after {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  margin-right: 4px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--zm-base) var(--zm-ease);
}
.zc-landing-faq details[open]:not([data-closing]) summary::after { transform: translateY(2px) rotate(225deg); }
.zc-landing-faq details[data-animating] { overflow: hidden; }
.zc-landing-faq details[open] p { animation: zm-fade var(--zm-base) var(--zm-ease) backwards; }
@media (hover: hover) {
  .zc-landing-faq summary:hover { color: var(--zc-blue); }
}

/* ── Menu mobile và nút lên đầu: chỉ có ở màn hình nhỏ ── */
.zc-landing-menu-toggle,
.zc-landing-menu,
.zc-to-top { display: none; }

@media (max-width: 600px) {
  .zc-landing-menu-toggle {
    display: inline-grid;
    place-content: center;
    gap: 4px;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px solid var(--zc-line);
    border-radius: 9px;
    background: var(--zc-soft);
    color: var(--zc-text);
    cursor: pointer;
  }
  .zc-landing-menu-toggle span {
    display: block;
    width: 16px;
    height: 1.5px;
    border-radius: 1px;
    background: currentColor;
    transition: transform var(--zm-base) var(--zm-ease), opacity var(--zm-fast) var(--zm-ease);
  }
  .zc-landing-menu-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
  .zc-landing-menu-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
  .zc-landing-menu-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

  .zc-landing-menu {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    right: 0;
    display: grid;
    gap: 2px;
    padding: 8px;
    border: 1px solid var(--zc-line);
    border-radius: 12px;
    background: var(--zc-card);
    box-shadow: 0 18px 40px rgba(0, 0, 0, .18);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition: opacity var(--zm-base) var(--zm-ease), transform var(--zm-base) var(--zm-ease),
      visibility 0s linear var(--zm-base);
  }
  .zc-landing-menu[data-open] {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 0s;
  }
  .zc-landing-menu button {
    padding: 12px;
    border: 0;
    border-radius: 8px;
    background: none;
    color: var(--zc-heading);
    font-size: 14px;
    text-align: left;
    cursor: pointer;
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity var(--zm-base) var(--zm-ease), transform var(--zm-base) var(--zm-ease),
      background-color var(--zm-fast) var(--zm-ease);
  }
  .zc-landing-menu[data-open] button { opacity: 1; transform: none; }
  .zc-landing-menu[data-open] button:nth-child(2) { transition-delay: 40ms; }
  .zc-landing-menu[data-open] button:nth-child(3) { transition-delay: 80ms; }
  .zc-landing-menu button:active { background: var(--zc-hover); }

  .zc-to-top {
    position: fixed;
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom));
    z-index: 30;
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 1px solid var(--zc-line);
    border-radius: 12px;
    background: var(--zc-card);
    color: var(--zc-heading);
    box-shadow: 0 10px 24px rgba(0, 0, 0, .2);
    cursor: pointer;
    opacity: 0;
    visibility: hidden;
    transform: translateY(12px);
    transition: opacity var(--zm-base) var(--zm-ease), transform var(--zm-base) var(--zm-ease),
      visibility 0s linear var(--zm-base);
  }
  .zc-to-top[data-visible] {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 0s;
  }
}

/* ── Trang đăng nhập / đăng ký / quên mật khẩu. motion.js gắn data-intro lên
 * .zc-auth-page (đăng nhập) hoặc .zc-auth-secondary (đăng ký, quên mật khẩu) và
 * data-step + animation-delay cho từng phần của form. ── */
@keyframes zm-appear { from { opacity: 0; transform: scale(.96); } }

:is(.zc-auth-page, .zc-auth-secondary)[data-intro="wait"] :is(.zc-auth-topbar, [data-step]) { opacity: 0; }
:is(.zc-auth-page, .zc-auth-secondary)[data-intro="run"] .zc-auth-topbar { animation: zm-drop var(--zm-slow) var(--zm-ease) backwards; }
:is(.zc-auth-page, .zc-auth-secondary)[data-intro="run"] [data-step] { animation: zm-rise var(--zm-slow) var(--zm-ease) backwards; }
:is(.zc-auth-page, .zc-auth-secondary)[data-intro="swap"] [data-step] { animation: zm-rise var(--zm-slow) var(--zm-ease) backwards; }

.zc-auth-submit,
.v2board-auth-box .btn-primary {
  transition: transform var(--zm-fast) var(--zm-ease), background-color var(--zm-base) var(--zm-ease),
    border-color var(--zm-base) var(--zm-ease), box-shadow var(--zm-base) var(--zm-ease);
}
.zc-auth-submit > *,
.v2board-auth-box .btn-primary > * { animation: zm-appear var(--zm-fast) ease-out backwards; }
.zc-input,
.zc-auth-field-control {
  transition: border-color var(--zm-fast) var(--zm-ease), box-shadow var(--zm-fast) var(--zm-ease);
}
.zc-input > i,
.zc-auth-field-control > i,
.zc-password-toggle { transition: color var(--zm-fast) var(--zm-ease); }
.zc-input:focus-within > i,
.zc-auth-field-control:focus-within > i { color: var(--zc-blue); }
/* Link: đường kẻ dưới chạy từ trái sang phải khi hover (scaleX, chạy trên card đồ hoạ). */
.zc-auth-link,
.zc-auth-signup-link,
.v2board-auth-box .bg-gray-lighter a {
  position: relative;
  display: inline-block;
  text-decoration: none !important;
}
.zc-auth-link::after,
.zc-auth-signup-link::after,
.v2board-auth-box .bg-gray-lighter a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--zm-base) var(--zm-ease);
}
.zc-auth-link:focus-visible::after,
.zc-auth-signup-link:focus-visible::after,
.v2board-auth-box .bg-gray-lighter a:focus-visible::after { transform: scaleX(1); }
@media (hover: hover) {
  .zc-auth-submit:hover:not(:disabled),
  .v2board-auth-box .btn-primary:hover:not(:disabled) {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--zc-primary) 86%, #fff);
    background: color-mix(in srgb, var(--zc-primary) 86%, #fff);
    box-shadow: 0 6px 18px rgba(22, 93, 255, .28);
  }
  .zc-auth-link:hover::after,
  .zc-auth-signup-link:hover::after,
  .v2board-auth-box .bg-gray-lighter a:hover::after { transform: scaleX(1); }
  .zc-password-toggle:hover { color: var(--zc-blue); }
}
/* Nhấn: thuộc tính scale riêng nên không đè transform sẵn có của nút. */
:is(.zc-auth-page, .v2board-auth-box) button:active:not(:disabled) { scale: .97; }

/* Dòng lỗi hiện ngay khi rời ô (onBlur) hoặc khi gửi, trượt xuống nhẹ. */
.zc-field-error { animation: zm-fade var(--zm-base) var(--zm-ease) backwards; }

/* Nút mắt: nét gạch vẽ dần khi mật khẩu đang hiện. */
.zc-eye { display: block; }
.zc-eye-slash {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset var(--zm-base) var(--zm-ease);
}
.zc-password-toggle[aria-pressed="true"] .zc-eye-slash { stroke-dashoffset: 0; }

/* ── Vòng focus bàn phím: CSS gốc tắt outline ở nhiều nút/link nên Tab tới mà
 * không thấy gì. Một vòng chung, chỉ hiện khi dùng bàn phím (:focus-visible);
 * ô nhập đã có vòng sáng riêng trên khung ô. ── */
:is(.zc-landing, .zc-auth-page, .v2board-auth-box) :is(a, button, summary, [role="button"]):focus-visible {
  outline: 3px solid var(--zc-blue) !important;
  outline-offset: 2px;
}
/* Danh sách ngôn ngữ nhận focus sau Enter; phím mũi tên đổi mục đang chọn. */
.ant-dropdown-menu:focus { outline: none; }
.ant-dropdown-menu:focus .ant-dropdown-menu-item-active {
  background: var(--zc-hover);
  color: var(--zc-heading);
}

/* ── Trang sau đăng nhập: layout có sidebar (#page-container.sidebar-o). Khung
 * (sidebar, header) giữ nguyên khi đổi route, nội dung trang dựng lại nên mỗi khối
 * tự chạy hiệu ứng lúc được chèn vào, dữ liệu về muộn cũng vậy. --zm-row là thứ tự
 * khối cấp 1, --zm-col là thứ tự trong lưới: nối nhau cách 70ms / 50ms. Khối chứa
 * lưới không tự chạy mà để các ô bên trong chạy. Cái gì mở ra có hiệu ứng thì đóng
 * lại cũng có. ── */
@keyframes zm-grow { from { transform: scaleX(0); } }
@keyframes zm-slide { from { opacity: 0; transform: translateX(-8px); } }

.sidebar-o #main-container > .content > * { --zm-row: 0; }
.sidebar-o #main-container > .content > :nth-child(2) { --zm-row: 1; }
.sidebar-o #main-container > .content > :nth-child(3) { --zm-row: 2; }
.sidebar-o #main-container > .content > :nth-child(4) { --zm-row: 3; }
.sidebar-o #main-container > .content > :nth-child(5) { --zm-row: 4; }
.sidebar-o #main-container > .content > :nth-child(6) { --zm-row: 5; }
.sidebar-o #main-container > .content > :nth-child(7) { --zm-row: 6; }
.sidebar-o :is(.zc-stats, .zc-middle, .zc-bottom, .zc-page-metrics, .zc-page-body, .zc-offer-grid, .zdp-content > div, .zdp-summary, .zdp-device-grid) > * { --zm-col: 0; }
.sidebar-o :is(.zc-stats, .zc-middle, .zc-bottom, .zc-page-metrics, .zc-page-body, .zc-offer-grid, .zdp-content > div, .zdp-summary, .zdp-device-grid) > :nth-child(2) { --zm-col: 1; }
.sidebar-o :is(.zc-stats, .zc-middle, .zc-bottom, .zc-page-metrics, .zc-page-body, .zc-offer-grid, .zdp-content > div, .zdp-summary, .zdp-device-grid) > :nth-child(3) { --zm-col: 2; }
.sidebar-o :is(.zc-stats, .zc-middle, .zc-bottom, .zc-page-metrics, .zc-page-body, .zc-offer-grid, .zdp-content > div, .zdp-summary, .zdp-device-grid) > :nth-child(4) { --zm-col: 3; }
.sidebar-o :is(.zc-stats, .zc-middle, .zc-bottom, .zc-page-metrics, .zc-page-body, .zc-offer-grid, .zdp-content > div, .zdp-summary, .zdp-device-grid) > :nth-child(5) { --zm-col: 4; }
.sidebar-o :is(.zc-stats, .zc-middle, .zc-bottom, .zc-page-metrics, .zc-page-body, .zc-offer-grid, .zdp-content > div, .zdp-summary, .zdp-device-grid) > :nth-child(6) { --zm-col: 5; }
.sidebar-o :is(.zc-stats, .zc-middle, .zc-bottom, .zc-page-metrics, .zc-page-body, .zc-offer-grid, .zdp-content > div, .zdp-summary, .zdp-device-grid) > :nth-child(7) { --zm-col: 6; }
.sidebar-o #main-container > .content > :not(.zc-stats, .zc-middle, .zc-bottom, .zc-page-metrics, .zc-page-body, :has(> .zdp-root)) {
  animation: zm-rise var(--zm-slow) var(--zm-ease) backwards;
  animation-delay: calc(var(--zm-row, 0) * 70ms);
}
.sidebar-o :is(.zc-stats, .zc-middle, .zc-bottom, .zc-page-metrics, .zc-page-body, .zc-offer-grid, .zdp-content > div, .zdp-summary, .zdp-device-grid) > :not(.zc-offer-grid) {
  animation: zm-rise var(--zm-slow) var(--zm-ease) backwards;
  animation-delay: calc(var(--zm-row, 0) * 70ms + var(--zm-col, 0) * 50ms);
}
/* Portal thiết bị đã vào xong (portal gắn data-zdp-settled): làm mới, mở/đóng hộp xác nhận
 * không chạy lại hiệu ứng vào. */
#zenpn-device-portal[data-zdp-settled] :is(.zdp-content > div, .zc-page-metrics, .zdp-summary, .zdp-device-grid) > * { animation: none; }
.sidebar-o #main-container :is(tbody, .zc-list) > * {
  animation: zm-fade var(--zm-base) var(--zm-ease) backwards;
}
.sidebar-o #main-container :is(tbody, .zc-list) > :nth-child(2) { animation-delay: 35ms; }
.sidebar-o #main-container :is(tbody, .zc-list) > :nth-child(3) { animation-delay: 70ms; }
.sidebar-o #main-container :is(tbody, .zc-list) > :nth-child(4) { animation-delay: 105ms; }
.sidebar-o #main-container :is(tbody, .zc-list) > :nth-child(5) { animation-delay: 140ms; }
.sidebar-o #main-container :is(tbody, .zc-list) > :nth-child(6) { animation-delay: 175ms; }
.sidebar-o #main-container :is(tbody, .zc-list) > :nth-child(7) { animation-delay: 210ms; }
.sidebar-o #main-container :is(tbody, .zc-list) > :nth-child(8) { animation-delay: 245ms; }
.sidebar-o :is(.zc-traffic-fill, .progress-bar) {
  transform-origin: left;
  transition: width 700ms var(--zm-ease);
  animation: zm-grow 700ms var(--zm-ease) 250ms backwards;
}

/* Ô số đang chờ backend (motion.js gắn data-waiting khi chữ là "—"): ẩn dấu gạch,
 * 3 chấm nhảy lên xuống lần lượt. Có số thì motion.js đếm từ 0 lên. */
@keyframes zm-dots {
  0%, 80%, 100% { background-position: 0 100%, 10px 100%, 20px 100%; }
  20% { background-position: 0 0, 10px 100%, 20px 100%; }
  40% { background-position: 0 100%, 10px 0, 20px 100%; }
  60% { background-position: 0 100%, 10px 100%, 20px 0; }
}
[data-waiting] {
  position: relative;
  display: inline-block;
  min-width: 27px;
  color: transparent !important;
}
[data-waiting]::after {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 27px;
  height: 14px;
  margin-top: -7px;
  background: radial-gradient(circle closest-side, var(--zc-muted) 90%, transparent) 0 100% / 7px 7px no-repeat,
    radial-gradient(circle closest-side, var(--zc-muted) 90%, transparent) 10px 100% / 7px 7px no-repeat,
    radial-gradient(circle closest-side, var(--zc-muted) 90%, transparent) 20px 100% / 7px 7px no-repeat;
  animation: zm-dots 1s ease-in-out infinite;
}
/* Nút đang chờ backend (Làm mới, Tải lại chính sách): giữ bề rộng, chữ ẩn, 3 chấm nhảy ở giữa. */
.zdp-button[data-loading] {
  position: relative;
  color: transparent !important;
}
.zdp-button[data-loading]::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 27px;
  height: 14px;
  margin: -7px 0 0 -13.5px;
  background: radial-gradient(circle closest-side, var(--zdp-muted) 90%, transparent) 0 100% / 7px 7px no-repeat,
    radial-gradient(circle closest-side, var(--zdp-muted) 90%, transparent) 10px 100% / 7px 7px no-repeat,
    radial-gradient(circle closest-side, var(--zdp-muted) 90%, transparent) 20px 100% / 7px 7px no-repeat;
  animation: zm-dots 1s ease-in-out infinite;
}

/* Khung ứng dụng: hiện một lần khi vào ứng dụng. Mỗi trang V2Board dựng lại layout
 * nên sidebar/header bị gắn lại ở mọi lần đổi route; motion.js gắn data-app-ready lên
 * <html> sau khi khởi động để hiệu ứng không chạy lại. */
:root:not([data-app-ready]) .sidebar-o #sidebar .content-side { animation: zm-slide var(--zm-slow) var(--zm-ease) backwards; }
:root:not([data-app-ready]) .sidebar-o #page-header .content-header { animation: zm-drop var(--zm-slow) var(--zm-ease) backwards; }

/* Menu tài khoản: Bootstrap bật/tắt display nên đóng là mất ngay. Giữ display, đổi
 * opacity/transform/visibility để mở và đóng đều chạy. */
.sidebar-o #page-header .dropdown-menu {
  display: block;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(.98);
  transform-origin: top right;
  transition: opacity var(--zm-fast) var(--zm-ease), transform var(--zm-fast) var(--zm-ease),
    visibility 0s linear var(--zm-fast);
}
.sidebar-o #page-header .dropdown-menu.show {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}

/* Ô chọn tự dựng (ZenpnCloud.select): danh sách luôn nằm trong DOM, mở thì trồi xuống, đóng thì
 * thu ngược lại; visibility trễ để hiệu ứng thu kịp chạy. Mũi tên trên nút xoay theo. */
.zc-select-list {
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(.98);
  transform-origin: top center;
  transition: opacity var(--zm-fast) var(--zm-ease), transform var(--zm-fast) var(--zm-ease),
    visibility 0s linear var(--zm-fast);
}
.zc-select[data-open] .zc-select-list {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}
.zc-select-button::after { transition: transform var(--zm-base) var(--zm-ease); }
.zc-select[data-open] .zc-select-button::after { transform: rotate(180deg); }

/* Sidebar mobile: baseline trượt 450ms với đuôi giảm tốc rất dài, nhìn như lết chậm dần. */
@media (max-width: 991.98px) {
  #page-container #sidebar { transition: transform var(--zm-drawer); }
}

/* Lớp phủ tối của sidebar mobile: bundle đặt display inline, còn #page-container có
 * sidebar-o-xs khi sidebar mở. */
.v2board-nav-mask {
  display: block !important;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--zm-drawer), visibility 0s linear 280ms;
}
.sidebar-o-xs > .v2board-nav-mask {
  opacity: .5;
  visibility: visible;
  transition-delay: 0s;
}

/* Mục thu gọn (details): motion.js co giãn chiều cao như FAQ trang chủ. */
.sidebar-o details[data-animating] { overflow: hidden; }
.sidebar-o details > summary {
  list-style: none;
  cursor: pointer;
}
.sidebar-o details > summary::-webkit-details-marker { display: none; }
.sidebar-o details > summary::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 8px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(-45deg);
  transition: transform var(--zm-base) var(--zm-ease);
}
.sidebar-o details[open]:not([data-closing]) > summary::before { transform: translateY(-2px) rotate(45deg); }
.sidebar-o details[open] > :not(summary) { animation: zm-fade var(--zm-base) var(--zm-ease) backwards; }

/* Nút lớn nhỏ: hover và nhấn. Nhấn dùng thuộc tính scale để không đè transform. */
.sidebar-o :is(.btn, .ant-btn, .zc-stat, .zc-list-item, .zc-link, .zc-tabs button, .dropdown-item,
  .nav-main-link, .ant-pagination-item, .zc-page-home, .v2board-select, .zdp-button) {
  transition: transform var(--zm-fast) var(--zm-ease), background-color var(--zm-base) var(--zm-ease),
    border-color var(--zm-base) var(--zm-ease), box-shadow var(--zm-base) var(--zm-ease),
    color var(--zm-base) var(--zm-ease), scale 100ms var(--zm-ease);
}
.sidebar-o :is(.zc-stat-arrow, .nav-main-link-icon, .zc-link > span, .zc-list-item > :last-child) {
  transition: transform var(--zm-base) var(--zm-ease), color var(--zm-base) var(--zm-ease);
}
@media (hover: hover) {
  .sidebar-o :is(.btn, .ant-btn):hover:not(:disabled) { transform: translateY(-1px); }
  .sidebar-o .zc-stat:hover { transform: translateY(-2px); }
  .sidebar-o .zc-stat:hover .zc-stat-arrow,
  .sidebar-o .zc-link:hover > span,
  .sidebar-o .zc-list-item:hover > :last-child { transform: translateX(2px); }
  .sidebar-o .nav-main-link:hover .nav-main-link-icon { transform: translateX(2px); }
  .sidebar-o .v2board-select:hover { background: var(--zc-hover); }
  .sidebar-o .zdp-button:hover:not(:disabled) { transform: translateY(-1px); }
}
.sidebar-o :is(button, .btn, .ant-btn, .zc-stat, .zc-list-item, .zc-link, .nav-main-link, .dropdown-item, .ant-pagination-item):active:not(:disabled) { scale: .97; }
.sidebar-o .v2board-select:active { scale: .99; }
.sidebar-o .zdp-button:active:not(:disabled) { scale: .97; }

/* Modal đồng bộ máy chủ (antd, gắn ngoài layout): các lựa chọn hiện nối nhau khi
 * modal mở; modal đóng thì antd tự thu về (zoom-leave). */
.ant-modal-body [class*="item___"] {
  animation: zm-rise var(--zm-base) var(--zm-ease) backwards;
  transition: transform var(--zm-fast) var(--zm-ease), background-color var(--zm-base) var(--zm-ease),
    border-color var(--zm-base) var(--zm-ease), scale 100ms var(--zm-ease);
}
.ant-modal-body [class*="item___"]:nth-child(2) { animation-delay: 40ms; }
.ant-modal-body [class*="item___"]:nth-child(3) { animation-delay: 80ms; }
.ant-modal-body [class*="item___"]:nth-child(4) { animation-delay: 120ms; }
.ant-modal-body [class*="item___"]:nth-child(5) { animation-delay: 160ms; }
.ant-modal-body [class*="item___"]:nth-child(6) { animation-delay: 200ms; }
.ant-modal-body [class*="item___"]:nth-child(7) { animation-delay: 240ms; }
@media (hover: hover) {
  .ant-modal-body [class*="item___"]:hover { transform: translateY(-1px); }
}
.ant-modal-body [class*="item___"]:active { scale: .98; }

/* Link chữ trong bảng và thông báo: đường kẻ chạy từ trái sang phải. */
.sidebar-o #main-container :is(td, .alert) a {
  position: relative;
  text-decoration: none !important;
}
.sidebar-o #main-container :is(td, .alert) a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--zm-base) var(--zm-ease);
}
.sidebar-o #main-container :is(td, .alert) a:is(:hover, :focus-visible)::after { transform: scaleX(1); }
/* Nhãn bấm được bọc switch (vd. "Tự động gia hạn"). */
.sidebar-o #main-container span[style*="cursor"] { transition: color var(--zm-fast) var(--zm-ease); }
@media (hover: hover) {
  .sidebar-o #main-container span[style*="cursor"]:hover { color: var(--zc-heading) !important; }
}

/* ── Khung chat ticket (.zc-chat, trang toàn màn hình không có sidebar) ── */
@keyframes zm-in-right { from { opacity: 0; transform: translateX(10px); } }
@keyframes zm-in-left { from { opacity: 0; transform: translateX(-10px); } }
.zc-chat .zc-chat-toolbar { animation: zm-drop var(--zm-slow) var(--zm-ease) backwards; }
/* Mỗi tin nhắn tự chạy khi được chèn vào, kể cả tin vừa gửi: của mình từ phải, của hỗ trợ từ trái. */
.zc-chat .js-chat-messages > * > * { animation: zm-fade var(--zm-base) var(--zm-ease) backwards; }
.zc-chat .js-chat-messages .text-right { animation-name: zm-in-right; }
.zc-chat .js-chat-messages .mr-4 { animation-name: zm-in-left; }
.zc-chat .zc-chat-toolbar > a {
  position: relative;
  text-decoration: none !important;
}
.zc-chat .zc-chat-toolbar > a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--zm-base) var(--zm-ease);
}
.zc-chat .zc-chat-toolbar > a:is(:hover, :focus-visible)::after { transform: scaleX(1); }
.zc-chat .js-chat-input {
  transition: box-shadow var(--zm-fast) var(--zm-ease), background-color var(--zm-fast) var(--zm-ease);
}
.zc-chat .js-chat-input:focus { box-shadow: 0 0 0 2px #165dff33; }

/* Panel xem nhanh đơn hàng: phóng lên giữa màn hình khi mở, thu lại khi đóng; nền mờ theo. */
.zc-order-quick { transition: visibility 0s linear var(--zm-base); }
.zc-order-quick[data-open] { transition: visibility 0s; }
.zc-order-quick-mask {
  opacity: 0;
  transition: opacity var(--zm-base) var(--zm-ease);
}
.zc-order-quick[data-open] .zc-order-quick-mask { opacity: 1; }
.zc-order-quick-sheet {
  opacity: 0;
  transform: translateY(12px) scale(.96);
  transition: opacity var(--zm-base) var(--zm-ease), transform var(--zm-base) var(--zm-ease);
}
.zc-order-quick[data-open] .zc-order-quick-sheet {
  opacity: 1;
  transform: none;
}
.zc-order-quick-info { animation: zm-rise var(--zm-base) var(--zm-ease); }

/* Dải thông báo dashboard: hover sáng lên, mũi tên nhích sang phải; danh sách trồi lên lần lượt. */
.zc-notice-main,
.zc-notice-all,
.zc-notice-item { transition: background-color var(--zm-fast) var(--zm-ease), border-color var(--zm-fast) var(--zm-ease); }
.zc-notice-main:hover,
.zc-notice-all:hover { background-color: var(--zc-hover, rgba(127, 127, 127, .1)); }
.zc-notice-image :is(.zc-notice-main, .zc-notice-all):hover { background-color: rgba(255, 255, 255, .1); }
.zc-notice-item:hover { background-color: var(--zc-hover, rgba(127, 127, 127, .1)); }
.zc-notice-arrow { transition: transform var(--zm-fast) var(--zm-ease); }
.zc-notice-main:hover .zc-notice-arrow,
.zc-notice-item:hover .zc-notice-arrow { transform: translateX(3px); }
/* Đổi thông báo: chữ cũ mờ lên trên rồi chữ mới trồi vào (chỉ opacity/transform của một dòng). */
.zc-notice-main .zc-notice-text { animation: zm-rise var(--zm-base) var(--zm-ease) backwards; }
.zc-notice-main .zc-notice-text,
.zc-notice-main .zc-notice-date {
  transition: opacity 200ms var(--zm-ease), transform 200ms var(--zm-ease);
}
.zc-notice-main[data-leaving] .zc-notice-text,
.zc-notice-main[data-leaving] .zc-notice-date {
  opacity: 0;
  transform: translateY(-6px);
}
.zc-notice-dot { transition: transform var(--zm-base) var(--zm-ease), opacity var(--zm-base) var(--zm-ease); }
.zc-notice-list > * { animation: zm-rise var(--zm-base) var(--zm-ease) backwards; }
.zc-notice-list > :nth-child(2) { animation-delay: 40ms; }
.zc-notice-list > :nth-child(3) { animation-delay: 80ms; }
.zc-notice-list > :nth-child(4) { animation-delay: 120ms; }
.zc-notice-list > :nth-child(n + 5) { animation-delay: 160ms; }

/* ── Giảm chuyển động: đổi trạng thái tức thì ── */
@media (prefers-reduced-motion: reduce) {
  .zc-landing,
  .zc-landing *,
  .zc-landing *::before,
  .zc-landing *::after,
  .zc-auth-page *,
  .v2board-auth-box *,
  .sidebar-o *,
  .zc-chat *,
  .ant-modal-body *,
  .zc-progress,
  [data-waiting]::after,
  .zdp-button[data-loading]::after,
  .zc-select-list,
  .zc-select-button::after,
  .v2board-nav-mask,
  .zc-theme-toggle,
  .zc-theme-toggle *,
  .zc-order-quick,
  .zc-order-quick * {
    animation: none !important;
    transition: none !important;
  }
}
