/* Motion. Only transform and opacity (plus SVG stroke offsets) are animated.
   prefers-reduced-motion switches all of it off at the bottom of this file. */

/* 1. Page entrance: the page's top-level blocks rise in, 70 ms apart. Pure CSS, so it
   replays on every page load. Grids stagger their children instead of moving as one. */
.page > *, .page > .grid > * { animation: m-rise .55s var(--ease) backwards; animation-delay: calc(var(--i, 0) * 70ms); }
.page > .grid { animation: none; }
.page > .grid > * { animation-delay: calc((var(--i, 0) + var(--k, 0)) * 70ms); }
.page > :nth-child(2) { --i: 1; } .page > :nth-child(3) { --i: 2; } .page > :nth-child(4) { --i: 3; }
.page > :nth-child(5) { --i: 4; } .page > :nth-child(6) { --i: 5; } .page > :nth-child(7) { --i: 6; }
.page > :nth-child(n+8) { --i: 7; }
.page > .grid > :nth-child(2) { --k: 1; } .page > .grid > :nth-child(3) { --k: 2; } .page > .grid > :nth-child(n+4) { --k: 3; }
@keyframes m-rise { from { opacity: 0; transform: translateY(14px); } }

/* 2. Scroll reveal (motion.js adds .reveal to blocks below the fold, then .is-in once seen). */
.reveal { animation: none !important; opacity: 0; transform: translateY(18px); }
.reveal.is-in { opacity: 1; transform: none; transition: opacity .6s var(--ease), transform .6s var(--ease); transition-delay: calc(var(--d, 0) * 70ms); }

/* 3. Hover lift. Cards holding a form or table stay put so they don't move while being used. */
.card, .stat { transition: transform .28s var(--ease); }
.card::after, .stat::after { transition: opacity .28s var(--ease); }
.card:not(.still):not(:has(form, table)):hover, .stat:hover { transform: translateY(-3px); }
.card:not(.still):not(:has(form, table)):hover::after, .stat:hover::after { opacity: .75; }
.task-card { transition: transform .25s var(--ease); }
.task-card::after { transition: opacity .25s var(--ease); }
.task-card:hover { transform: translateY(-3px) rotate(.4deg); }
.task-card:hover::after { opacity: .7; }
.task-card.is-dragging, .task-card.is-moving { transform: none; }
.task-card.is-arrived { animation: m-pop .35s var(--spring); }
.btn, button { transition: transform .2s var(--ease); }
.btn:hover, button:hover { transform: translateY(-1px); }
.btn:active, button:active { transform: translateY(0) scale(.98); }
.icon-btn:hover, .menu-item:hover, button.menu-item:hover, .icon-btn:active { transform: none; }
.nav-label { display: inline-block; transition: transform .22s var(--ease); }
.nav a:hover .nav-label { transform: translateX(3px); }

/* 4. Idle float for big avatars and empty-state icons. */
.float, .empty-icon { animation: m-float 3s ease-in-out infinite; }
@keyframes m-float { 50% { transform: translateY(-6px); } }

/* 5. Check-in pulse. */
.pulse-dot::after { animation: m-pulse 2.6s var(--ease) infinite; }
@keyframes m-pulse { 0% { transform: scale(1); opacity: .55; } 75%, 100% { transform: scale(2.9); opacity: 0; } }

/* 7. Progress bars and rings fill on load, and glide when their value changes. */
.progress > span { transition: transform .7s var(--ease); animation: m-grow 1s var(--ease) .25s backwards; }
@keyframes m-grow { from { transform: scaleX(0); } }
.ring .ring-fill { transition: stroke-dashoffset .8s var(--ease); animation: m-ring 1.2s var(--ease) .2s backwards; }
@keyframes m-ring { from { stroke-dashoffset: 100; } }

/* 8. Today list: new points slide in, the box pops when ticked, a short wipe crosses the text,
   and motion.js throws a small confetti burst when every point is done. The glow of the
   first-load card fades as it collapses. */
.today-item.is-new { animation: m-rise .4s var(--ease) backwards; }
.tick.is-on.pop { animation: m-tick .38s var(--spring); }
@keyframes m-tick { 0% { transform: scale(.55); } 60% { transform: scale(1.18); } 100% { transform: scale(1); } }
.today-item.just-done .today-text::after { animation: m-wipe .55s var(--ease); }
@keyframes m-wipe { 0% { transform: scaleX(0); opacity: 1; } 65% { transform: scaleX(1); opacity: 1; } 100% { transform: scaleX(1); opacity: 0; } }
.today-card::before { transition: opacity .7s var(--ease); }
.confetti i { animation: m-confetti .95s cubic-bezier(.15, .7, .3, 1) forwards; }
@keyframes m-confetti {
  0% { transform: translate(0, 0) rotate(0) scale(1); opacity: 1; }
  100% { transform: translate(var(--x), var(--y)) rotate(var(--r)) scale(.6); opacity: 0; }
}

/* 9. Calendar: days grow a little on hover, tooltips fade up, today's outline breathes. */
.cal-day { transition: transform .2s var(--ease); }
.cal-day:hover { transform: scale(1.08); }
.cal-day::after { transition: opacity .15s var(--ease), transform .15s var(--ease); }
.cal-day.is-today::before { animation: m-today 2.6s ease-in-out infinite; }
@keyframes m-today { 50% { opacity: .35; transform: scale(1.05); } }
[data-calendar] .cal-grid { transition: opacity .2s; }

/* 10. Greeting words rise in one by one; the first visit of the day gets a small welcome. */
.greet span { animation: m-word .6s var(--ease) backwards; animation-delay: calc(var(--w, 0) * 90ms + 150ms); }
@keyframes m-word { from { opacity: 0; transform: translateY(10px); } }
.hello.is-welcome .avatar { animation: m-welcome 1s var(--spring) backwards, m-float 3s 1s ease-in-out infinite; }
.hello.is-welcome .chip-checkin { animation: m-welcome .8s .55s var(--spring) backwards; }
@keyframes m-welcome { 0% { transform: scale(.6); opacity: 0; } 60% { transform: scale(1.08); opacity: 1; } 100% { transform: scale(1); } }

/* Dashboards: side panel slides in, new activity rows slide down, workload bars grow. */
.drawer { transition: transform .3s var(--ease); }
.drawer-scrim { transition: opacity .25s; }
.activity-row.is-new { animation: m-rise .45s var(--ease) backwards; }
.workload .bar::after { animation: m-grow .9s var(--ease) .2s backwards; }

/* Jump chips: the section they lead to flashes its orange border once. */
.card.flash::after { animation: m-flash 1.4s ease-out; }
@keyframes m-flash { 0%, 35% { opacity: 1; } 100% { opacity: 0; } }

/* 11. Background glow: slow drift; motion.js adds a small mouse parallax. */
.glow { transition: translate 1.4s var(--ease); }
.glow i { will-change: transform; }
.glow i:first-child { animation: m-drift-a 44s ease-in-out infinite alternate; }
.glow i:last-child { animation: m-drift-b 56s ease-in-out infinite alternate; }
@keyframes m-drift-a { to { transform: translate(-9vmax, 7vmax) scale(1.08); } }
@keyframes m-drift-b { to { transform: translate(8vmax, -6vmax) scale(.94); } }

/* 13. Page transitions: cross-fade where the View Transitions API exists; elsewhere the
   entrance animation above gives the fade. The shell keeps its place. */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .2s; }
.topbar { view-transition-name: topbar; }
.sidebar { view-transition-name: sidebar; }

/* 14. Toasts slide in from the right; skeletons shimmer. */
.toast { animation: m-toast-in .5s var(--spring) backwards; }
.toast:nth-child(2) { animation-delay: .08s; }
.toast:nth-child(3) { animation-delay: .16s; }
.toast.is-leaving { opacity: 0; transform: translateX(24px); transition: opacity .25s, transform .25s; }
@keyframes m-toast-in { from { opacity: 0; transform: translateX(28px) scale(.98); } }
.skeleton::after { animation: m-shimmer 1.4s ease-in-out infinite; }
@keyframes m-shimmer { to { transform: translateX(100%); } }

/* 15. Magnetic primary buttons (motion.js sets `translate`, which composes with the hover lift). */
[data-magnetic] { transition: transform .2s var(--ease), translate .25s var(--ease); }

/* 16. Checkmark draw. */
.just-completed .check-draw path { stroke-dashoffset: 24; animation: m-draw .55s var(--ease) .3s forwards; }
.card.just-completed::after { animation: m-flash 1.6s ease-out; }
@keyframes m-draw { to { stroke-dashoffset: 0; } }

/* Menus, badges, mobile sidebar. */
.menu[open] > .menu-pop { animation: m-pop .22s var(--spring); transform-origin: top right; }
@keyframes m-pop { from { opacity: 0; transform: translateY(-6px) scale(.97); } }
.icon-btn .dot-count { animation: m-bounce .6s var(--spring) .45s backwards; }
@keyframes m-bounce { from { transform: scale(.4); opacity: 0; } }
@media (max-width: 960px) { .sidebar { transition: transform .3s var(--ease), visibility .3s; } }

/* Chat: the pop-up springs open from the button, new messages slide in, the badge bounces once. */
.chat-pop { transition: opacity .2s var(--ease), transform .38s var(--spring); }
.chat-fab { transition: transform .25s var(--spring), background .2s; }
.chat-fab:hover { transform: translateY(-2px) scale(1.04); }
.chat-fab[aria-expanded="true"] { transform: rotate(-8deg); }
.chat-badge.is-bouncing { animation: m-chat-bounce .7s var(--spring); }
@keyframes m-chat-bounce { 0% { transform: scale(.4); } 55% { transform: scale(1.25); } 100% { transform: scale(1); } }
.msg.is-new { animation: m-msg-in .4s var(--ease) backwards; }
.msg.mine.is-new { animation-name: m-msg-in-mine; }
@keyframes m-msg-in { from { opacity: 0; transform: translate(-10px, 8px); } }
@keyframes m-msg-in-mine { from { opacity: 0; transform: translate(10px, 8px); } }
.chat-tip::after { transition: opacity .15s var(--ease), transform .15s var(--ease); }
.online-chat-icon { transition: opacity .15s, color .15s; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0s !important; animation-delay: 0s !important; animation-iteration-count: 1 !important;
    transition-duration: 0s !important; transition-delay: 0s !important; scroll-behavior: auto !important;
  }
  .glow { display: none; }
  @view-transition { navigation: none; }
}
