/* motion.css — fase 7 del rediseño v3 (animaciones). Plan: ~/cerebro/dash-rediseno/PLAN.md (Mac).
   Va enlazada después de mobile.css. Su pareja es static/js/motion.js, que solo añade clases m-*,
   la variable --i/--mx/--my y elementos aria-hidden; sin JS, aquí solo quedan los hovers, el punto
   vivo, la transición entre páginas y los botones.
   Reglas: solo se anima transform/translate y opacity (el desenfoque de entrada de página es la
   única excepción, y solo en escritorio). Keyframes con prefijo m- para no chocar con los de los
   módulos (pulse, fadeUp, livePing, spin...). Al final, el bloque de prefers-reduced-motion.
   Módulos con animación propia fuera: [data-motion-off], ÓRBITA (.orbita), oficina (.office-page)
   y grafo (.graph-wrap). */

:root {
    --ease-out: cubic-bezier(.22,1,.36,1);
    --ease-spring: cubic-bezier(.34,1.56,.64,1);
    --dur-1: .15s;
    --dur-2: .28s;
    --dur-3: .6s;
    --lift: -5px;
    --stagger: 45ms;
    --m-rise: 10px;
    --m-glare-c: rgba(255,255,255,0.075);
}
:root[data-theme="light"] { --m-glare-c: rgba(255,255,255,0.95); }
@media (max-width: 768px) { :root { --m-rise: 6px; } }

/* ── Tarjetas: suben al pasar el ratón ─────────────────────────────────────
   translate (no transform): se suma a cualquier transform que ya tenga la tarjeta.
   Fuera: anidadas, con menú/modal dentro (un translate convierte la tarjeta en contenedor de
   los position:fixed de dentro) y las que ya mueven solas (.task-item, .email-card). */
@media (hover: hover) and (pointer: fine) {
    .main-content :is(.card, .stat, .kpi, .g-card, .vital, .m-card) {
        transition: translate var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out),
                    box-shadow var(--dur-2) var(--ease-out), border-color var(--transition),
                    background-color var(--transition), color var(--transition);
    }
    .main-content :is(.card, .stat, .kpi, .g-card, .vital, .m-card):not(:is(.card, .stat, .kpi, .g-card, .vital, .m-card, .modal-box) *):not(:is([data-motion-off], .orbita, .office-page, .graph-wrap) *):not(.task-item, .email-card, [data-motion-off]):not(:has(.open, [open], [aria-expanded="true"], .show, [class*="modal"], [role="dialog"], dialog)):hover {
        translate: 0 var(--lift);
        box-shadow: var(--shadow-lg), var(--hover-glow);
    }
}

/* ── Entrada escalonada (la pone motion.js: .m-in + --i) ──────────────────
   backwards: antes de empezar se ve el «desde»; al acabar no queda transform puesto. */
@keyframes m-up {
    from { opacity: 0; transform: translateY(var(--m-rise)); }
    to   { opacity: 1; transform: none; }
}
.m-in {
    animation: m-up var(--dur-3) var(--ease-out) backwards;
    animation-delay: calc(var(--i, 0) * var(--stagger));
}

/* ── Transición entre páginas (View Transitions entre documentos) ─────────
   La sidebar y la cápsula móvil tienen nombre propio y no se funden; la píldora del activo
   (.m-pill) se desliza de su sitio viejo al nuevo. NUNCA view-transition-name en .main-content:
   dejaría los modales debajo de la sidebar. Firefox no lo soporta y simplemente no anima. */
@view-transition { navigation: auto; }

@keyframes m-vt-out { to { opacity: 0; } }
@keyframes m-vt-in  { from { opacity: 0; transform: translateY(8px); } }
@keyframes m-vt-in-blur { from { opacity: 0; transform: translateY(8px); filter: blur(4px); } }

::view-transition-old(root) { animation: m-vt-out 160ms var(--ease-out) both; }
::view-transition-new(root) { animation: m-vt-in 240ms var(--ease-out) both; }
@media (min-width: 769px) {
    ::view-transition-new(root) { animation-name: m-vt-in-blur; }
    .sidebar { view-transition-name: m-sidebar; }
}
@media (max-width: 768px) {
    .mobile-topbar { view-transition-name: m-topbar; }
}
::view-transition-group(m-pill),
::view-transition-group(m-tabpill) { animation-duration: .34s; animation-timing-function: var(--ease-out); }
::view-transition-group(m-sidebar),
::view-transition-group(m-topbar),
::view-transition-group(m-tabbar) { animation-duration: 0s; }
/* Mismo contenido a los dos lados: sin fundido, para que el vidrio no parpadee */
::view-transition-old(m-sidebar), ::view-transition-old(m-topbar), ::view-transition-old(m-tabbar) { animation: none; opacity: 0; }
::view-transition-new(m-sidebar), ::view-transition-new(m-topbar), ::view-transition-new(m-tabbar) { animation: none; }

/* ── Píldora deslizante del activo (sidebar) ──────────────────────────────
   motion.js la inserta en .sidebar y le da translate/ancho/alto del enlace activo. Copia el
   aspecto de .sidebar a.active de skin-glass (fase 3); con ella puesta, el activo se queda sin
   fondo propio. z-index:-1 dentro del contexto de apilamiento de la sidebar (sticky + z-index). */
.m-pill {
    position: absolute;
    top: 0;
    left: 0;
    z-index: -1;
    border-radius: var(--radius-sm);
    background: var(--accent-soft);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 32%, transparent);
    pointer-events: none;
    view-transition-name: m-pill;
}
.m-pill[hidden] { display: none; }
.m-pill.m-ready { transition: transform var(--dur-2) var(--ease-out), height var(--dur-2) var(--ease-out), width var(--dur-2) var(--ease-out); }
.sidebar.m-has-pill a.active,
.sidebar.m-has-pill a.active:hover { background: transparent; box-shadow: none; }
/* En móvil el cajón entra y sale: la píldora no viaja entre páginas */
@media (max-width: 768px) { .m-pill { view-transition-name: none; } }

/* Lo mismo en las .tab-bar (todas son enlaces que recargan con ?tab=) */
.tab-bar.m-has-tabpill { position: relative; isolation: isolate; }
.m-tabpill {
    position: absolute;
    top: 0;
    left: 0;
    z-index: -1;
    border-radius: var(--pill);
    background: var(--seg-on);
    box-shadow: var(--seg-on-shadow);
    pointer-events: none;
}
.m-tabpill[hidden] { display: none; }
.m-tabpill.m-ready { transition: transform var(--dur-2) var(--ease-out), width var(--dur-2) var(--ease-out); }
.tab-bar.m-has-tabpill .tab-btn.active,
.tab-bar.m-has-tabpill .tab-btn.active:hover { background: transparent; box-shadow: none; }

/* ── Punto «en vivo»: anillo que se expande y se apaga ──────────────────── */
@keyframes m-ring {
    from { transform: scale(1); opacity: .55; }
    to   { transform: scale(2.6); opacity: 0; }
}
.live-dot, .live-dot--pulse { position: relative; }
.live-dot::after, .live-dot--pulse::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: var(--m-ring, var(--green));
    pointer-events: none;
    animation: m-ring 2s var(--ease-out) infinite;
}

/* ── Reflejo de luz que sigue al ratón ────────────────────────────────────
   motion.js pone .m-glare y --mx/--my en la tarjeta bajo el cursor. No se usan ::before/::after
   (las .g-card y .vital de la home ya los gastan) ni se toca su background: se re-valora el token
   de fondo de vidrio solo en esa tarjeta, así que una tarjeta con fondo propio de su módulo
   simplemente no brilla. Los descendientes recuperan el token original. */
@media (hover: hover) and (pointer: fine) {
    :root { --m-base-card: var(--glass-card); --m-base-bg: var(--glass-bg); }
    .m-glare {
        --glass-card: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%), var(--m-glare-c), transparent 70%), var(--m-base-card);
        --glass-bg: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%), var(--m-glare-c), transparent 70%), var(--m-base-bg);
    }
    .m-glare * { --glass-card: var(--m-base-card); --glass-bg: var(--m-base-bg); }
}

/* ── Botones primarios: brillo, se encogen al pulsar y barrido de luz ──────
   ::after es del spinner de .is-loading: el barrido va en ::before. */
:where(.btn-primary, .btn-action, .chat-send) { position: relative; overflow: hidden; isolation: isolate; }
.btn-primary, .btn-action, .chat-send {
    transition: box-shadow var(--dur-2) var(--ease-out), filter var(--transition), transform var(--dur-1) var(--ease-out);
}
.btn-primary:not(:disabled):active, .btn-action:not(:disabled):active, .chat-send:not(:disabled):active {
    transform: scale(.97);
}
@media (hover: hover) and (pointer: fine) {
    .btn-primary:not(:disabled):hover, .btn.btn-primary:not(:disabled):hover,
    .btn-action:not(:disabled):hover, .chat-send:not(:disabled):hover {
        box-shadow: 0 0 0 1px var(--accent2), 0 8px 28px var(--accent-glow);
    }
    .btn-primary::before, .btn-action::before, .chat-send::before {
        content: "";
        position: absolute;
        inset: 0;
        background: linear-gradient(105deg, transparent 30%, rgba(255,255,255,0.32) 50%, transparent 70%);
        transform: translateX(-120%);
        pointer-events: none;
    }
    .btn-primary:not(:disabled):hover::before, .btn-action:not(:disabled):hover::before,
    .chat-send:not(:disabled):hover::before {
        transform: translateX(120%);
        transition: transform var(--dur-3) var(--ease-out);
    }
}

/* ── Contador ascendente: cifras de ancho fijo para que no bailen ───────── */
:is(.stat-num, .kpi-value, .v-val, [data-countup]) { font-variant-numeric: tabular-nums; }

/* ── Menos movimiento: nada se mueve ──────────────────────────────────────
   :where() deja la especificidad a 0; el !important es lo que gana. Los pseudoelementos van
   fuera del :where() (dentro no son válidos y se descartarían). */
@media (prefers-reduced-motion: reduce) {
    :where(*), :where(*)::before, :where(*)::after {
        animation: none !important;
        transition-duration: 0s !important;
        scroll-behavior: auto !important;
    }
    @view-transition { navigation: none; }
    :where(.sidebar, .mobile-topbar, .m-pill) { view-transition-name: none !important; }
    .main-content :is(.card, .stat, .kpi, .g-card, .vital, .m-card):hover { translate: none; }
    .live-dot::after, .live-dot--pulse::after, .btn-primary::before, .btn-action::before, .chat-send::before { display: none; }
}
