/* ===== Motion layer (2026-10-05) ======================================
   Interaction only: no colours, sizes or layout change here. Screens slide
   in and out instead of popping, taps get a physical press, ticks spring,
   and the calendar moves between month and day. Everything animates
   transform/opacity only (compositor-friendly) and switches off under
   prefers-reduced-motion. Paired with js/motion.js. */

:root{
  --m-ease-out:cubic-bezier(.22,.8,.3,1);
  --m-spring:cubic-bezier(.34,1.56,.64,1);
}

/* ---- Full screens: slide up + fade in, quicker fade out ------------------
   They used to flip display:none -> flex, which can't animate. Now they stay
   laid out but invisible (visibility also removes them from taps, focus and
   screen readers exactly like display:none did). */
#settingsPanel, #tosPanel, #privacyPanel, #calendarPanel, #pricingPanel,
#tutorialPanel, #caloriePanel, #teamPanel, #teamMemberCalendarPanel{
  display:flex; visibility:hidden; opacity:0; pointer-events:none;
  transform:translate3d(0,18px,0);
  transition:opacity .18s ease, transform .2s ease, visibility 0s linear .2s;
}
#settingsPanel.show, #tosPanel.show, #privacyPanel.show, #calendarPanel.show, #pricingPanel.show,
#tutorialPanel.show, #caloriePanel.show, #teamPanel.show, #teamMemberCalendarPanel.show{
  visibility:visible; opacity:1; pointer-events:auto; transform:none;
  transition:opacity .24s ease, transform .34s var(--m-ease-out), visibility 0s;
}
/* nothing keeps animating behind a closed screen */
#pricingPanel:not(.show) *, #caloriePanel:not(.show) *, #calendarPanel:not(.show) *{
  animation-play-state:paused !important;
}

/* ---- Install sheet: backdrop fades, card rises from the bottom ---------- */
#installSheet{
  display:flex; visibility:hidden; opacity:0; pointer-events:none;
  transition:opacity .2s ease, visibility 0s linear .26s;
}
#installSheet.show{
  visibility:visible; opacity:1; pointer-events:auto;
  transition:opacity .22s ease, visibility 0s;
}
#installSheet .install-card{ transform:translate3d(0,40px,0); transition:transform .26s var(--m-ease-out); }
#installSheet.show .install-card{ transform:none; transition:transform .38s var(--m-ease-out); }

/* ---- Calendar: month <-> day, month to month ---------------------------- */
@keyframes mPushIn{ from{ opacity:0; transform:translate3d(28px,0,0); } to{ opacity:1; transform:none; } }
@keyframes mPopIn{ from{ opacity:0; transform:translate3d(-28px,0,0); } to{ opacity:1; transform:none; } }
@keyframes mRise{ from{ opacity:0; transform:translate3d(0,10px,0); } to{ opacity:1; transform:none; } }
#calDayView.m-push, #tmcalDayView.m-push{ animation:mPushIn .32s var(--m-ease-out) both; }
#calMonthView.m-pop, #tmcalMonthView.m-pop{ animation:mPopIn .32s var(--m-ease-out) both; }
.cal-grid.m-next{ animation:mPushIn .3s var(--m-ease-out) both; }
.cal-grid.m-prev{ animation:mPopIn .3s var(--m-ease-out) both; }
/* the day's exercises arrive one after another */
#calDayExercises.m-stagger > *{ animation:mRise .36s var(--m-ease-out) both; }
#calDayExercises.m-stagger > :nth-child(2){ animation-delay:.04s; }
#calDayExercises.m-stagger > :nth-child(3){ animation-delay:.08s; }
#calDayExercises.m-stagger > :nth-child(4){ animation-delay:.12s; }
#calDayExercises.m-stagger > :nth-child(5){ animation-delay:.16s; }
#calDayExercises.m-stagger > :nth-child(6){ animation-delay:.2s; }
#calDayExercises.m-stagger > :nth-child(n+7){ animation-delay:.24s; }

/* ---- Exercise tick: spring pop, and a wave when the whole set is done --- */
@keyframes mTickOn{ 0%{ transform:scale(.7); } 55%{ transform:scale(1.2); } 100%{ transform:scale(1); } }
@keyframes mTickOff{ 0%{ transform:scale(1); } 45%{ transform:scale(.82); } 100%{ transform:scale(1); } }
.ex-check.m-on{ animation:mTickOn .42s var(--m-ease-out); }
.ex-check.m-off{ animation:mTickOff .3s var(--m-ease-out); }
@keyframes mWave{ 0%,100%{ transform:none; } 40%{ transform:translate3d(0,-3px,0) scale(1.012); } }
.ex-card.m-wave{ animation:mWave .5s var(--m-ease-out) both; }
.ex-complete-banner{ animation:mRise .4s var(--m-ease-out) both; }

/* ---- Streak badge bumps when the streak grows ----------------------------- */
@keyframes mBump{ 0%{ transform:scale(1); } 40%{ transform:scale(1.18); } 100%{ transform:scale(1); } }
.streak-badge.m-bump{ animation:mBump .5s var(--m-spring); }

/* ---- Typing indicator eases in instead of popping ------------------------ */
.typing-row.show{ animation:mRise .24s var(--m-ease-out) both; }

/* ---- Press feedback: things you tap give way under the finger ------------ */
.side-footer-btn, .side-chat-row, .cal-day:not(.pad), .ex-video-btn, #sendBtn, #menuBtn,
.cal-nav-btn, .msg-feedback button, .calorie-meal-delete, .tone-opt, .secondary-btn,
.install-go, .install-close, .attach-menu-item, .cal-day-back, .team-invite-copy{
  transition-property:background, background-color, border-color, color, box-shadow, opacity, transform;
  transition-duration:.15s; transition-timing-function:ease;
}
.side-footer-btn:active, .side-chat-row:active, .cal-day:not(.pad):active, .ex-video-btn:active,
#sendBtn:active, #menuBtn:active, .cal-nav-btn:active, .msg-feedback button:active,
.calorie-meal-delete:active, .tone-opt:active, .secondary-btn:active, .install-go:active,
.install-close:active, .attach-menu-item:active, .cal-day-back:active, .team-invite-copy:active{
  transform:scale(.95); transition-duration:.06s;
}
.side-chat-row:active, .secondary-btn:active, .install-go:active, .install-close:active,
.attach-menu-item:active{ transform:scale(.98); }
.ex-check:active{ transform:scale(.88); transition-duration:.06s; }
body.reply-busy #sendBtn:active{ transform:none; }

/* ---- Chat: your message lifts off the input bar; Tharvik's reply grows out of
   the typing dots (motion.js tags the live reply row with .m-from-typing) -- */
@keyframes mSend{ from{ opacity:0; transform:translate3d(0,26px,0) scale(.94); } to{ opacity:1; transform:none; } }
@keyframes mFromDots{ from{ opacity:0; transform:translate3d(0,8px,0) scale(.96); } to{ opacity:1; transform:none; } }
#chat .msg-row.user:not(.replayed){ animation:mSend .42s var(--m-ease-out); transform-origin:100% 100%; }
#chat .msg-row.coach.m-from-typing{ animation:mFromDots .34s var(--m-ease-out) both; transform-origin:0 0; }

/* ---- Rings fill instead of jumping --------------------------------------- */
/* registered so the calendar ring's --pct can transition (same values as before) */
@property --pct{ syntax:'<number>'; inherits:false; initial-value:0; }
.cal-ring.m-ring{ transition:--pct .7s var(--m-ease-out) .12s; }
/* calorie ring: a track-coloured cover over the ring band unwinds as the number counts up */
@property --m-sweep{ syntax:'<angle>'; inherits:false; initial-value:360deg; }
.calorie-ring::after{
  content:''; position:absolute; inset:-1px; border-radius:50%; pointer-events:none;
  background:conic-gradient(transparent var(--m-sweep), var(--panel) 0);
  -webkit-mask:radial-gradient(farthest-side, transparent calc(100% - 13px), #000 calc(100% - 12px));
          mask:radial-gradient(farthest-side, transparent calc(100% - 13px), #000 calc(100% - 12px));
}
@keyframes mSweep{ from{ --m-sweep:0deg; } to{ --m-sweep:360deg; } }
.calorie-ring.m-sweep::after{ animation:mSweep .8s var(--m-ease-out) both; }

/* ---- Signup questions: the pick washes across, questions move sideways --- */
#setup .q-opt{ position:relative; isolation:isolate; overflow:hidden; }
#setup .q-opt::after{
  content:''; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:var(--gold); opacity:0; transform:scaleX(0); transform-origin:0 50%;
}
@keyframes mWash{ 0%{ opacity:.2; transform:scaleX(0); } 60%{ opacity:.16; transform:scaleX(1); } 100%{ opacity:0; transform:scaleX(1); } }
@keyframes mPick{ 0%{ transform:scale(1); } 35%{ transform:scale(.975); } 100%{ transform:scale(1); } }
#setup .q-opt.m-pick{ animation:mPick .38s var(--m-spring); }
#setup .q-opt.m-pick::after{ animation:mWash .5s var(--m-ease-out); }
@keyframes mQIn{ from{ opacity:0; transform:translate3d(36px,0,0); } to{ opacity:1; transform:none; } }
@keyframes mQOut{ from{ opacity:1; transform:none; } to{ opacity:0; transform:translate3d(-36px,0,0); } }
@keyframes mQInBack{ from{ opacity:0; transform:translate3d(-36px,0,0); } to{ opacity:1; transform:none; } }
@keyframes mQOutBack{ from{ opacity:1; transform:none; } to{ opacity:0; transform:translate3d(36px,0,0); } }
#setup .q-step.active{ animation:mQIn .4s var(--m-ease-out); }
#setup .q-step.leaving{ animation:mQOut .24s ease forwards; }
#setup .q-step.active[data-m-dir="back"]{ animation-name:mQInBack; }
#setup .q-step.leaving[data-m-dir="back"]{ animation-name:mQOutBack; }
.q-progress-fill{ transition:width .5s var(--m-ease-out); }

/* No browser tap-flash on tappable cards (Android paints a blue box over them) */
.ex-card, .ex-card *, .cal-day, .side-chat-row, .status-note, .calorie-meal-row{ -webkit-tap-highlight-color:transparent; }

/* ---- Batch 3 ---------------------------------------------------------------
   Swipe from the left edge to go back: the screen follows the finger. */
.m-edge-drag{ transition:none !important; }

/* "saved and verified": the tick draws itself (the ✓ character stays in the text) */
.m-check{ display:inline-block; width:1.1em; height:1.1em; vertical-align:-0.2em; margin-right:.3em; }
.m-check path{ stroke-dasharray:24; stroke-dashoffset:0; }
.status-note.m-fresh{ animation:mRise .35s var(--m-ease-out) both; }
.status-note.m-fresh .m-check path{ stroke-dashoffset:24; animation:mDraw .5s var(--m-ease-out) .2s forwards; }
@keyframes mDraw{ to{ stroke-dashoffset:0; } }
.m-vh{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }

/* PDF button: a fill sweeps across and the arrow becomes a tick once the download starts */
.pdf-btn::after{
  content:''; position:absolute; inset:0; z-index:0; pointer-events:none;
  background:rgba(255,255,255,.32); opacity:0; transform:scaleX(0); transform-origin:0 50%;
}
@keyframes mPdfFill{ 0%{ opacity:1; transform:scaleX(0); } 45%{ opacity:1; transform:scaleX(1); } 100%{ opacity:0; transform:scaleX(1); } }
.pdf-btn.m-done::after{ animation:mPdfFill 1.1s var(--m-ease-out) forwards; }
.pdf-btn.m-done > svg:not(.m-pdf-tick){ display:none; }
.m-pdf-tick path{ stroke-dasharray:24; stroke-dashoffset:24; animation:mDraw .45s var(--m-ease-out) .2s forwards; }

/* Streak: the new number rolls up from below as the old one leaves the top */
@keyframes mRollIn{ from{ transform:translate3d(0,1.35em,0); } to{ transform:none; } }
#streakBadgeCount.m-roll{ position:relative; display:inline-block; animation:mRollIn .5s var(--m-ease-out) .08s both; }
#streakBadgeCount.m-roll::before{ content:attr(data-m-prev); position:absolute; left:0; right:0; bottom:100%; text-align:center; }
@keyframes mFlicker{ 0%{ transform:none; } 30%{ transform:scale(1.25) rotate(-8deg); } 60%{ transform:scale(.95) rotate(5deg); } 100%{ transform:none; } }
.streak-badge.m-bump svg{ animation:mFlicker .6s ease-out; transform-origin:50% 90%; }

/* Sidebar: its contents arrive in sequence while it slides in */
@keyframes mSlideIn{ from{ opacity:0; transform:translate3d(-12px,0,0); } to{ opacity:1; transform:none; } }
#sidePanel.m-opening .side-new, #sidePanel.m-opening .side-label,
#sidePanel.m-opening .side-chat-row, #sidePanel.m-opening .side-footer-btn{ animation:mSlideIn .34s var(--m-ease-out) backwards; }
#sidePanel.m-opening .side-new{ animation-delay:.04s; }
#sidePanel.m-opening .side-label{ animation-delay:.07s; }
#sidePanel.m-opening .side-chat-row:nth-child(1){ animation-delay:.09s; }
#sidePanel.m-opening .side-chat-row:nth-child(2){ animation-delay:.11s; }
#sidePanel.m-opening .side-chat-row:nth-child(3){ animation-delay:.13s; }
#sidePanel.m-opening .side-chat-row:nth-child(4){ animation-delay:.15s; }
#sidePanel.m-opening .side-chat-row:nth-child(n+5){ animation-delay:.17s; }
#sidePanel.m-opening .side-footer-btn:nth-child(1){ animation-delay:.12s; }
#sidePanel.m-opening .side-footer-btn:nth-child(2){ animation-delay:.14s; }
#sidePanel.m-opening .side-footer-btn:nth-child(3){ animation-delay:.16s; }
#sidePanel.m-opening .side-footer-btn:nth-child(4){ animation-delay:.18s; }
#sidePanel.m-opening .side-footer-btn:nth-child(5){ animation-delay:.2s; }
#sidePanel.m-opening .side-footer-btn:nth-child(6){ animation-delay:.22s; }
#sidePanel.m-opening .side-footer-btn:nth-child(7){ animation-delay:.24s; }
#sidePanel.m-opening .side-footer-btn:nth-child(8){ animation-delay:.26s; }
#sidePanel.m-opening .side-footer-btn:nth-child(n+9){ animation-delay:.28s; }

/* ---- Batch 4 ---------------------------------------------------------------
   Opening the app: chat, menu button and message bar ease in, in sequence */
@keyframes mEnter{ from{ opacity:0; transform:translate3d(0,14px,0); } to{ opacity:1; transform:none; } }
body.m-enter #chat{ animation:mEnter .45s var(--m-ease-out) .04s backwards; }
body.m-enter #menuBtn{ animation:mEnter .4s var(--m-ease-out) backwards; }
body.m-enter #inputRow{ animation:mEnter .45s var(--m-ease-out) .14s backwards; }

/* Check-in chat: new messages lift / grow in like the main chat */
.checkin-msg.user.m-new{ animation:mSend .42s var(--m-ease-out); transform-origin:100% 100%; }
.checkin-msg.coach.m-new{ animation:mFromDots .34s var(--m-ease-out) both; transform-origin:0 0; }

/* Thumbs: the thumb pops; the reason chips and the thank-you slide in */
@keyframes mThumb{ 0%{ transform:scale(1); } 35%{ transform:scale(1.35) rotate(-12deg); } 70%{ transform:scale(.92); } 100%{ transform:none; } }
.fb-btn.m-pop svg{ animation:mThumb .42s var(--m-spring); }
.fb-btn.fb-down.m-pop svg{ animation-name:mThumbDown; }
/* thumbs-down is the same icon turned 180deg (redesign.css), so its pop keeps that turn */
@keyframes mThumbDown{ 0%{ transform:rotate(180deg); } 35%{ transform:rotate(192deg) scale(1.35); } 70%{ transform:rotate(180deg) scale(.92); } 100%{ transform:rotate(180deg); } }
.fb-extra .fb-chip{ animation:mSlideIn .3s var(--m-ease-out) backwards; }
.fb-extra .fb-chip:nth-child(2){ animation-delay:.04s; }
.fb-extra .fb-chip:nth-child(3){ animation-delay:.08s; }
.fb-extra .fb-chip:nth-child(4){ animation-delay:.12s; }
.fb-extra .fb-chip:nth-child(n+5){ animation-delay:.16s; }
.fb-extra .fb-thanks{ animation:mRise .3s var(--m-ease-out) backwards; }

/* ---- Sidebar follows the finger while it's being swiped shut ------------- */
.side-sheet.m-dragging{ transition:none !important; }

@media (prefers-reduced-motion: reduce){
  #settingsPanel, #tosPanel, #privacyPanel, #calendarPanel, #pricingPanel, #tutorialPanel,
  #caloriePanel, #teamPanel, #teamMemberCalendarPanel, #installSheet, #installSheet .install-card{
    transform:none !important; transition:none !important;
  }
  #calDayView.m-push, #tmcalDayView.m-push, #calMonthView.m-pop, #tmcalMonthView.m-pop,
  .cal-grid.m-next, .cal-grid.m-prev, #calDayExercises.m-stagger > *, .ex-check.m-on, .ex-check.m-off,
  .ex-card.m-wave, .ex-complete-banner, .streak-badge.m-bump, .typing-row.show,
  #chat .msg-row.user:not(.replayed), #chat .msg-row.coach.m-from-typing, .calorie-ring.m-sweep::after,
  #setup .q-opt.m-pick, #setup .q-opt.m-pick::after,
  .status-note.m-fresh, .status-note.m-fresh .m-check path, .pdf-btn.m-done::after, .m-pdf-tick path,
  #streakBadgeCount.m-roll, .streak-badge.m-bump svg,
  #sidePanel.m-opening .side-new, #sidePanel.m-opening .side-label,
  #sidePanel.m-opening .side-chat-row, #sidePanel.m-opening .side-footer-btn,
  body.m-enter #chat, body.m-enter #menuBtn, body.m-enter #inputRow, .checkin-msg.m-new,
  .fb-btn.m-pop svg, .fb-extra .fb-chip, .fb-extra .fb-thanks{ animation:none !important; }
  .status-note.m-fresh .m-check path, .m-pdf-tick path{ stroke-dashoffset:0; }
  #streakBadgeCount.m-roll::before{ content:none; }
  #setup .q-step.active, #setup .q-step.leaving{ animation-duration:.01s !important; }
  .cal-ring.m-ring, .q-progress-fill{ transition:none !important; }
  .side-footer-btn:active, .side-chat-row:active, .cal-day:not(.pad):active, .ex-video-btn:active,
  #sendBtn:active, #menuBtn:active, .cal-nav-btn:active, .msg-feedback button:active,
  .calorie-meal-delete:active, .tone-opt:active, .secondary-btn:active, .install-go:active,
  .install-close:active, .attach-menu-item:active, .cal-day-back:active, .team-invite-copy:active,
  .ex-check:active{ transform:none; }
}
