/* ════════════════════════════════════════════════════════════════════════
   FLUDE · flude-animations.css
   Librería de micro-animaciones in-app · SVG + CSS puro · cero dependencias
   ────────────────────────────────────────────────────────────────────────
   Uso general:
   - Cada animación se dispara agregando una clase trigger por JS:
       .play   → anima una vez (success, splash, módulos, data viz, transiciones)
       .on     → estado activo (toggle, accordion, modal, tab)
   - Para "on in-view" usá IntersectionObserver (ver flude-animations.js).
   - Respeta prefers-reduced-motion al final del archivo.
   Tokens esperados (definí estos --vars en tu :root o reemplazá inline):
     --brand #5B5CF6  --teal #06CFC4  --success #10B981  --error #EF4444
     --hi #F0F0FA  --mid #A0A0C4  --elev #141424  --card #191929  --border #2a2a45
   ════════════════════════════════════════════════════════════════════════ */

/* ── 1 · SPLASH / BOOT (isotype se construye) ───────────────────────────── */
.flu-splash .iso-stroke{stroke:#fff;stroke-width:44;stroke-linecap:round;fill:none;stroke-dasharray:320;stroke-dashoffset:320}
.flu-splash .iso-rect{transform-box:fill-box;transform-origin:center;transform:scale(.8);opacity:0}
.flu-splash .iso-dot{transform-box:fill-box;transform-origin:center;opacity:0}
.flu-splash.play .iso-rect{animation:fluSplashRect .5s cubic-bezier(.3,1.3,.5,1) forwards}
.flu-splash.play .s1{animation:fluDraw .5s ease forwards .05s}
.flu-splash.play .s2{animation:fluDraw .5s ease forwards .21s}
.flu-splash.play .s3{animation:fluDraw .5s ease forwards .37s}
.flu-splash.play .iso-dot{animation:fluSplashDot .5s cubic-bezier(.5,1.6,.4,1) forwards .62s}
@keyframes fluDraw{to{stroke-dashoffset:0}}
@keyframes fluSplashRect{to{opacity:1;transform:scale(1)}}
@keyframes fluSplashDot{from{opacity:0;transform:scale(0)}60%{transform:scale(1.3)}to{opacity:.9;transform:scale(1)}}

/* ── 2 · SUCCESS CHECK ──────────────────────────────────────────────────── */
.flu-check .ring{stroke:var(--success);stroke-width:6;fill:none;stroke-dasharray:283;stroke-dashoffset:283;transform-box:fill-box;transform-origin:center;transform:rotate(-90deg)}
.flu-check .tick{stroke:var(--success);stroke-width:8;fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:60;stroke-dashoffset:60}
.flu-check .burst{stroke:var(--success);stroke-width:3;fill:none;opacity:0;transform-box:fill-box;transform-origin:center}
.flu-check.play .ring{animation:fluRing .5s ease forwards}
.flu-check.play .tick{animation:fluDraw .35s cubic-bezier(.6,0,.3,1.3) forwards .4s}
.flu-check.play .burst{animation:fluBurst .5s ease-out forwards .55s}
@keyframes fluRing{to{stroke-dashoffset:0}}
@keyframes fluBurst{0%{opacity:.9;transform:scale(.6)}100%{opacity:0;transform:scale(1.3)}}

/* ── 3 · ERROR / RECHAZO (ring + cross + shake) ─────────────────────────── */
.flu-error .ring{stroke:var(--error);stroke-width:6;fill:none;stroke-dasharray:283;stroke-dashoffset:283;transform-box:fill-box;transform-origin:center;transform:rotate(-90deg)}
.flu-error .cross{stroke:var(--error);stroke-width:8;stroke-linecap:round;stroke-dasharray:40;stroke-dashoffset:40}
.flu-error.play .ring{animation:fluRing .5s ease forwards}
.flu-error.play .cross{animation:fluDraw .3s ease forwards .4s}
.flu-error.play .flu-shake{animation:fluShake .4s ease .7s}
@keyframes fluShake{0%,100%{transform:translateX(0)}20%{transform:translateX(-7px)}40%{transform:translateX(7px)}60%{transform:translateX(-4px)}80%{transform:translateX(4px)}}

/* ── 4 · TOGGLE (knob elástico) ─────────────────────────────────────────── */
.flu-toggle{width:72px;height:40px;border-radius:99px;background:var(--elev);border:1px solid var(--border);position:relative;cursor:pointer;transition:background .3s ease,border-color .3s}
.flu-toggle.on{background:linear-gradient(115deg,var(--brand),var(--teal));border-color:transparent}
.flu-toggle .knob{position:absolute;top:4px;left:4px;width:30px;height:30px;border-radius:50%;background:#fff;transition:left .3s cubic-bezier(.5,1.5,.5,1),width .15s;box-shadow:0 2px 8px rgba(0,0,0,.3)}
.flu-toggle.on .knob{left:38px}
.flu-toggle:active .knob{width:38px}
.flu-toggle.on:active .knob{left:30px}

/* ── 5 · BUTTON (ripple; estados loading/done por JS) ───────────────────── */
.flu-btn{position:relative;overflow:hidden;display:inline-flex;align-items:center;gap:8px;justify-content:center;cursor:pointer}
.flu-btn .ripple{position:absolute;border-radius:50%;background:rgba(255,255,255,.5);transform:translate(-50%,-50%) scale(0);pointer-events:none}
.flu-btn.rip .ripple{animation:fluRipple .6s ease-out}
.flu-btn.loading{background:var(--brand)}
.flu-btn.done{background:var(--success);color:#fff}
@keyframes fluRipple{to{transform:translate(-50%,-50%) scale(8);opacity:0}}

/* ── 6 · NOTIFICATION BELL ──────────────────────────────────────────────── */
.flu-bell .bell-body{transform-origin:top center;transform-box:fill-box}
.flu-bell .badge{transform-box:fill-box;transform-origin:center;transform:scale(0)}
.flu-bell.play .bell-body{animation:fluBellRing .8s ease}
.flu-bell.play .badge{animation:fluPop .4s cubic-bezier(.5,1.7,.4,1) forwards .15s}
@keyframes fluBellRing{0%,100%{transform:rotate(0)}15%{transform:rotate(14deg)}30%{transform:rotate(-12deg)}45%{transform:rotate(8deg)}60%{transform:rotate(-5deg)}75%{transform:rotate(2deg)}}
@keyframes fluPop{to{transform:scale(1)}}

/* ── 7 · MINI SPINNER (isotype rotando · currentColor) ──────────────────── */
.flu-spin{animation:fluRot 1.1s linear infinite}
@keyframes fluRot{to{transform:rotate(360deg)}}

/* ── 8 · INLINE SPINNER FULLSCREEN (draw loop) ──────────────────────────── */
.flu-loader .iso-stroke{stroke:#fff;stroke-width:44;stroke-linecap:round;fill:none;stroke-dasharray:300;stroke-dashoffset:300;animation:fluLoaderDraw 1.6s ease-in-out infinite}
.flu-loader .s1{animation-delay:0s}.flu-loader .s2{animation-delay:.16s}.flu-loader .s3{animation-delay:.32s}
.flu-loader .iso-dot{transform-box:fill-box;transform-origin:center;animation:fluLoaderPulse 1.6s ease-in-out infinite}
@keyframes fluLoaderDraw{0%{stroke-dashoffset:300}30%,100%{stroke-dashoffset:0}}
@keyframes fluLoaderPulse{0%,55%{transform:scale(1);opacity:.55}70%{transform:scale(1.25);opacity:1}100%{transform:scale(1);opacity:.85}}

/* ═══════════════ MÓDULOS (10) — íconos con vida al activar ═══════════════ */
.flu-mod svg{width:56px;height:56px}
.flu-mod .mi{stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;fill:none}

/* gastos · sparkle IA */
.flu-mod.gastos .spark{transform-box:fill-box;transform-origin:center;opacity:0}
.flu-mod.gastos.play .spark{animation:fluSparkle 1s ease forwards}
@keyframes fluSparkle{0%{opacity:0;transform:scale(0) rotate(0)}50%{opacity:1;transform:scale(1.2) rotate(90deg)}100%{opacity:1;transform:scale(1) rotate(90deg)}}

/* ventas · barras crecen en secuencia */
.flu-mod.ventas .bar1,.flu-mod.ventas .bar2,.flu-mod.ventas .bar3{transform-box:fill-box;transform-origin:bottom}
.flu-mod.ventas.play .bar1{animation:fluBarGrow .5s ease 0s both}
.flu-mod.ventas.play .bar2{animation:fluBarGrow .5s ease .12s both}
.flu-mod.ventas.play .bar3{animation:fluBarGrow .5s ease .24s both}
@keyframes fluBarGrow{from{transform:scaleY(0)}to{transform:scaleY(1)}}

/* stock · caja se ensambla */
.flu-mod.stock .box{transform-box:fill-box;transform-origin:center}
.flu-mod.stock.play .box{animation:fluBoxIn .5s cubic-bezier(.4,1.4,.5,1)}
@keyframes fluBoxIn{from{transform:scale(.5) translateY(-8px);opacity:.3}to{transform:scale(1) translateY(0);opacity:1}}

/* finanzas · moneda gira */
.flu-mod.finanzas .coin{transform-box:fill-box;transform-origin:center}
.flu-mod.finanzas.play .coin{animation:fluFlip .8s ease}
@keyframes fluFlip{from{transform:rotateY(0)}to{transform:rotateY(360deg)}}

/* flujos · nodos se conectan (líneas se dibujan + nodos pop) */
.flu-mod.flujos .fline{stroke-dasharray:40;stroke-dashoffset:40}
.flu-mod.flujos .fnode{transform-box:fill-box;transform-origin:center;transform:scale(0)}
.flu-mod.flujos.play .fline{animation:fluDraw .45s ease forwards .2s}
.flu-mod.flujos.play .n1{animation:fluPop .3s cubic-bezier(.5,1.6,.4,1) forwards 0s}
.flu-mod.flujos.play .n2{animation:fluPop .3s cubic-bezier(.5,1.6,.4,1) forwards .5s}
.flu-mod.flujos.play .n3{animation:fluPop .3s cubic-bezier(.5,1.6,.4,1) forwards .65s}

/* flota · ruedas giran + avanza */
.flu-mod.flota .wheel{transform-box:fill-box;transform-origin:center}
.flu-mod.flota.play .wheel{animation:fluRot .6s linear 2}
.flu-mod.flota.play .van{animation:fluNudge .6s ease}
@keyframes fluNudge{0%{transform:translateX(-4px)}50%{transform:translateX(2px)}100%{transform:translateX(0)}}

/* factura · líneas se escriben + sello cae */
.flu-mod.factura .fl{stroke-dasharray:20;stroke-dashoffset:20}
.flu-mod.factura.play .fl1{animation:fluDraw .3s ease forwards .1s}
.flu-mod.factura.play .fl2{animation:fluDraw .3s ease forwards .25s}
.flu-mod.factura.play .fl3{animation:fluDraw .3s ease forwards .4s}
.flu-mod.factura .stamp{transform-box:fill-box;transform-origin:center;transform:scale(0) rotate(-25deg);opacity:0}
.flu-mod.factura.play .stamp{animation:fluStamp .35s cubic-bezier(.5,1.6,.4,1) forwards .6s}
@keyframes fluStamp{from{transform:scale(2) rotate(-25deg);opacity:0}to{transform:scale(1) rotate(-12deg);opacity:1}}

/* compras · carrito rueda + ítem cae */
.flu-mod.compras .cart{transform-box:fill-box;transform-origin:center}
.flu-mod.compras.play .cart{animation:fluNudge .6s ease}
.flu-mod.compras .citem{transform-box:fill-box;transform-origin:center;transform:translateY(-10px);opacity:0}
.flu-mod.compras.play .citem{animation:fluDrop .4s cubic-bezier(.4,1.3,.5,1) forwards .2s}
@keyframes fluDrop{to{transform:translateY(0);opacity:1}}

/* rrhh · personas aparecen */
.flu-mod.rrhh .person{transform-box:fill-box;transform-origin:bottom;transform:scale(0)}
.flu-mod.rrhh.play .p1{animation:fluPop .35s cubic-bezier(.5,1.6,.4,1) forwards 0s}
.flu-mod.rrhh.play .p2{animation:fluPop .35s cubic-bezier(.5,1.6,.4,1) forwards .15s}

/* proyectos · filas de tareas se chequean */
.flu-mod.proyectos .task{transform-box:fill-box;transform-origin:left;transform:scaleX(0)}
.flu-mod.proyectos.play .t1{animation:fluGrowX .35s ease forwards 0s}
.flu-mod.proyectos.play .t2{animation:fluGrowX .35s ease forwards .15s}
.flu-mod.proyectos.play .t3{animation:fluGrowX .35s ease forwards .3s}
@keyframes fluGrowX{to{transform:scaleX(1)}}

/* ═══════════════ DATA VIZ ═══════════════ */
/* counter: el valor lo anima JS (ver runCounter). */

/* chart · línea se dibuja + puntos pop */
.flu-chart .area{opacity:0}
.flu-chart .line{stroke:var(--brand);stroke-width:3;fill:none;stroke-dasharray:400;stroke-dashoffset:400}
.flu-chart .pt{transform-box:fill-box;transform-origin:center;transform:scale(0)}
.flu-chart.play .area{animation:fluFade .6s ease forwards .4s}
.flu-chart.play .line{animation:fluDrawLong 1s ease forwards}
.flu-chart.play .pt{animation:fluPop .3s cubic-bezier(.5,1.6,.4,1) forwards}
.flu-chart.play .pt:nth-child(1){animation-delay:.4s}.flu-chart.play .pt:nth-child(2){animation-delay:.55s}
.flu-chart.play .pt:nth-child(3){animation-delay:.7s}.flu-chart.play .pt:nth-child(4){animation-delay:.85s}
.flu-chart.play .pt:nth-child(5){animation-delay:1s}
@keyframes fluDrawLong{to{stroke-dashoffset:0}}
@keyframes fluFade{to{opacity:1}}

/* progress bar */
.flu-prog{height:10px;background:var(--elev);border-radius:99px;overflow:hidden}
.flu-prog .fill{height:100%;width:0;border-radius:99px;background:linear-gradient(90deg,var(--brand),var(--teal))}
.flu-prog.play .fill{animation:fluProg 1.4s cubic-bezier(.3,0,.2,1) forwards}
@keyframes fluProg{to{width:var(--flu-prog-to,78%)}}

/* donut / ring progress */
.flu-donut .track{stroke:var(--elev);fill:none}
.flu-donut .val{stroke:var(--teal);fill:none;stroke-linecap:round;stroke-dasharray:283;stroke-dashoffset:283;transform-box:fill-box;transform-origin:center;transform:rotate(-90deg)}
.flu-donut.play .val{animation:fluDonut 1.2s cubic-bezier(.3,0,.2,1) forwards}
@keyframes fluDonut{to{stroke-dashoffset:var(--flu-donut-to,85)}}

/* ═══════════════ TRANSICIONES DE ESTADO ═══════════════ */
/* skeleton → datos */
.flu-skel .row{height:14px;border-radius:6px;background:linear-gradient(90deg,var(--elev) 25%,var(--card) 50%,var(--elev) 75%);background-size:200% 100%;animation:fluShimmer 1.2s infinite}
.flu-skel.play .row{animation:none;background:var(--elev)}
.flu-skel .real{opacity:0;transition:opacity .4s ease .2s}
.flu-skel.play .real{opacity:1}
@keyframes fluShimmer{to{background-position:-200% 0}}

/* empty → primer ítem */
.flu-empty .ph{transition:all .3s}
.flu-empty.play .ph{border-style:solid;border-color:transparent;background:var(--card)}
.flu-empty .item{opacity:0;transform:translateY(8px)}
.flu-empty.play .item{animation:fluItemIn .4s ease forwards .15s}
@keyframes fluItemIn{to{opacity:1;transform:translateY(0)}}

/* ═══════════════ INTERACCIONES NUEVAS ═══════════════ */

/* tooltip (fade + slide) */
.flu-tooltip{opacity:0;transform:translateY(4px);pointer-events:none;transition:opacity .18s ease,transform .18s ease}
.flu-tooltip.on{opacity:1;transform:translateY(0)}

/* modal / dialog (scale-in backdrop) */
.flu-modal-backdrop{opacity:0;transition:opacity .25s ease;pointer-events:none}
.flu-modal-backdrop.on{opacity:1;pointer-events:auto}
.flu-modal{transform:scale(.92) translateY(8px);opacity:0;transition:transform .28s cubic-bezier(.3,1.2,.4,1),opacity .22s ease}
.flu-modal-backdrop.on .flu-modal{transform:scale(1) translateY(0);opacity:1}

/* tab underline (slide) */
.flu-tabs{position:relative}
.flu-tabs .flu-tab-ink{position:absolute;bottom:0;height:2px;background:linear-gradient(90deg,var(--brand),var(--teal));border-radius:2px;transition:left .28s cubic-bezier(.4,0,.2,1),width .28s cubic-bezier(.4,0,.2,1)}

/* accordion (height + chevron) */
.flu-acc-body{overflow:hidden;max-height:0;transition:max-height .32s cubic-bezier(.4,0,.2,1)}
.flu-acc.on .flu-acc-body{max-height:var(--flu-acc-h,300px)}
.flu-acc .flu-chevron{transition:transform .28s ease}
.flu-acc.on .flu-chevron{transform:rotate(180deg)}

/* input focus (label float + underline grow) */
.flu-field{position:relative}
.flu-field input{background:transparent;border:none;border-bottom:1.5px solid var(--border);width:100%;padding:18px 0 8px;color:var(--hi);font-size:15px;outline:none}
.flu-field .flu-underline{position:absolute;bottom:0;left:0;height:1.5px;width:0;background:linear-gradient(90deg,var(--brand),var(--teal));transition:width .3s ease}
.flu-field input:focus ~ .flu-underline{width:100%}
.flu-field .flu-label{position:absolute;left:0;top:18px;color:var(--mid);font-size:15px;pointer-events:none;transition:all .22s ease}
.flu-field input:focus ~ .flu-label,.flu-field input:not(:placeholder-shown) ~ .flu-label{top:0;font-size:11px;color:var(--teal)}

/* copy-to-clipboard (icon swap + bounce) */
.flu-copy .ico-copy,.flu-copy .ico-done{transition:transform .2s ease,opacity .2s ease;transform-box:fill-box;transform-origin:center}
.flu-copy .ico-done{position:absolute;opacity:0;transform:scale(0)}
.flu-copy.copied .ico-copy{opacity:0;transform:scale(0)}
.flu-copy.copied .ico-done{opacity:1;transform:scale(1)}

/* drag & drop (lift + drop zone glow) */
.flu-drag{transition:transform .18s ease,box-shadow .18s ease,opacity .18s}
.flu-drag.dragging{transform:scale(1.04) rotate(-1.5deg);box-shadow:0 16px 40px rgba(0,0,0,.5);opacity:.92;cursor:grabbing}
.flu-dropzone{transition:background .2s ease,border-color .2s ease}
.flu-dropzone.over{background:rgba(6,207,196,.08);border-color:var(--teal)}

/* pull-to-refresh (isotype spinner reveal) */
.flu-ptr{transition:transform .25s ease}
.flu-ptr.refreshing .flu-ptr-icon{animation:fluRot 1s linear infinite}

/* row enter (lista que aparece en stagger — usá .play en el contenedor) */
.flu-stagger > *{opacity:0;transform:translateY(10px)}
.flu-stagger.play > *{animation:fluRowIn .4s ease forwards}
.flu-stagger.play > *:nth-child(1){animation-delay:.04s}
.flu-stagger.play > *:nth-child(2){animation-delay:.10s}
.flu-stagger.play > *:nth-child(3){animation-delay:.16s}
.flu-stagger.play > *:nth-child(4){animation-delay:.22s}
.flu-stagger.play > *:nth-child(5){animation-delay:.28s}
.flu-stagger.play > *:nth-child(6){animation-delay:.34s}
@keyframes fluRowIn{to{opacity:1;transform:translateY(0)}}

/* toast (slide-in desde abajo-derecha) */
.flu-toast{transform:translateY(120%) scale(.96);opacity:0;transition:transform .35s cubic-bezier(.3,1.2,.4,1),opacity .25s}
.flu-toast.on{transform:translateY(0) scale(1);opacity:1}

/* ════════════════════════════ ACCESIBILIDAD ════════════════════════════ */
@media (prefers-reduced-motion: reduce){
  .flu-splash *,.flu-check *,.flu-error *,.flu-bell *,.flu-mod *,.flu-chart *,
  .flu-prog .fill,.flu-donut .val,.flu-skel .row,.flu-empty .item,.flu-loader *,
  .flu-stagger > *{animation:none !important;transition:none !important}
  .flu-splash .iso-stroke{stroke-dashoffset:0}
  .flu-splash .iso-rect,.flu-splash .iso-dot{opacity:1;transform:none}
  .flu-check .ring,.flu-check .tick,.flu-error .ring,.flu-error .cross,
  .flu-chart .line{stroke-dashoffset:0}
  .flu-chart .area,.flu-skel .real,.flu-empty .item{opacity:1}
  .flu-stagger > *{opacity:1;transform:none}
}
