/* ============================================================================
   Avisos de la consola — la capa propia de la consola, en vez de llamar
   directo a la libreria de la plantilla.

   DOS FORMAS, NO UNA CON VARIANTES. El toast (.fvt) flota y se va solo: es el
   resultado de algo que la persona acaba de hacer. El aviso inline (.fvn) va en
   el flujo del documento, no se cierra solo y lo pinta el SERVIDOR: es un estado
   que ya era cierto antes de que cargara la pagina — por eso no puede depender
   de que cargue ningun JS (el caso del login).

   UNA SOLA SUPERFICIE, A PROPOSITO. El "modo oscuro" de la consola solo agrega
   `forsvar-sidebar-primary-theme` al body y pinta EL SIDEBAR: el area de
   contenido es siempre clara. No hay fondo oscuro sobre el que un aviso tenga
   que flotar, asi que no hay variante por tema.

   CSS PLANO, NO SASS. Existe src/sass/vendors/plugins/_toastr.scss, pero lo que
   sirve la consola son los bundles ya compilados en assets/css/. Este archivo es
   independiente: no toca el bundle de Metronic ni necesita su toolchain.

   Contrato visual: reports/2026-09-04_mockup-notificaciones.html
   Plan: gcp-infra-agent/next_steps/forsvar_avisos_consola.md
   ========================================================================== */

.fv-notify-stack {
  /* Centinela para el JS: si esta propiedad no llega, la hoja no cargo y el
     motor pinta con estilos propios en vez de mostrar un aviso sin forma.
     No la saques: es como se cumple la garantia de "no falla en silencio". */
  --fv-css: 1;

  position: fixed;
  top: 14px;
  right: 14px;
  width: 326px;
  max-width: calc(100vw - 28px);
  display: flex;
  flex-direction: column;
  gap: 9px;
  z-index: 999999;      /* por encima de los drawers y modales de Metronic */
  pointer-events: none; /* el hueco entre avisos no roba clicks a la pantalla */
}

/* Debajo del header, cuando hay header.
   Con `top: 14px` a secas el aviso se monta sobre la barra de la consola y tapa el menú
   de usuario y la campana de notificaciones — medido, no estimado: la pila ocupa
   x 1260-1586 y el menú de usuario x 1535-1570. Con un toast de 5 s sería tolerable,
   pero el aviso de inactividad del árbol es `duracion: 0` + `cerrable: false` a
   propósito: ese se queda tapando los controles hasta que la persona resuelve.

   NO alcanza con leer `--bs-app-header-height`: Metronic la define TAMBIÉN en el login,
   donde no hay ningún header, así que sola empujaría el aviso 88 px hacia abajo sobre
   una pantalla que no tiene nada arriba. Lo que decide es la PRESENCIA del header, y eso
   lo dice `:has()`. La altura sigue saliendo de la variable para no clavar un 74 fijo:
   Metronic la cambia por breakpoint.

   Si un navegador no soporta `:has()`, la regla se ignora y queda el ancla de 14 px —
   o sea el comportamiento anterior, no uno roto. */
body:has(#kt_app_header) .fv-notify-stack {
  top: calc(var(--bs-app-header-height, 0px) + 14px);
}

/* ---------- Los cuatro tonos ----------
   OJO CON LA CASCADA: `.fv-info` y `.fvn` tienen la MISMA especificidad, asi que
   si `.fvn` declarara su propio `--tone` por default ganaria por venir despues y
   TODOS los avisos inline saldrian dorados. Por eso el default no vive en la
   regla del componente: va como segundo argumento de cada `var(--tone, …)`.
   Verificado mirando la pantalla — la hoja "correcta" pintaba los cuatro igual.
   El tono lo define QUE LE PASO AL TRABAJO DEL USUARIO, no que color queda
   bien. Ese criterio es lo que no existia, y por eso el 86% de los avisos de
   la consola son rojos.

   ok    el trabajo se completo
   error el trabajo no se hizo y hay algo que corregir
   warn  el trabajo siguio, pero cambio algo que el usuario necesita saber
   info  no paso nada malo; el sistema hizo algo por su cuenta            */
.fv-ok    { --tone: #2f7d5b; }
.fv-error { --tone: #b23b3b; }
.fv-warn  { --tone: #CC9E37; }
.fv-info  { --tone: #5b7ba8; }

/* ============ FORMA 1: toast — flotante y transitorio ============ */
.fvt {
  pointer-events: auto;
  position: relative;
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) 16px;
  gap: 11px;
  align-items: start;
  padding: 13px 13px 13px 15px;
  border-radius: 14px;
  overflow: hidden;
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  background: #FFFFFFF2;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 8px 26px #1f2a3d29, 0 0 0 1px #1f2a3d14;
  animation: fvIn 420ms cubic-bezier(.16, 1, .3, 1) both;
}
.fvt::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--tone, #5b7ba8);
}
.fvt .fvt-ic {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--tone, #5b7ba8);
  flex: 0 0 auto;
}
.fvt .fvt-ic svg { width: 18px; height: 18px; display: block; stroke: #fff; }
.fvt .fvt-tt {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.3;
  margin: 1px 0 2px;
  letter-spacing: -.005em;
  color: #223350;
}
.fvt .fvt-bd {
  font-size: 12.5px;
  font-weight: 400;
  line-height: 1.42;
  color: #5a5d68;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* La accion opcional (`opciones.accion`): un link, no un boton, a lo que el aviso ofrece hacer a
   continuacion ("Ver 360"). Escala del cuerpo, color del titulo y subrayado para que se lea como
   link: el color del tono no alcanza contraste AA sobre blanco en `warn` (el dorado). */
.fvt .fvt-ac {
  display: inline-block;
  margin-top: 4px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.42;
  color: #223350;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.fvt .fvt-ac:hover { color: var(--tone, #5b7ba8); }
.fvt .fvt-ac:focus-visible {
  outline: 2px solid var(--tone, #5b7ba8);
  outline-offset: 2px;
  border-radius: 3px;
}
.fvt .fvt-cl {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  opacity: .45;
  color: #223350;
  font-family: inherit;
}
.fvt .fvt-cl:hover { opacity: .9; }
.fvt .fvt-cl:focus-visible {
  outline: 2px solid var(--tone, #5b7ba8);
  outline-offset: 2px;
  border-radius: 3px;
  opacity: .9;
}
.fvt .fvt-bar {
  position: absolute;
  left: 0; bottom: 0;
  height: 2px;
  background: var(--tone, #5b7ba8);
  opacity: .5;
  animation: fvBar var(--fv-dur, 5000ms) linear both;
}
.fvt.fvt-out { animation: fvOut 240ms cubic-bezier(.4, 0, 1, 1) both; }

@keyframes fvIn {
  from { transform: translateX(calc(100% + 28px)); opacity: 0; }
  40%  { opacity: 1; }
  to   { transform: translateX(0); opacity: 1; }
}
@keyframes fvOut {
  from { transform: translateX(0); opacity: 1; }
  to   { transform: translateX(calc(100% + 28px)); opacity: 0; }
}
@keyframes fvBar { from { width: 100%; } to { width: 0%; } }

@media (prefers-reduced-motion: reduce) {
  .fvt          { animation: fvFade 180ms ease both; }
  .fvt.fvt-out  { animation: fvFade 140ms ease reverse both; }
  .fvt .fvt-bar { animation: none; width: 100%; }
  @keyframes fvFade { from { opacity: 0; } to { opacity: 1; } }
}

/* ============ FORMA 2: aviso inline — persistente, sin JS ============
   Mismo riel, mismos tonos, misma escala tipografica. Va en el flujo del
   documento, no se cierra solo, radio 9 px y un inset en vez de sombra. */
.fvn {
  position: relative;
  /* El aviso inline se pone adentro de contenedores ajenos —el de un grafico suele ser
     `text-center`— y heredaba el centrado: icono a la izquierda y texto en el medio. La
     alineacion es del componente, no del lugar donde cae. */
  text-align: left;
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr);
  gap: 11px;
  align-items: start;
  padding: 13px 15px 13px 17px;
  border-radius: 9px;
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  background: #FFFFFF;
  box-shadow: inset 0 0 0 1px #1f2a3d1f;
}
.fvn::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  border-radius: 9px 0 0 9px;
  background: var(--tone, #5b7ba8);
}
.fvn svg {
  width: 19px;
  height: 19px;
  display: block;
  margin-top: 1px;
  stroke: var(--tone, #5b7ba8);
}
.fvn .fvn-tt {
  font-size: 13.5px;
  font-weight: 600;
  color: #223350;
  line-height: 1.3;
  margin: 0 0 2px;
}
.fvn .fvn-bd {
  font-size: 12.5px;
  font-weight: 400;
  color: #5a5d68;
  line-height: 1.45;
}
/* Sin cuerpo, el titulo es todo el aviso y no necesita el margen de separacion. */
.fvn .fvn-tt:only-child { margin: 0; }
/* La accion del aviso inline: el mismo link que la del toast (.fvt-ac), por las mismas razones —
   color del titulo y subrayado, porque el dorado de `warn` no llega a contraste AA sobre blanco. */
.fvn .fvn-ac {
  display: inline-block;
  margin-top: 4px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.42;
  color: #223350;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.fvn .fvn-ac:hover { color: var(--tone, #5b7ba8); }
.fvn .fvn-ac:focus-visible {
  outline: 2px solid var(--tone, #5b7ba8);
  outline-offset: 2px;
  border-radius: 3px;
}
