﻿/* ═══ La perrovaquita — BASE Y PERSONAJE ═══════════════════════════════════
   Una cachorra dálmata regordeta con cuernitos y manchas de vaca. Vive a nivel de
   layout y acompaña al usuario en todas las pantallas, salvo donde la vista pida lo
   contrario.

   ESTA CARPETA REPARTE EL CSS EN UNA HOJA POR RESPONSABILIDAD, y esta es la
   primera. Eran 1.150 líneas en un archivo y encontrar una regla obligaba a bajar
   por medio dibujo:

     · base.css      variables, temas, contenedor, las vistas y las piezas del
                     animal. Lo que el personaje ES.
     · poses.css     las posturas persistentes y sus adornos (burbuja del sueño).
     · una hoja por conducta y animos.css. Lo que el personaje HACE.
     · interfaz.css  barra de acciones, corazones, minimizada, visitante,
                     responsive y menos movimiento. Lo que le RODEA.

   El ORDEN DE CARGA en el layout es obligatorio y está documentado allí y en
   poses.css: las poses y conductas sobreescriben propiedades declaradas aquí
   —animation, transform— y con la misma especificidad gana la última hoja.

   SEIS VISTAS EN UN SOLO SVG, y solo una visible a la vez:
     · FRENTE   sentada mirándote. Casi todo —conductas, ánimos, caricia— ocurre
                aquí. Su marcado está en Views/Shared/Mascota/_MascotaFrente.cshtml.
     · ECHADA   ÚNICAMENTE con la pose echado: tumbada, con la misma cabeza y las
                mismas clases que el frente. En _MascotaEchada.cshtml.
     · PERFIL   ÚNICAMENTE mientras camina. Un animal de frente que se desplaza de
                lado se ve deslizando, no andando. En _MascotaPerfil.cshtml.
     · DORMIDA  ÚNICAMENTE con la pose durmiendo: enroscada con su burbujita. En
                _MascotaDormida.cshtml.
     · PARADA y PARADA DE PERFIL, erguida en dos patas. Sus reglas, en poses.css.
   El cambio es un display, no hay JavaScript que las alterne.

   LA TERNURA ESTÁ EN LAS PROPORCIONES: cabeza enorme, hocico bajo, ojos grandes,
   patas cortas. Y el MOVIMIENTO manda tanto como el dibujo: aplastar y estirar en
   vez de solo girar, y retardo en lo blando —orejas, papada, colgante— para que no
   llegue todo a la vez.

   TRES EJES INDEPENDIENTES, tres familias de clases que no se pisan:
     · ÁNIMO    --saciada / --hambrienta / --triste. Lo dice el servidor.
     · POSE     --pose-pie / --pose-sentado / --pose-echado / --pose-durmiendo /
                --pose-parada / --pose-parada-perfil.
     · CONDUCTA --caminando / --rascando / --sacudiendo / --olfateando /
                --bostezando / --siguiendo / --acariciando / --contenta.
   La alegría es del CLIENTE: --contenta y --acariciando las pone interacciones.js y
   no viajan en el estado.

   COLORES: los del personaje van escritos, igual que los metales del podio: son del
   personaje, no de la interfaz. Cada uno con su contraparte para el tema oscuro. Lo
   que sí sale de la paleta es la barra de acciones, que sí es interfaz.

   EL VOLUMEN va en los degradados de _Mascota.cshtml, que las piezas usan como
   atributo fill. Por eso aquí NO se declara relleno para el cuerpo, el cráneo, las
   ancas, las orejas, el hocico ni los ojos: una regla de hoja pisaría al atributo y
   la pieza volvería a ser plana. Sus colores salen de las clases __tono-* de abajo,
   que leen estas mismas variables y cambian con el tema.

   NO TAPA LA PÁGINA: el contenedor no intercepta el puntero. Solo lo hacen el
   animal y su barra.
   ═══════════════════════════════════════════════════════════════════════════ */

.edu-mascota {
    --pv-cuerpo: #fdfcf9;
    --pv-pecho: #ffffff;
    --pv-mancha: #2f2f39;
    --pv-borde: #23232b;
    --pv-hocico: #f6c9c9;
    --pv-rosa: #f19bb0;
    --pv-nariz: #2f2530;
    --pv-cuerno: #dcccaa;
    --pv-corazon: #e8557a;
    --pv-lengua: #e4738b;
    --pv-collar: #3f8fe0;
    --pv-ojo: #3a2a26;
    /* Luces y sombras de los degradados. */
    --pv-pelaje-luz: #ffffff;
    --pv-pelaje-sombra: #eee9e0;
    --pv-oreja-raiz: #3c3c49;
    --pv-ojo-luz: #5b4035;
    --pv-blanco-sombra: #e4e0ec;
    --pv-hocico-luz: #fde4e4;
    --pv-collar-brillo: #a9d0f7;
    --pv-sombra-contacto: rgba(90, 66, 40, .10);
    /* Opacidad del centro de la sombra del suelo: un número y no un color, porque
       el color es siempre negro y lo que cambia con el tema es cuánto se nota. */
    --pv-sombra-suelo: .24;
    --pv-x: 0px;
    --pv-cabeza-giro: 0deg;
    position: fixed;
    right: 1.25rem;
    bottom: 1rem;
    z-index: 1030; /* Por debajo de los modales de Bootstrap (1055). */
    display: flex;
    align-items: flex-end;
    gap: .5rem;
    /* Solo transform, nunca left ni right: mover el animal con propiedades de
       posición forzaría un recálculo de diseño en cada fotograma del paseo. */
    transform: translateX(var(--pv-x, 0px));
    pointer-events: none;
}

/* En oscuro SIGUE SIENDO BLANCA: un blanco apenas rebajado para que no deslumbre, y
   las sombras en gris neutro: con sombras de tono cálido, sobre fondo oscuro se
   leería color crema. */
[data-tema="oscuro"] .edu-mascota {
    --pv-cuerpo: #f3f3f5;
    --pv-pecho: #fbfbfc;
    --pv-mancha: #1c1c24;
    --pv-borde: #121218;
    --pv-hocico: #dda6a6;
    --pv-rosa: #d98da0;
    --pv-cuerno: #c2b18e;
    --pv-pelaje-luz: #ffffff;
    --pv-pelaje-sombra: #d9dbe1;
    --pv-oreja-raiz: #2a2a35;
    --pv-ojo-luz: #503830;
    --pv-blanco-sombra: #d9d5e2;
    --pv-hocico-luz: #e9bcbc;
    --pv-collar-brillo: #8fbef0;
    --pv-sombra-contacto: rgba(0, 0, 0, .11);
    /* Sobre fondo oscuro la sombra necesita más cuerpo para leerse. */
    --pv-sombra-suelo: .5;
}

/* ── Las tres vistas ──────────────────────────────────────────────────────── */
/* El perfil y la dormida están ocultos salvo en su momento: el perfil mientras
   camina, la dormida con la pose de dormir (el encendido de esa vive en poses.css,
   junto a su pose). Con display y no con opacidad: una vista invisible pero
   presente seguiría animándose y costando fotogramas. */
.edu-mascota__vista--perfil {
    display: none;
}

.edu-mascota__vista--dormida {
    display: none;
}

.edu-mascota--caminando .edu-mascota__vista--frente {
    display: none;
}

.edu-mascota--caminando .edu-mascota__vista--perfil {
    display: block;
}

/* ── El animal ────────────────────────────────────────────────────────────── */
.edu-mascota__cuerpo-boton {
    pointer-events: auto;
    position: relative;
    padding: 0;
    border: 0;
    background: none;
    line-height: 0;
    /* El cursor invita a tocarla, no a pulsarla: acariciar es pasar la mano. */
    cursor: grab;
    transition: transform .2s ease;
}

.edu-mascota--acariciando .edu-mascota__cuerpo-boton {
    cursor: grabbing;
}

/* El perfil mira a la IZQUIERDA, así que caminar hacia la derecha exige espejarlo.
   Solo el animal: la barra no se voltea, o el texto saldría al revés. */
.edu-mascota--mirando-derecha.edu-mascota--caminando .edu-mascota__cuerpo-boton {
    transform: scaleX(-1);
}

/* El SVG entero solo se anima en lo que mueve al animal completo: alzarse y el
   salto de alegría. La respiración vive en __aliento y __cabeza-aliento: aquí la
   pisaría el alzarse, y un ánimo que la alargara alzaría a cámara lenta. */
.edu-mascota__svg {
    width: 8.5rem;
    height: auto;
    display: block;
    overflow: visible;
    transform-origin: center bottom;
}

/* Al volver a la vista de frente —al despertar, al levantarse de echada, al
   acabar un paseo— se asienta con un aplastado corto. Es lo que convierte el
   cambio de dibujo en un movimiento y no en un corte de montaje. Al cargar la
   página también ocurre, una vez, y se lee como que llega. */
.edu-mascota__vista--frente {
    transform-origin: 70px 146px;
    animation: edu-pv-asentarse .45s cubic-bezier(.3, 1.4, .6, 1) 1 both;
}

@keyframes edu-pv-asentarse {
    0% {
        transform: translateY(-3px) scale(.97, 1.04);
    }

    55% {
        transform: translateY(0) scale(1.03, .97);
    }

    100% {
        transform: none;
    }
}

/* ── Respiración ──────────────────────────────────────────────────────────── */
/* El cuerpo se ensancha al llenarse, desde el suelo: es scaleX sobre scaleY
   invertido, no un escalado uniforme, que se leería como zoom. La cabeza sube un
   pelo con retardo, que es lo que hace que el cuerpo empuje y ella acompañe. Las
   dos llevan la misma duración: cada ánimo y cada pose que la cambia, cambia las
   dos. */
.edu-mascota__aliento {
    transform-origin: 70px 146px;
    animation: edu-pv-aliento 3.6s cubic-bezier(.45, 0, .55, 1) infinite;
}

.edu-mascota__cabeza-aliento {
    animation: edu-pv-cabeza-aliento 3.6s cubic-bezier(.45, 0, .55, 1) .18s infinite;
}

@keyframes edu-pv-aliento {
    0%, 100% {
        transform: scale(1, 1);
    }

    42% {
        transform: scale(1.022, .988);
    }
}

@keyframes edu-pv-cabeza-aliento {
    0%, 100% {
        transform: translateY(0);
    }

    42% {
        transform: translateY(-.9px);
    }
}

/* ── Articulaciones ───────────────────────────────────────────────────────── */
/* Los orígenes van en coordenadas del viewBox y NO con transform-box: fill-box: la
   articulación real casi nunca coincide con el centro de la caja del grupo. Con
   fill-box, contonearse habría girado a la perra por el aire.

   Se resuelven en el sistema LOCAL de cada grupo: en las vistas que reutilizan la
   cabeza del frente colocada con un transform —echada, parada—, (70,86) sigue
   siendo la nuca de esa cabeza y no un punto fijo del lienzo. */
.edu-mascota__tronco {
    transform-origin: 70px 138px;
}

/* LA CABEZA EN CUATRO CAPAS (el porqué, en _MascotaFrente.cshtml). Las tres giran
   sobre la base del cráneo, donde se encuentra con el cuello. */
.edu-mascota__cabeza,
.edu-mascota__cabeza-gesto,
.edu-mascota__cabeza-ladeo {
    transform-origin: 70px 86px;
}

/* Los ESTADOS: transform fijo y transición, sin animación en este grupo. Por eso
   entrar en un estado y salir de él se desliza, con un pelo de rebote al llegar.
   Seguir el cursor usa la propiedad rotate y no transform: así se suma a un estado
   que ya incline la cabeza —hambrienta la sigue mirando— en vez de anularlo. */
.edu-mascota__cabeza {
    transition: transform .45s cubic-bezier(.3, 1.25, .6, 1), rotate .32s cubic-bezier(.25, .8, .35, 1);
}

.edu-mascota--siguiendo .edu-mascota__cabeza {
    rotate: var(--pv-cabeza-giro, 0deg);
}

/* El vaivén de mirar alrededor. De frente, mirar es LADEAR la cabeza, que además es
   el gesto más tierno que hace un perro; de perfil sería girarla, y no se vería.
   Llega un poco más allá de cada lado y se asienta, como una cabeza con peso. */
.edu-mascota__cabeza-ladeo {
    animation: edu-pv-mirar 6.8s infinite;
}

@keyframes edu-pv-mirar {
    0% {
        transform: rotate(0deg);
        animation-timing-function: cubic-bezier(.45, 0, .4, 1);
    }

    22% {
        transform: rotate(-6.8deg);
        animation-timing-function: cubic-bezier(.4, 0, .5, 1);
    }

    29% {
        transform: rotate(-5.6deg);
        animation-timing-function: cubic-bezier(.45, 0, .4, 1);
    }

    54% {
        transform: rotate(5.8deg);
        animation-timing-function: cubic-bezier(.4, 0, .5, 1);
    }

    61% {
        transform: rotate(4.7deg);
        animation-timing-function: cubic-bezier(.45, 0, .4, 1);
    }

    88%, 100% {
        transform: rotate(0deg);
    }
}

/* Mientras otra capa manda sobre la cabeza, el vaivén se PAUSA en vez de quitarse:
   quitarlo la haría saltar al ángulo de arranque, y pausado se reanuda donde iba.
   Cada conducta que mueve la cabeza añade su clase aquí desde su propia hoja. */
.edu-mascota--siguiendo .edu-mascota__cabeza-ladeo {
    animation-play-state: paused;
}

/* ── Piezas del cuerpo ────────────────────────────────────────────────────── */
/* El relleno de la sombra es un degradado del marcado (pv-sombra-suelo). */
.edu-mascota__sombra {
    transform-origin: 70px 146px;
    transition: transform .45s ease;
}

/* ── Los tonos de los degradados ──────────────────────────────────────────── */
/* Cada stop de _Mascota.cshtml lleva una de estas clases: el degradado no tiene un
   solo color escrito, así que cambia con el tema como el resto del personaje. */
.edu-mascota__tono-pelaje-luz {
    stop-color: var(--pv-pelaje-luz);
}

.edu-mascota__tono-pelaje {
    stop-color: var(--pv-cuerpo);
}

.edu-mascota__tono-pelaje-sombra {
    stop-color: var(--pv-pelaje-sombra);
}

.edu-mascota__tono-oreja-raiz {
    stop-color: var(--pv-oreja-raiz);
}

.edu-mascota__tono-mancha {
    stop-color: var(--pv-mancha);
}

.edu-mascota__tono-ojo-luz {
    stop-color: var(--pv-ojo-luz);
}

.edu-mascota__tono-ojo {
    stop-color: var(--pv-ojo);
}

.edu-mascota__tono-blanco-sombra {
    stop-color: var(--pv-blanco-sombra);
}

/* El blanco del ojo es blanco en los dos temas, como sus brillos: es la luz del
   ojo, no la piel. */
.edu-mascota__tono-blanco {
    stop-color: #fff;
}

.edu-mascota__tono-hocico-luz {
    stop-color: var(--pv-hocico-luz);
}

.edu-mascota__tono-hocico {
    stop-color: var(--pv-hocico);
}

/* La sombra del suelo es negra en los dos temas; lo que cambia es su opacidad. */
.edu-mascota__tono-sombra-centro {
    stop-color: #000;
    stop-opacity: var(--pv-sombra-suelo);
}

.edu-mascota__tono-sombra-medio {
    stop-color: #000;
    stop-opacity: calc(var(--pv-sombra-suelo) * .45);
}

.edu-mascota__tono-sombra-borde {
    stop-color: #000;
    stop-opacity: 0;
}

/* El cuello reutiliza la clase del cráneo a propósito: necesita exactamente lo
   mismo —degradado de cuerpo y borde— y una clase propia solo duplicaría la regla.
   Solo el contorno: el relleno es el degradado del atributo. */
.edu-mascota__cuerpo-forma,
.edu-mascota__craneo,
.edu-mascota__anca,
.edu-mascota__pata-del,
.edu-mascota__pie-forma,
.edu-mascota__zarpa {
    stroke: var(--pv-borde);
    stroke-width: 2.5;
    stroke-linejoin: round;
}

/* Las patas delanteras en dos piezas: el relleno sin contorno, que la máscara funde
   con el pecho por arriba, y el contorno como trazo abierto. */
.edu-mascota__pata-frente {
    stroke: none;
}

/* La base lisa de las patas cercanas del perfil: el color del cuerpo, sin borde,
   para que su parte de dentro del cuerpo no se note. */
.edu-mascota__pata-base {
    fill: var(--pv-cuerpo);
    stroke: none;
}

.edu-mascota__pata-frente-borde {
    stroke: var(--pv-borde);
    stroke-width: 2.5;
    stroke-linejoin: round;
    stroke-linecap: round;
}

/* Los deditos de los pies y el pliegue de la manita doblada de la parada de
   perfil: el mismo trazo fino del contorno. */
.edu-mascota__dedos,
.edu-mascota__pliegue {
    stroke: var(--pv-borde);
}

/* La sombra que la barbilla deja sobre el cuello y el pecho. */
.edu-mascota__sombra-contacto {
    fill: var(--pv-sombra-contacto);
}

/* El pecho claro va SIN contorno: con borde parecería una pieza pegada encima, y lo
   que tiene que parecer es el mismo pelo más claro. */
.edu-mascota__pecho {
    fill: var(--pv-pecho);
}

.edu-mascota__mancha {
    fill: var(--pv-mancha);
}

.edu-mascota__collar {
    stroke: var(--pv-collar);
}

.edu-mascota__collar-brillo {
    stroke: var(--pv-collar-brillo);
    opacity: .7;
}

.edu-mascota__colgante {
    fill: var(--pv-corazon);
    stroke: var(--pv-borde);
    stroke-width: 1.5;
    transform-box: fill-box;
    transform-origin: top center;
    /* Cuelga, así que se balancea con retardo: como todo lo blando. */
    transition: transform .5s cubic-bezier(.22, 1.5, .5, 1) .08s;
}

.edu-mascota__cuerno {
    stroke: var(--pv-cuerno);
}

/* Silueta fina del cuerno: el mismo trazo, debajo y un poco más ancho, en el
   color del contorno. Un trazo sin relleno no admite borde propio. */
.edu-mascota__cuerno-borde {
    stroke: var(--pv-borde);
}

.edu-mascota__cola {
    stroke: var(--pv-cuerpo);
    transform-origin: 110px 130px;
    animation: edu-pv-cola 1.9s cubic-bezier(.45, .05, .55, .95) infinite;
}

/* Llega un poco más allá y rebota antes de volver: una cola tiene peso y no frena
   en seco en cada extremo. */
@keyframes edu-pv-cola {
    0%, 100% {
        transform: rotate(-11deg);
    }

    42% {
        transform: rotate(15deg);
    }

    52% {
        transform: rotate(12.5deg);
    }

    90% {
        transform: rotate(-13deg);
    }
}

/* ── Orejas ───────────────────────────────────────────────────────────────── */
.edu-mascota__oreja {
    transform-box: fill-box;
    /* Nacen en el borde superior de su propia caja, así que aquí fill-box y el
       nacimiento coinciden. */
    transform-origin: top center;
    /* La curva rebasa y vuelve: una oreja larga no frena en seco. El retardo la hace
       ir por detrás del movimiento de la cabeza. */
    transition: transform .5s cubic-bezier(.22, 1.5, .5, 1) .05s;
}

/* Un pelo de desfase entre las dos: sincronizadas parecen una sola pieza rígida
   atravesando el cráneo. */
.edu-mascota__oreja--der {
    transition-delay: .1s;
}

/* El relleno es el degradado pv-oreja del marcado. */
.edu-mascota__oreja-forma {
    stroke: var(--pv-borde);
    stroke-width: 2.5;
    stroke-linejoin: round;
}

.edu-mascota__oreja-dentro {
    fill: var(--pv-rosa);
    opacity: .85;
}

/* ── Cara ─────────────────────────────────────────────────────────────────── */
.edu-mascota__morro {
    transform-origin: 70px 60px;
    transition: transform .3s ease;
}

/* Vale para la elipse ancha de la vista de frente y para el trazo AFILADO del
   perfil, que se estrecha hacia la punta. El linejoin es para ese segundo caso: al
   dejar de ser una elipse y pasar a ser un path con esquinas, sin él la punta del
   hocico sale picuda en lugar de redondeada. */
.edu-mascota__morro-forma {
    stroke: var(--pv-borde);
    stroke-width: 2.5;
    stroke-linejoin: round;
}

.edu-mascota__nariz {
    fill: var(--pv-nariz);
    stroke: var(--pv-borde);
    stroke-width: 1.5;
    stroke-linejoin: round;
}

/* El reflejo que hace húmeda a la nariz. Blanco en los dos temas, como los brillos
   de los ojos: es luz, no piel. */
.edu-mascota__nariz-brillo {
    fill: #fff;
    opacity: .6;
}

.edu-mascota__boca {
    stroke: var(--pv-borde);
    transition: stroke-width .3s ease;
}

.edu-mascota__lengua {
    fill: var(--pv-lengua);
    stroke: var(--pv-borde);
    stroke-width: 1.6;
    stroke-linejoin: round;
    transform-box: fill-box;
    transform-origin: center top;
    transform: scaleY(0);
    transition: transform .25s ease;
}

/* Blanco e iris llevan su degradado en el marcado (pv-blanco y pv-iris). */
.edu-mascota__ojo-blanco {
    stroke: var(--pv-borde);
    stroke-width: 2;
}

/* LA MIRADA: pupila y brillos juntos. Mientras sigue al cursor se desplazan hacia
   él con las dos variables que escribe el JS; al dejar de seguirlo vuelven solas al
   centro con la transición, sin que el JS tenga que ponerlas a cero. Con la
   propiedad translate y no transform, para que no pise a nada que escale la pupila.
   El recorte del ojo impide que asome por fuera del blanco. */
.edu-mascota__mirada {
    transition: translate .28s cubic-bezier(.2, .8, .2, 1);
}

.edu-mascota--siguiendo .edu-mascota__mirada {
    translate: var(--pv-mirada-x, 0px) var(--pv-mirada-y, 0px);
}

/* Dos brillos por ojo: es lo que convierte un punto negro en una mirada húmeda. */
.edu-mascota__brillo {
    fill: #fff;
    pointer-events: none;
}

.edu-mascota__brillo--menor {
    opacity: .75;
}

/* Las pestañas leen a la mascota como hembra, y cuestan seis trazos. La vista
   dormida reutiliza esta clase para sus ojos cerrados: necesita exactamente este
   trazo y nada más. */
.edu-mascota__pestana {
    stroke: var(--pv-borde);
    transform-box: fill-box;
    transform-origin: center;
    transition: transform .3s ease;
}

/* Las cejas son lo más expresivo de la cara y lo más barato de animar. */
.edu-mascota__ceja {
    stroke: var(--pv-mancha);
    transform-box: fill-box;
    transform-origin: center;
    transition: transform .3s ease;
}

/* ── Párpados ─────────────────────────────────────────────────────────────── */
/* EL PÁRPADO ES UNA PERSIANA DENTRO DEL OJO: piel por arriba y la línea de la
   pestaña por borde, recortados por la silueta del ojo. Baja DESPLAZÁNDOSE, no
   escalándose: escalado, el borde curvo se aplanaría y la línea de la pestaña
   adelgazaría. Y el recorte es el que impide que su contorno asome por fuera del
   ojo, que lo haría leerse como una nube pegada encima.

   DOS CAPAS, como la cabeza: __parpado lleva el ESTADO —cuánto cierra— y
   __parpado-parpadeo el parpadeo, que se suma. Así un ojo entornado de gusto o de
   hambre sigue parpadeando, y entrar o salir de un estado se desliza.

   Cuánto cierra lo dice --pv-parpado-cierre, de 0 (abierto) a 1 (cerrado), que
   ponen los estados en la raíz: una sola regla por estado mueve todos los
   párpados de todas las vistas. 27 unidades es el alto del ojo del frente; los
   ojos más pequeños colocan su párpado con una escala en el marcado. */
.edu-mascota__parpado {
    transform: translateY(calc((var(--pv-parpado-cierre, 0) - 1) * 27px));
    transition: transform .24s ease-out, rotate .3s ease;
}

/* Cada uno inclina sobre el centro de su ojo, que es lo que usa triste. */
.edu-mascota__parpado--izq {
    transform-origin: 52px 46px;
}

.edu-mascota__parpado--der {
    transform-origin: 88px 46px;
}

.edu-mascota__parpado-borde {
    stroke: var(--pv-borde);
}

/* Parpadeo natural: cierra rápido y abre despacio, y de vez en cuando parpadea dos
   veces seguidas. Uno a intervalos exactos se lee como un reloj. */
.edu-mascota__parpado-parpadeo {
    animation: edu-pv-parpadeo 7.6s infinite;
}

@keyframes edu-pv-parpadeo {
    0%, 38% {
        transform: translateY(0);
        animation-timing-function: cubic-bezier(.55, 0, 1, .45);
    }

    39.3% {
        transform: translateY(27px);
        animation-timing-function: cubic-bezier(0, .55, .45, 1);
    }

    41.8% {
        transform: translateY(0);
    }

    86% {
        transform: translateY(0);
        animation-timing-function: cubic-bezier(.55, 0, 1, .45);
    }

    87.3% {
        transform: translateY(27px);
        animation-timing-function: cubic-bezier(0, .55, .45, 1);
    }

    89.4% {
        transform: translateY(0);
        animation-timing-function: cubic-bezier(.55, 0, 1, .45);
    }

    90.7% {
        transform: translateY(27px);
        animation-timing-function: cubic-bezier(0, .55, .45, 1);
    }

    93.2%, 100% {
        transform: translateY(0);
    }
}

/* ── Piezas exclusivas del perfil ─────────────────────────────────────────── */
.edu-mascota__p-cuerpo {
    /* La base del cuerpo, donde apoya: el trote comprime hacia el suelo. */
    transform-origin: 94px 128px;
}

.edu-mascota__p-cabeza {
    /* La nuca, donde el cráneo se solapa con el cuello. */
    transform-origin: 70px 80px;
}

/* Las patas del perfil son formas con RELLENO Y BORDE, no trazos: un trazo del
   color del cuerpo y sin contorno queda blanco sobre blanco, invisible; y a una forma
   sin relleno declarado el SVG la pinta negra.

   La clase va en el GRUPO de cada pata: lo que lleva dentro hereda de aquí el borde,
   y también el relleno salvo en las patas cercanas, que traen su degradado en el
   marcado. */
.edu-mascota__p-pata {
    fill: var(--pv-cuerpo);
    stroke: var(--pv-borde);
    stroke-width: 2.5;
}

/* Cada pata gira desde su articulación, que es el CENTRO DE SU BORDE SUPERIOR, el
   que queda escondido bajo el cuerpo. Sin transform-origin, en SVG el origen
   resuelve contra el (0,0) del viewBox y la pata giraría desde la esquina del
   dibujo.

   ESTOS CUATRO VALORES DEPENDEN DEL MARCADO de _MascotaPerfil.cshtml. Si allí se
   mueve o se estrecha el nacimiento de una pata, aquí hay que recalcular su origen:
   con el origen desfasado, al trotar la pata gira descolgada del cuerpo. */
.edu-mascota__p-pata--del {
    /* Nace entre x=69.75 y x=85.25 → 77.5 */
    transform-origin: 77.5px 116px;
}

.edu-mascota__p-pata--del-lejos {
    /* Nace entre x=83.75 y x=96.25 → 90 */
    transform-origin: 90px 114px;
}

.edu-mascota__p-pata--tras {
    /* Nace entre x=97.25 y x=114.75 → 106 */
    transform-origin: 106px 116px;
}

.edu-mascota__p-pata--tras-lejos {
    /* Nace entre x=103.25 y x=116.75 → 110 */
    transform-origin: 110px 114px;
}

/* Las del lado lejano, en el tono de sombra del pelaje y con su contorno entero:
   más apagadas se distinguen de las cercanas, que es lo que evita que cuatro patas
   iguales se lean como un amasijo. Translúcidas y sin contorno firme se leerían como
   la sombra del animal, no como patas. */
.edu-mascota__p-pata--tras-lejos,
.edu-mascota__p-pata--del-lejos {
    fill: var(--pv-pelaje-sombra);
}

/* La pata trasera lejana de la parada de perfil, como las lejanas del perfil que
   camina: tono de sombra del pelaje y contorno entero. En el grupo, que lleva el pie
   y el muslo, para que las dos piezas compartan estilo. */
.edu-mascota__pp-pata-lejos {
    fill: var(--pv-pelaje-sombra);
    stroke: var(--pv-borde);
    stroke-width: 2.5;
    stroke-linejoin: round;
}

.edu-mascota__p-oreja {
    transform-box: fill-box;
    transform-origin: top center;
    transition: transform .5s cubic-bezier(.22, 1.5, .5, 1) .05s;
}

/* La cola del perfil nace en otro punto que la de frente, y como solo hay una vista
   visible a la vez basta con reasignarle el origen aquí. */
.edu-mascota--caminando .edu-mascota__cola {
    transform-origin: 120px 96px;
}

/* El contorno de la cola: un trazo oscuro y más ancho por debajo del claro. Es la
   forma barata de dar borde a un trazo —paint-order no hace nada sobre un path sin
   relleno— y sin él la cola desaparecía sobre el cuerpo. */
.edu-mascota__cola--borde {
    stroke: var(--pv-borde);
}