/* motion-kit: the one source for motion in every project. Copy (or publish) this file, never edit a copy.
   Feel (Franklin, 2026-09-27): smooth for big moves, snappy for taps. No spring, no bounce.
   Colours come from the page: --b1 --b2 --b3 (brights), --m2 (muted), --ok --bad, --ink --surface. */
:root{
  --m-smooth:cubic-bezier(.22,1,.36,1);
  --m-snappy:cubic-bezier(.2,.9,.1,1);
  --m-fast:180ms;--m-med:320ms;--m-slow:560ms;
  --m-ok:var(--ok,#16A864);--m-bad:var(--bad,#E8414F);
}

/* press: every tappable thing gives under the finger */
.m-press{transition:transform var(--m-fast) var(--m-snappy)}
.m-press:active{transform:scale(.95)}

/* reveal on scroll, staggered. Hidden only once motion.js has added .js to <html>. */
.js [data-m-reveal]{opacity:0;transform:translateY(14px);transition:opacity var(--m-slow) var(--m-smooth),transform var(--m-slow) var(--m-smooth);transition-delay:calc(var(--m-i,0) * 60ms)}
.js [data-m-reveal].m-in{opacity:1;transform:none}

/* row flash: did my edit save? */
.m-flash-ok{animation:m-flash-ok 1.2s var(--m-smooth)}
.m-flash-bad{animation:m-flash-bad 1.2s var(--m-smooth),m-shake .4s var(--m-snappy)}
@keyframes m-flash-ok{0%,30%{background-color:color-mix(in oklab,var(--m-ok) 22%,transparent)}}
@keyframes m-flash-bad{0%,30%{background-color:color-mix(in oklab,var(--m-bad) 20%,transparent)}}
.m-shake{animation:m-shake .4s var(--m-snappy)}
@keyframes m-shake{0%,100%{transform:translateX(0)}20%{transform:translateX(-7px)}40%{transform:translateX(6px)}60%{transform:translateX(-4px)}80%{transform:translateX(2px)}}

/* toast */
.m-toast{position:fixed;left:50%;bottom:calc(24px + env(safe-area-inset-bottom,0px));z-index:1000;display:flex;align-items:center;gap:9px;padding:11px 18px 11px 12px;border-radius:99px;background:var(--ink,#151823);color:var(--surface,#fff);font-weight:800;font-size:14px;box-shadow:0 20px 40px -16px rgba(0,0,0,.45);transform:translate(-50%,24px);opacity:0;pointer-events:none;transition:transform var(--m-med) var(--m-smooth),opacity var(--m-fast)}
.m-toast.m-show{transform:translate(-50%,0);opacity:1}
.m-toast .m-dot{width:18px;height:18px;border-radius:50%;flex:none;background:var(--m-ok);display:grid;place-items:center;color:#fff;font-size:12px}
.m-toast.m-bad .m-dot{background:var(--m-bad)}
.m-toast-local{position:absolute;bottom:14px}

/* hold to confirm: <button data-m-hold="1200"> ... </button>, --m-p runs 0..1 */
[data-m-hold]{--m-p:0;position:relative;user-select:none;-webkit-user-select:none;touch-action:none}
.m-ring{width:24px;height:24px;border-radius:50%;flex:none;background:conic-gradient(currentColor calc(var(--m-p)*1turn),color-mix(in oklab,currentColor 30%,transparent) 0);-webkit-mask:radial-gradient(circle,transparent 7px,#000 7.5px);mask:radial-gradient(circle,transparent 7px,#000 7.5px)}

/* morph button: the button becomes its own spinner, then a tick. Motion.busy(btn, promise) */
.m-morph{position:relative;transition:width var(--m-med) var(--m-smooth),padding var(--m-med) var(--m-smooth),background-color var(--m-med)}
.m-morph>*{transition:opacity var(--m-fast)}
.m-morph.m-busy,.m-morph.m-done,.m-morph.m-fail{padding-left:0!important;padding-right:0!important;overflow:hidden}
.m-morph.m-busy>*,.m-morph.m-done>*,.m-morph.m-fail>*{opacity:0}
.m-morph::after{content:"";position:absolute;inset:0;margin:auto;width:20px;height:20px;border-radius:50%;opacity:0;pointer-events:none}
.m-morph.m-busy::after{opacity:1;border:3px solid color-mix(in oklab,currentColor 30%,transparent);border-top-color:currentColor;animation:m-spin .7s linear infinite}
.m-morph.m-done{background-color:var(--m-ok)!important;color:#fff!important}
.m-morph.m-done::after{opacity:1;width:22px;height:12px;border-radius:0;border:0 solid #fff;border-width:0 0 3.5px 3.5px;transform:translateY(-3px) rotate(-45deg);animation:m-pop var(--m-med) var(--m-smooth)}
.m-morph.m-fail{background-color:var(--m-bad)!important;color:#fff!important;animation:m-shake .4s var(--m-snappy)}
.m-morph.m-fail::after{opacity:1;content:"!";width:auto;height:auto;border:0;font-weight:900;font-size:20px;display:grid;place-items:center;color:#fff}
@keyframes m-spin{to{transform:rotate(360deg)}}
@keyframes m-pop{from{transform:translateY(-3px) rotate(-45deg) scale(.4);opacity:0}}

/* liquid fill hover: <button class="m-liquid"> — colour pours in from the pointer */
.m-liquid{position:relative;overflow:hidden;isolation:isolate;transition:color var(--m-med)}
.m-liquid::before{content:"";position:absolute;left:var(--m-x,50%);top:var(--m-y,50%);width:340px;height:340px;margin:-170px;border-radius:50%;background:var(--m-fill,var(--b1,#1A7CF5));transform:scale(0);transition:transform var(--m-slow) var(--m-smooth);z-index:-1}
.m-liquid:hover{color:var(--m-fill-on,var(--on1,#fff))}
.m-liquid:hover::before{transform:scale(1)}

/* loading: skeleton, dots, blob, spinner with a live verb, step list */
.m-skel{border-radius:10px;background:linear-gradient(90deg,var(--sunk,#E9EBF1) 25%,color-mix(in oklab,var(--sunk,#E9EBF1) 60%,var(--muted,#666B7D)) 50%,var(--sunk,#E9EBF1) 75%);background-size:300% 100%;animation:m-shimmer 1.4s ease-in-out infinite}
@keyframes m-shimmer{from{background-position:100% 0}to{background-position:-50% 0}}
.m-dots{display:inline-flex;gap:7px}
.m-dots i{width:11px;height:11px;border-radius:50%;background:var(--b1,#1A7CF5);animation:m-dot 1s var(--m-smooth) infinite}
.m-dots i:nth-child(2){background:var(--b2,#19C2DC);animation-delay:.12s}.m-dots i:nth-child(3){background:var(--b3,#A6E23A);animation-delay:.24s}
@keyframes m-dot{0%,60%,100%{transform:translateY(0)}30%{transform:translateY(-12px)}}
.m-blob{width:56px;height:56px;background:linear-gradient(135deg,var(--b1,#1A7CF5),var(--b2,#19C2DC));animation:m-morphshape 3s ease-in-out infinite,m-spin 7s linear infinite}
@keyframes m-morphshape{0%,100%{border-radius:42% 58% 63% 37%/41% 44% 56% 59%}33%{border-radius:63% 37% 44% 56%/55% 62% 38% 45%}66%{border-radius:38% 62% 52% 48%/63% 38% 62% 37%}}
.m-spinner{display:inline-flex;align-items:center;gap:10px;font-weight:800}
.m-spinner::before{content:"";width:22px;height:22px;border-radius:50%;border:3px solid var(--sunk,#E9EBF1);border-top-color:var(--b1,#1A7CF5);animation:m-spin .8s linear infinite;flex:none}
.m-verb{transition:opacity var(--m-fast),transform var(--m-fast) var(--m-smooth)}
.m-verb.m-swap{opacity:0;transform:translateY(6px)}
.m-steps{display:flex;flex-direction:column;gap:9px;margin:0;padding:0;list-style:none}
.m-steps li{display:flex;align-items:center;gap:10px;font-weight:700;color:var(--muted,#666B7D);transition:color var(--m-med)}
.m-steps li::before{content:"";width:18px;height:18px;border-radius:50%;border:2px solid var(--sunk,#E9EBF1);flex:none;transition:background-color var(--m-med),border-color var(--m-med)}
.m-steps li.m-active{color:var(--ink,#151823)}
.m-steps li.m-active::before{border-color:var(--b1,#1A7CF5);border-top-color:transparent;animation:m-spin .8s linear infinite}
.m-steps li.m-done{color:var(--ink,#151823)}
.m-steps li.m-done::before{background:var(--b3,#A6E23A) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='%23fff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/12px no-repeat;border-color:var(--b3,#A6E23A)}

/* confetti pieces (Motion.confetti) and sparks (Motion.sparks) */
.m-piece{position:absolute;pointer-events:none;z-index:5}

/* status pulse */
.m-pulse{position:relative}
.m-pulse::after{content:"";position:absolute;inset:0;border-radius:inherit;background:inherit;animation:m-ripple 1.8s var(--m-smooth) infinite}
@keyframes m-ripple{to{transform:scale(3.2);opacity:0}}

/* reduced motion: no movement, but feedback still arrives (colour, text, state) */
@media (prefers-reduced-motion:reduce){
  .js [data-m-reveal]{opacity:1;transform:none;transition:none}
  .m-press:active{transform:none}
  .m-flash-bad,.m-shake,.m-morph.m-fail{animation:m-flash-bad 1.2s linear}
  .m-skel,.m-dots i,.m-blob,.m-pulse::after{animation:none}
  .m-spinner::before,.m-steps li.m-active::before,.m-morph.m-busy::after{animation-duration:2.4s}
  .m-toast,.m-liquid::before,.m-morph{transition-duration:1ms}
}
