/* ============================================================================
   EL PUNTO BEPP — componente de mascota
   Sustituye a bepp-mascot.js + los 18 GIFs de Beppina.

   Geometría (retícula 32): todo deriva de --punto-d.
     núcleo          D
     ancho de ojo    3D/32
     alto de ojo     9D/32        (razón 1:3)
     separación      D/4          (de centro a centro)
     hueco entre     5D/32

   Uso:
     <span class="bepp-punto bepp-punto--md" data-state="reposo" aria-hidden="true">
       <span class="bepp-punto__aura"></span>
       <span class="bepp-punto__ring bepp-punto__ring--a"></span>
       <span class="bepp-punto__ring bepp-punto__ring--b"></span>
       <span class="bepp-punto__core"><span class="bepp-punto__eyes"><i></i><i></i></span></span>
     </span>

   O deja que punto-bepp.js llene las entrañas: <span class="bepp-punto" data-state="..."></span>

   La caja mide D. Los anillos se desbordan hasta 3.2D — reservar ese espacio
   alrededor, o usar el modificador --reserva.
   ========================================================================= */

.bepp-punto {
  /* --- geometría --- */
  --punto-d: 64px;
  --punto-eye-w: calc(var(--punto-d) * 3 / 32);
  --punto-eye-h: calc(var(--punto-d) * 9 / 32);
  --punto-eye-gap: calc(var(--punto-d) * 5 / 32);
  --punto-ring-w: calc(var(--punto-d) / 38);

  /* --- color --- */
  --punto-core: #4FA3D8;
  --punto-hl:   #B5D8EF;
  --punto-sh:   #3A7FA9;
  --punto-halo: #7ED3F3;
  --punto-eye:  #FFFFFF;

  /* --- cadencia --- */
  --punto-beat: 3600ms;
  --punto-blink: 5200ms;

  position: relative;
  display: inline-grid;
  place-items: center;
  width: var(--punto-d);
  height: var(--punto-d);
  flex: none;
  vertical-align: middle;
}

/* En superficies blancas el núcleo baja un escalón para cruzar 3:1 (WCAG 1.4.11).
   Es un solo paso de luminosidad — nadie lo distingue lado a lado. */
.bepp-punto--producto {
  --punto-core: #3E96CF;
  --punto-hl:   #AAD3ED;
  --punto-sh:   #2E75A3;
}

/* Reserva el área que necesita el pulso: útil en splash y empty states. */
.bepp-punto--reserva {
  width: calc(var(--punto-d) * 3.2);
  height: calc(var(--punto-d) * 3.2);
}

/* --- tamaños --- */
.bepp-punto--xs     { --punto-d: 24px; }
.bepp-punto--sm     { --punto-d: 40px; }
.bepp-punto--md     { --punto-d: 64px; }
.bepp-punto--lg     { --punto-d: 96px; }
.bepp-punto--xl     { --punto-d: 128px; }
.bepp-punto--splash { --punto-d: min(40vw, 200px); }

/* Corrección óptica: abajo de 40px las rendijas se rasterizan a lodo.
   Engordan y se acortan; la separación de centros no se mueve. */
.bepp-punto--xs,
.bepp-punto--micro {
  --punto-eye-w: calc(var(--punto-d) * 4 / 32);
  --punto-eye-h: calc(var(--punto-d) * 8 / 32);
  --punto-eye-gap: calc(var(--punto-d) * 4 / 32);
}

/* 16px o menos: sin ojos. Una cara borrosa no se reconoce; un punto sí. */
.bepp-punto--favicon { --punto-d: 16px; }
.bepp-punto--favicon .bepp-punto__eyes { display: none; }

/* ---------- núcleo ---------- */

.bepp-punto__core {
  position: relative;
  z-index: 2;
  width: var(--punto-d);
  height: var(--punto-d);
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: radial-gradient(circle at 33% 26%,
    var(--punto-hl) 0%,
    var(--punto-core) 48%,
    var(--punto-sh) 100%);
  transition: background 320ms var(--ease-out, cubic-bezier(.16,1,.3,1));
}

/* La sombra de contacto vive fuera del núcleo — así nunca la recorta un mask.

   AJUSTE DEL LABORATORIO: antes era un box-shadow sobre una caja
   transparente del tamaño del núcleo. Un box-shadow exterior no se pinta
   debajo de su propia caja, así que la sombra tenía un hueco circular que
   sólo tapaba el núcleo mientras no se moviera. En cuanto el punto brinca,
   trota o se estira, el hueco se veía como un círculo de otro color.
   Ahora es una mancha llena y difuminada, sin hueco. Misma medida que el
   box-shadow original: 0.64D de diámetro (D - 2·0.18D), bajada 0.25D y
   difuminada 0.23D (la mitad del blur de 0.46D). Portar a la hoja. */
.bepp-punto__aura {
  position: absolute;
  z-index: 1;
  width: var(--punto-d);
  height: var(--punto-d);
  border-radius: 50%;
}
.bepp-punto__aura::before {
  content: "";
  position: absolute;
  inset: calc(var(--punto-d) * 0.18);
  border-radius: 50%;
  background: color-mix(in srgb, var(--punto-core) 80%, transparent);
  transform: translateY(calc(var(--punto-d) * 0.25));
  filter: blur(calc(var(--punto-d) * 0.23));
}

/* En fondos oscuros la sombra no aporta: se apaga. */
.bepp-punto--sin-sombra .bepp-punto__aura::before { display: none; }

/* ---------- anillos de pulso ---------- */

.bepp-punto__ring {
  position: absolute;
  z-index: 0;
  width: var(--punto-d);
  height: var(--punto-d);
  border-radius: 50%;
  border: var(--punto-ring-w) solid var(--punto-halo);
  opacity: 0;
  pointer-events: none;
}

@keyframes bepp-punto-ring {
  0%   { transform: scale(1);   opacity: 0.85; }
  70%  { opacity: 0; }
  100% { transform: scale(3.2); opacity: 0; }
}

@keyframes bepp-punto-beat {
  0%, 100% { transform: scale(1); }
  8%       { transform: scale(1.07); }
  16%      { transform: scale(1); }
}

/* ---------- ojos ---------- */

.bepp-punto__eyes {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--punto-eye-gap);
  transition: transform 320ms cubic-bezier(.16,1,.3,1);
}

.bepp-punto__eyes i {
  display: block;
  width: var(--punto-eye-w);
  height: var(--punto-eye-h);
  border-radius: calc(var(--punto-eye-w) / 2);
  background: var(--punto-eye);
  transform-origin: center;
  animation: bepp-punto-blink var(--punto-blink) ease-in-out infinite;
}

@keyframes bepp-punto-blink {
  0%, 91%, 100% { transform: scaleY(1); }
  94.5%         { transform: scaleY(0.08); }
}

/* ============================================================================
   LOS OCHO ESTADOS
   Regla dura: el punto NO cambia de color para celebrar. Cambia de color
   solo para detenerte. Éxito se lee por forma; error y alerta por color.
   ========================================================================= */

/* --- reposo · el default. Está ahí, está vivo, no pide nada --- */
.bepp-punto[data-state="reposo"] { --punto-beat: 3600ms; }
.bepp-punto[data-state="reposo"] .bepp-punto__core {
  animation: bepp-punto-beat var(--punto-beat) cubic-bezier(.4,0,.2,1) infinite;
}
.bepp-punto[data-state="reposo"] .bepp-punto__ring {
  animation: bepp-punto-ring var(--punto-beat) cubic-bezier(.2,.6,.3,1) infinite;
}
.bepp-punto[data-state="reposo"] .bepp-punto__ring--b {
  animation-delay: calc(var(--punto-beat) / 3);
}

/* --- escuchando · el usuario escribe o habla. Misma forma, triple cadencia --- */
.bepp-punto[data-state="escuchando"] { --punto-beat: 1100ms; --punto-blink: 2400ms; }
.bepp-punto[data-state="escuchando"] .bepp-punto__core {
  animation: bepp-punto-beat var(--punto-beat) cubic-bezier(.4,0,.2,1) infinite;
}
.bepp-punto[data-state="escuchando"] .bepp-punto__ring {
  animation: bepp-punto-ring var(--punto-beat) cubic-bezier(.2,.6,.3,1) infinite;
}
.bepp-punto[data-state="escuchando"] .bepp-punto__ring--b {
  animation-delay: calc(var(--punto-beat) / 3);
}

@keyframes bepp-punto-orbit { to { transform: rotate(360deg); } }

/* --- pensando · procesa sin barra de progreso. La mirada se va --- */
.bepp-punto[data-state="pensando"] .bepp-punto__eyes {
  transform: translate(calc(var(--punto-d) * -0.047), calc(var(--punto-d) * -0.062));
}
.bepp-punto[data-state="pensando"] .bepp-punto__ring--a {
  opacity: 1;
  width: calc(var(--punto-d) * 2);
  height: calc(var(--punto-d) * 2);
  border-style: dashed;
  animation: bepp-punto-orbit 9000ms linear infinite;
}
.bepp-punto[data-state="pensando"] .bepp-punto__ring--b { display: none; }

/* --- cargando · espera CON final. La diferencia con pensando es que este termina --- */
@keyframes bepp-punto-scan {
  0%, 100% { transform: translateX(calc(var(--punto-d) * -0.055)); }
  50%      { transform: translateX(calc(var(--punto-d) *  0.055)); }
}
.bepp-punto[data-state="cargando"] .bepp-punto__eyes {
  animation: bepp-punto-scan 1800ms ease-in-out infinite;
}
.bepp-punto[data-state="cargando"] .bepp-punto__ring--a {
  opacity: 1;
  width: calc(var(--punto-d) * 1.8);
  height: calc(var(--punto-d) * 1.8);
  border-color: transparent;
  border-top-color: var(--punto-halo);
  border-right-color: var(--punto-halo);
  animation: bepp-punto-orbit 900ms linear infinite;
}
.bepp-punto[data-state="cargando"] .bepp-punto__ring--b { display: none; }

/* --- éxito · el anillo se expande una vez y se queda. Los ojos se arquean --- */
@keyframes bepp-punto-lock {
  0%   { transform: scale(1);   opacity: 0.9; }
  100% { transform: scale(1.9); opacity: 1; }
}
.bepp-punto[data-state="exito"] .bepp-punto__ring--a {
  opacity: 1;
  border-width: calc(var(--punto-ring-w) * 1.4);
  animation: bepp-punto-lock 620ms cubic-bezier(.16,1,.3,1) forwards;
}
.bepp-punto[data-state="exito"] .bepp-punto__ring--b { display: none; }
.bepp-punto[data-state="exito"] .bepp-punto__eyes i {
  animation: none;
  background: transparent;
  width: calc(var(--punto-eye-w) * 1.45);
  height: calc(var(--punto-eye-h) * 0.26);
  border-top: calc(var(--punto-d) * 0.045) solid var(--punto-eye);
  border-radius: 50% 50% 0 0 / 100% 100% 0 0;
}

/* --- error · algo se rompió. Parpadeo duro, mirada plana --- */
@keyframes bepp-punto-crit { 0%, 100% { opacity: 1; } 45% { opacity: 0.25; } }
.bepp-punto[data-state="error"] {
  --punto-core: #D5544F;
  --punto-hl:   #EDB7B5;
  --punto-sh:   #9B4647;
}
.bepp-punto[data-state="error"] .bepp-punto__core {
  animation: bepp-punto-crit 900ms steps(1, end) infinite;
}
.bepp-punto[data-state="error"] .bepp-punto__ring { display: none; }

/* --- alerta · pide atención pero no bloquea. Doble latido y vuelve a la calma --- */
@keyframes bepp-punto-warn {
  0%, 100% { transform: scale(1); }
  12%      { transform: scale(1.14); }
  24%      { transform: scale(1); }
  36%      { transform: scale(1.14); }
  48%      { transform: scale(1); }
}
.bepp-punto[data-state="alerta"] {
  --punto-core: #E0A32F;
  --punto-hl:   #F2D8A8;
  --punto-sh:   #A37F30;
  --punto-halo: #E0A32F;
}
.bepp-punto[data-state="alerta"] .bepp-punto__core {
  animation: bepp-punto-warn 1800ms ease-out infinite;
}
.bepp-punto[data-state="alerta"] .bepp-punto__ring--a {
  animation: bepp-punto-ring 1800ms cubic-bezier(.2,.6,.3,1) infinite;
}
.bepp-punto[data-state="alerta"] .bepp-punto__ring--b { display: none; }
.bepp-punto[data-state="alerta"] .bepp-punto__eyes i {
  animation: none;
  transform: scaleY(1.2);
}

/* --- sin conexión · el punto se vacía. No late porque no hay señal --- */
.bepp-punto[data-state="offline"] .bepp-punto__core {
  background: transparent;
  box-shadow: inset 0 0 0 var(--punto-ring-w) #3E5766;
}
.bepp-punto[data-state="offline"] .bepp-punto__aura::before { display: none; }
.bepp-punto[data-state="offline"] .bepp-punto__ring { display: none; }

/* mirada plana compartida por error y sin conexión */
.bepp-punto[data-state="error"] .bepp-punto__eyes i,
.bepp-punto[data-state="offline"] .bepp-punto__eyes i {
  animation: none;
  width: calc(var(--punto-eye-w) * 1.45);
  height: calc(var(--punto-d) * 0.024);
  border-radius: calc(var(--punto-d) * 0.012);
}
.bepp-punto[data-state="offline"] .bepp-punto__eyes i { background: #3E5766; }

/* ---------- accesibilidad ---------- */

@media (prefers-reduced-motion: reduce) {
  .bepp-punto *,
  .bepp-punto *::before,
  .bepp-punto *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  /* sin movimiento, el anillo estático da la única señal de "vivo" */
  .bepp-punto[data-state="reposo"] .bepp-punto__ring--a,
  .bepp-punto[data-state="escuchando"] .bepp-punto__ring--a,
  .bepp-punto[data-state="contento"] .bepp-punto__ring--a {
    opacity: 0.45;
    transform: scale(1.6);
  }
}

/* ============================================================================
   AJUSTE DE GEMA — latido continuo
   Divergencia deliberada de la hoja de personaje: ahí reposo late una vez cada
   3.6 s y se queda quieto en medio, y éxito congela el núcleo después de cerrar
   el anillo. En GEMA el punto es la única señal de vida en pantallas que pueden
   quedarse largo rato sin cambiar (login, empty states), así que respira sin
   pausa: el núcleo nunca se detiene y siempre hay un anillo en vuelo.
   Si esto gusta, hay que portarlo de regreso a Identidad/Personajes/Punto.
   ========================================================================= */

@keyframes bepp-punto-respira {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.055); }
}

/* --- reposo: respiración pareja, anillos encadenados sin hueco --- */
.bepp-punto[data-state="reposo"] { --punto-beat: 2200ms; }

.bepp-punto[data-state="reposo"] .bepp-punto__core {
  animation: bepp-punto-respira var(--punto-beat) cubic-bezier(.45, 0, .55, 1) infinite;
}

/* medio ciclo de desfase: mientras un anillo se apaga, el otro ya salió */
.bepp-punto[data-state="reposo"] .bepp-punto__ring--b {
  animation-delay: calc(var(--punto-beat) / 2);
}

/* --- éxito: el anillo sigue cerrando una sola vez (eso es lo que significa),
       pero el núcleo se queda respirando en vez de congelarse --- */
.bepp-punto[data-state="exito"] .bepp-punto__core {
  animation: bepp-punto-respira 2600ms cubic-bezier(.45, 0, .55, 1) infinite;
}

/* ============================================================================
   CONTENTO — el noveno estado, exclusivo de GEMA
   No está en la hoja de personaje. Nace para los empty states buenos ("cero
   atrasadas"): éxito significa "esto terminó", y por eso cierra el anillo una
   vez y lo congela. Un empty state no terminó nada — se queda en pantalla
   mientras el usuario lee. Así que aquí el punto no cierra: late, halea y mira
   alrededor. Sigue sin tocar el color; la alegría se lee por forma y por
   movimiento. Si gusta, portar de regreso a Identidad/Personajes/Punto.
   ========================================================================= */

.bepp-punto[data-state="contento"] { --punto-beat: 2000ms; }

/* núcleo · respira más hondo que reposo (1.055). A este sí lo alcanzas a ver. */
@keyframes bepp-punto-respira-feliz {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.075); }
}
.bepp-punto[data-state="contento"] .bepp-punto__core {
  animation: bepp-punto-respira-feliz var(--punto-beat) cubic-bezier(.45, 0, .55, 1) infinite;
}

/* halo · la sombra de contacto se abre y cierra en fase con el núcleo.
   Esto es lo que de verdad lee como "vivo" de lejos, no los 4px del core. */
@keyframes bepp-punto-halo {
  0%, 100% { opacity: 0.7; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.12); }
}
.bepp-punto[data-state="contento"] .bepp-punto__aura {
  animation: bepp-punto-halo var(--punto-beat) cubic-bezier(.45, 0, .55, 1) infinite;
}

/* anillos · encadenados sin hueco: mientras uno se apaga, el otro ya salió */
.bepp-punto[data-state="contento"] .bepp-punto__ring {
  animation: bepp-punto-ring var(--punto-beat) cubic-bezier(.2,.6,.3,1) infinite;
}
.bepp-punto[data-state="contento"] .bepp-punto__ring--b {
  animation-delay: calc(var(--punto-beat) / 2);
}

/* mirada · vagabundea: se va a un lado, aguanta, cruza al otro, vuelve al
   centro. Los 7000ms no son múltiplo de los 2000ms del latido a propósito —
   los dos movimientos derivan y nunca caen en patrón visible. */
@keyframes bepp-punto-vagar {
  0%,  16%  { transform: translateX(0); }
  25%, 39%  { transform: translateX(calc(var(--punto-d) *  0.055)); }
  48%, 62%  { transform: translateX(calc(var(--punto-d) * -0.055)); }
  71%, 100% { transform: translateX(0); }
}
.bepp-punto[data-state="contento"] .bepp-punto__eyes {
  animation: bepp-punto-vagar 7000ms cubic-bezier(.65, 0, .35, 1) infinite;
}

/* ojos · los arcos de éxito, pero vivos. En un arco el parpadeo normal
   (scaleY 0.08) no parpadea: lo borra. Aquí la sonrisa se aprieta y rebota,
   que es como parpadea una cara que ya venía sonriendo. */
@keyframes bepp-punto-guino {
  0%, 86%, 100% { transform: scaleY(1); }
  91%           { transform: scaleY(0.4); }
  95%           { transform: scaleY(1.18); }
}
.bepp-punto[data-state="contento"] .bepp-punto__eyes i {
  background: transparent;
  width: calc(var(--punto-eye-w) * 1.45);
  height: calc(var(--punto-eye-h) * 0.26);
  border-top: calc(var(--punto-d) * 0.045) solid var(--punto-eye);
  border-radius: 50% 50% 0 0 / 100% 100% 0 0;
  animation: bepp-punto-guino 5200ms ease-in-out infinite;
}

/* ============================================================================
   CONGELADO — un cuadro fijo de cualquier animación
   Para hojas de referencia (la pestaña El Punto): pausa todo el punto en el
   instante --punto-t de su ciclo. Tiene que estar desde que el punto se monta;
   ponerlo después congela donde la animación ya iba.
   ========================================================================= */
.bepp-punto--congelado,
.bepp-punto--congelado *,
.bepp-punto--congelado *::before,
.bepp-punto--congelado *::after {
  animation-play-state: paused !important;
  animation-delay: calc(var(--punto-t, 0ms) * -1) !important;
}
