﻿/* ==========================================================================
   Tema FEMORF sobre Basecoat (shadcn/ui)
   --------------------------------------------------------------------------
   Basecoat expone el juego de tokens de shadcn en :root (--primary, --muted,
   --border, --radius, la familia --sidebar*, --chart-*). Este archivo NO
   redefine componentes: solo reemplaza esos tokens por los del fondo, y todo
   lo demas (botones, campos, tablas, dialogos) se recolorea solo.

   ORDEN DE CARGA OBLIGATORIO en el layout:
       1. app.css          -> Tailwind (preflight + utilidades)
       2. basecoat.min.css -> componentes + tema por defecto
       3. marca.theme.css  -> ESTE archivo, que pisa los tokens

   Cargarlo antes de Basecoat lo deja sin efecto: los tokens por defecto
   ganarian por orden de cascada, no por especificidad.

   NO RENOMBRAR A "femorf.*" (ni a nada que contenga la palabra de la marca).
   -------------------------------------------------------------------------
   Este archivo se llamaba femorf.theme.css y en el servidor daba 404. El
   balanceador desvia al servidor IIS viejo TODA url que contenga la subcadena
   "femorf" en cualquier posicion y sin distinguir mayusculas: /css/femorf.*,
   /js/femorf.*, /img/LogoFEMORF.png. La regla no esta anclada al inicio de la
   ruta, asi que atrapa nombres de archivo, no solo el prefijo que pretendia.

   Sin este archivo el navegador se queda con los tokens por defecto de
   Basecoat y --primary vale oklch(0.205 0 0): NEGRO. La aplicacion no falla ni
   registra nada, solo cambia de color. Un 404 de CSS no rompe el layout ni tira
   el servicio, por eso el sintoma llego como "los botones se ven negros".

   Como se diagnostica: la cabecera Server: de la respuesta delata al backend.
   Un 404 con Server: Kestrel es sano (la ruta llego bien); uno con
   Server: Microsoft-IIS/10.0 es el desvio. Ojo con el falso positivo del
   asp-append-version: que el <link> lleve ?v= prueba que la app LEE el archivo
   en disco, no que el navegador pueda descargarlo.

   Verificado el 2026-08-28 en testing.proyectosymantenimiento.com. Mientras la
   regla del balanceador siga sin anclar a /femorf, cualquier archivo servido
   por HTTP que lleve la marca en el nombre nace roto.

   Los valores salen del lienzo de diseno (.claude/sessions/Rediseno-shadcn):
   base neutra fria (escala slate) y azul institucional #1a7ab2 como color de
   accion. Cada token lleva su equivalente hex para poder rastrearlo.
   ========================================================================== */

:root {
    /* --- Superficies -------------------------------------------------- */
    --background: oklch(1 0 0);                       /* #ffffff */
    --foreground: oklch(0.208 0.042 265.755);         /* #0f172a slate-900 */
    --card: oklch(1 0 0);                             /* #ffffff */
    --card-foreground: oklch(0.208 0.042 265.755);
    --popover: oklch(1 0 0);
    --popover-foreground: oklch(0.208 0.042 265.755);

    /* --- Marca --------------------------------------------------------
       #1a7ab2 es el azul que el fondo ya usa en la barra lateral actual;
       convertido a oklch para poder derivar tintes sin cambiar de tono. */
    --primary: oklch(0.554 0.120 241);                /* #1a7ab2 */
    --primary-foreground: oklch(1 0 0);               /* #ffffff */

    /* --- Neutros ------------------------------------------------------ */
    --secondary: oklch(0.968 0.007 247.896);          /* #f1f5f9 slate-100 */
    --secondary-foreground: oklch(0.372 0.044 257.287); /* #334155 slate-700 */
    --muted: oklch(0.984 0.003 247.858);              /* #f8fafc slate-50 */
    --muted-foreground: oklch(0.554 0.046 257.417);   /* #64748b slate-500 */
    --accent: oklch(0.968 0.007 247.896);             /* #f1f5f9 */
    --accent-foreground: oklch(0.208 0.042 265.755);  /* #0f172a */

    /* --- Estado -------------------------------------------------------- */
    --destructive: oklch(0.577 0.245 27.325);         /* rojo de accion */

    /* Tonos semanticos propios del fondo. Basecoat no los trae; los consumen
       las variantes .btn[data-variant] y .badge[data-variant] de mas abajo.
       El par "solido / tenue" existe porque el mismo significado se pinta de
       dos maneras: relleno en un boton, fondo suave en un distintivo. */
    --fem-success: oklch(0.596 0.145 163);            /* #16a34a */
    --fem-success-fg: #ffffff;
    --fem-success-soft: #ecfdf5;
    --fem-success-border: #a7f3d0;
    --fem-success-text: #047857;

    /* El ambar es el unico que no admite texto blanco: sobre #f59e0b el blanco
       queda por debajo del contraste minimo, asi que su texto es casi negro. */
    --fem-warning: oklch(0.769 0.163 70);             /* #f59e0b */
    --fem-warning-fg: #1c1917;
    --fem-warning-soft: #fffbeb;
    --fem-warning-border: #fde68a;
    --fem-warning-text: #b45309;

    --fem-info: oklch(0.588 0.158 254);               /* #2563eb */
    --fem-info-fg: #ffffff;
    --fem-info-soft: #eff6ff;
    --fem-info-border: #bfdbfe;
    --fem-info-text: #1d4ed8;

    /* El peligro es el unico de los cuatro que NO lleva par solido: el boton rojo
       lo resuelve Basecoat con --destructive y ahi el contraste esta bien. Estos
       tres tonos existen solo para el DISTINTIVO suave, porque el de Basecoat
       —rojo sobre un 10 % de si mismo— queda en 3,97:1 y no llega al 4,5:1 que
       pide WCAG AA para texto normal (el .badge mide 12 px con peso 500). Es el
       numero que mas importa leer en una pantalla: la cuenta de fallidos. */
    --fem-danger-soft: #fef2f2;
    --fem-danger-border: #fecaca;
    --fem-danger-text: #b91c1c;

    /* --- Bordes y foco -------------------------------------------------- */
    --border: oklch(0.929 0.013 255.508);             /* #e2e8f0 slate-200 */
    --input: oklch(0.929 0.013 255.508);
    --ring: oklch(0.554 0.120 241);                   /* el foco es de marca */

    /* --- Forma ---------------------------------------------------------
       10 px en tarjetas; Basecoat deriva 6 y 8 px para controles y paneles. */
    --radius: 0.625rem;

    /* --- Graficos ------------------------------------------------------
       Analogos del azul de marca, misma croma: las series se distinguen por
       tono y no por saturacion, asi que sobreviven a una impresion en gris. */
    --chart-1: oklch(0.554 0.120 241);                /* marca */
    --chart-2: oklch(0.646 0.098 205);                /* verde agua */
    --chart-3: oklch(0.511 0.096 265);                /* indigo */
    --chart-4: oklch(0.704 0.084 220);                /* celeste */
    --chart-5: oklch(0.646 0.046 257);                /* gris azulado */

    /* --- Barra lateral --------------------------------------------------
       Clara con borde de 1 px, no el bloque azul solido de hoy: el color de
       marca queda libre para senalar la pantalla activa. */
    --sidebar: oklch(0.984 0.003 247.858);            /* #f8fafc */
    --sidebar-foreground: oklch(0.208 0.042 265.755); /* #0f172a */
    --sidebar-primary: oklch(0.554 0.120 241);        /* #1a7ab2 */
    --sidebar-primary-foreground: oklch(1 0 0);
    --sidebar-accent: oklch(0.955 0.017 241);         /* tinte de marca */
    --sidebar-accent-foreground: oklch(0.554 0.120 241);
    --sidebar-border: oklch(0.929 0.013 255.508);     /* #e2e8f0 */
    --sidebar-ring: oklch(0.554 0.120 241);
    --sidebar-width: 16rem;                           /* 256 px */
}

/* ==========================================================================
   Variantes semanticas que Basecoat no trae
   --------------------------------------------------------------------------
   Basecoat expone data-variant = primary | secondary | destructive | outline |
   ghost | link. El proyecto tiene una convencion de color por semantica en los
   botones de accion de las tablas (regla 8 de employeefund-frontend-components)
   que necesita CINCO: editar es verde, ver documento es ambar, ver historial es
   celeste. Sin estas tres variantes la migracion tendria que aplanar ese
   significado, y el usuario perderia una senal que ya sabe leer.

   Se declaran con la misma mecanica de atributo que usa Basecoat, para que un
   boton migrado se escriba igual que cualquier otro:
       <button class="btn" data-variant="success" data-size="icon-sm">
   ========================================================================== */

.btn[data-variant='success'] {
    background-color: var(--fem-success);
    color: var(--fem-success-fg);
}

.btn[data-variant='success']:hover {
    background-color: color-mix(in oklab, var(--fem-success) 88%, #000);
}

.btn[data-variant='warning'] {
    background-color: var(--fem-warning);
    color: var(--fem-warning-fg);
}

.btn[data-variant='warning']:hover {
    background-color: color-mix(in oklab, var(--fem-warning) 88%, #000);
}

.btn[data-variant='info'] {
    background-color: var(--fem-info);
    color: var(--fem-info-fg);
}

.btn[data-variant='info']:hover {
    background-color: color-mix(in oklab, var(--fem-info) 88%, #000);
}

/* Los mismos tres tonos como distintivo suave, para los estados de un registro
   (aprobado, pendiente, verificado) donde el color va de fondo tenue y no de
   relleno solido. */
.badge[data-variant='success'] {
    background-color: var(--fem-success-soft);
    border-color: var(--fem-success-border);
    color: var(--fem-success-text);
}

.badge[data-variant='warning'] {
    background-color: var(--fem-warning-soft);
    border-color: var(--fem-warning-border);
    color: var(--fem-warning-text);
}

.badge[data-variant='info'] {
    background-color: var(--fem-info-soft);
    border-color: var(--fem-info-border);
    color: var(--fem-info-text);
}

/* A diferencia de las tres de arriba, esta variante SI existe en Basecoat: aca se
   sobreescribe, no se agrega. Basecoat la pinta con color-mix del rojo al 10 % de
   fondo y ese mismo rojo de texto, que da 3,97:1 y falla AA. Esta hoja se carga
   DESPUES de basecoat.min.css (ver el orden en _LayoutBasecoat.cshtml), asi que
   gana por cascada sin necesidad de !important ni de subir especificidad.

   Solo toca el DISTINTIVO, a proposito. El boton .btn[data-variant='destructive']
   arrastra EL MISMO defecto y queda pendiente de decision: Basecoat lo declara tres
   veces y la que gana no es el relleno solido sino la suave (color-mix del rojo al
   10 % de fondo, con ese mismo rojo de texto), asi que mide los mismos 3,97:1 con
   una etiqueta de 14 px. Cambiarlo altera el aspecto de todos los botones de borrar
   de la aplicacion, que es una decision de diseno y no de contraste; el arreglo
   minimo seria pisarle solo el color de texto con --fem-danger-text, conservando el
   fondo suave. */
.badge[data-variant='destructive'] {
    background-color: var(--fem-danger-soft);
    border-color: var(--fem-danger-border);
    color: var(--fem-danger-text);
}

/* Las mismas tres variantes para el bloque .alert, por el mismo motivo que arriba:
   Basecoat solo trae `destructive`, asi que un `data-variant="warning"` en una alerta
   no pintaba NADA y el aviso salia con el gris de una alerta comun. Es lo que pasaba
   con la advertencia de impersonacion ("lo que hagas quedara a nombre de esa
   persona"), que es justo la que no deberia pasar desapercibida.

   Sin esta regla la unica salida era escribir los tres tokens a mano en cada vista
   (border-[color:var(--fem-info-border)] bg-[...] text-[...]), que es lo que venian
   haciendo las pantallas migradas y lo que arma FEEDBACK_STYLES en
   js/General/Dialogs.basecoat.js. Con la variante declarada, una alerta se escribe
   igual que un boton o un distintivo.

   El color del texto va sobre el hijo <section> ademas de sobre el contenedor porque
   Basecoat le da a esa seccion su propio color, y si no se lo pisa el cuerpo del
   mensaje queda gris sobre el fondo de color. */
.alert[data-variant='success'] {
    background-color: var(--fem-success-soft);
    border-color: var(--fem-success-border);
    color: var(--fem-success-text);
}

.alert[data-variant='warning'] {
    background-color: var(--fem-warning-soft);
    border-color: var(--fem-warning-border);
    color: var(--fem-warning-text);
}

.alert[data-variant='info'] {
    background-color: var(--fem-info-soft);
    border-color: var(--fem-info-border);
    color: var(--fem-info-text);
}

.alert[data-variant='success'] > section,
.alert[data-variant='warning'] > section,
.alert[data-variant='info'] > section {
    color: inherit;
}

/* ==========================================================================
   Lienzo de la pantalla
   Malla suave derivada del azul de marca, en vez del blanco plano. Las
   tarjetas siguen siendo blancas y por eso resaltan sobre el.
   La primera declaracion es el respaldo para navegadores sin color-mix.
   ========================================================================== */
.fem-canvas {
    background: #f4f7fb;
    background:
        radial-gradient(1100px 620px at 0% 0%, color-mix(in oklab, var(--primary) 13%, #ffffff) 0%, rgba(255, 255, 255, 0) 62%),
        radial-gradient(900px 520px at 100% 0%, #edf0fc 0%, rgba(255, 255, 255, 0) 58%),
        radial-gradient(1000px 640px at 100% 100%, #eaf7f2 0%, rgba(255, 255, 255, 0) 62%),
        radial-gradient(760px 480px at 12% 100%, color-mix(in oklab, var(--primary) 8%, #ffffff) 0%, rgba(255, 255, 255, 0) 58%),
        #f7fafc;
}

/* ==========================================================================
   Cifras
   Todo numero de tabla, indicador o importe va con cifras de ancho fijo: sin
   esto las columnas de dinero no alinean el punto de miles entre filas.
   ========================================================================== */
.fem-num {
    font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   Tipografia
   Basecoat pide Geist; el proyecto no puede cargar fuentes externas (regla de
   cero CDN de employeefund-dependency-policy) y Geist no esta vendorizada
   todavia, asi que se declara la pila del sistema. Vendorizar Geist es una
   decision aparte: cuando entre, se cambia SOLO esta regla.
   ========================================================================== */
:root {
    --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-mono: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
}

/* ==========================================================================
   Clases que aplica el JAVASCRIPT en tiempo de ejecucion
   --------------------------------------------------------------------------
   Una clase que solo existe en el marcado se traduce al migrar la vista. Una
   que el JS AGREGA o QUITA en caliente no se puede traducir sin reescribir el
   JS, y hay archivos que NO se pueden tocar porque los comparten vistas que
   todavia corren sobre Bootstrap. Esas dos son las unicas que entran aca.
   ========================================================================== */

/* .input-error es del PROYECTO, no de Bootstrap: nacio en wwwroot/css/site.css y
   la aplican por igual PartnersRequest.js y varios validadores mas para marcar
   un campo rechazado. Aquella hoja se elimino al cerrar la migracion, asi que
   esta regla es ahora la UNICA definicion de la clase: sin ella el campo
   invalido se veria identico a uno correcto.

   Se repinta con los tokens del tema en vez de copiar el #dc3545 de Bootstrap,
   y el resaltado usa la misma medida de anillo que Basecoat le da al foco de un
   campo (3 px), para que un campo en error y uno enfocado no se peleen de tamano.

   Cubre los dos envases posibles: el control nativo y el marcado de Select2. */
.input-error,
.select2-container .select2-selection.input-error,
.select2-container--default .select2-selection--single.input-error {
    border-color: var(--destructive);
    box-shadow: 0 0 0 3px color-mix(in oklab, var(--destructive) 22%, transparent);
}

.input-error:focus,
.input-error:focus-visible,
.select2-container--default .select2-selection--single.input-error:focus {
    border-color: var(--destructive);
    box-shadow: 0 0 0 3px color-mix(in oklab, var(--destructive) 34%, transparent);
}

/* .d-none es un nombre heredado de Bootstrap y esta aca por una dependencia
   concreta: wwwroot/js/Partner/SignatureImage.js la agrega y la quita sobre el
   contenedor de la camara y sobre el enlace de descarga (lineas 436, 481, 533 y
   567). Ese archivo lo comparten Administration/Users, FundPeople/Index y
   Partner/PartnersRequest — las tres ya en Basecoat, asi que la regla no
   sobrevive por compatibilidad con el layout viejo sino porque el JS sigue
   escribiendo ese nombre de clase.

   No lleva !important (como si lo llevaba la de Bootstrap): marca.theme.css se
   carga DESPUES de app.css, asi que ya le gana por orden de cascada a cualquier
   utilidad de display de Tailwind con la misma especificidad. Se borra el dia
   que SignatureImage.js pase a usar la utilidad hidden de Tailwind. */
.d-none {
    display: none;
}

/* ==========================================================================
   Menu lateral: nombres largos completos, sin truncar
   --------------------------------------------------------------------------
   Basecoat trunca el rotulo de cada opcion con
     :is(.sidebar nav>section ul li>a, ...>button, ...>summary) > span:last-child
       { text-overflow:ellipsis; white-space:nowrap; overflow:hidden }
   Con tres niveles de anidamiento, los nombres largos de nivel 3
   ("Solicitudes de retiro de efectivo", "Gestion de ahorros y aportes") no
   entran en una linea y se ven cortados ("Solicitudes d...").

   La correccion deja que el rotulo ENVUELVA a dos lineas: los cortos siguen en
   una linea, solo los largos bajan. Va aca (no en la clase Tailwind del item)
   porque hay que vencer una regla de Basecoat, y este archivo carga despues.

   Como la fila tenia altura fija (h-[30px]/h-[34px] de Tailwind), un rotulo de
   dos lineas se cortaria por arriba y por abajo; por eso la altura pasa a
   automatica con un minimo, y se centra el texto con un pequeno respiro
   vertical.
   ========================================================================== */
:is(.sidebar nav > section ul li > a,
    .sidebar nav > section ul li > button,
    .sidebar nav > section ul li > details > summary) > span:last-child {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    line-height: 1.2;
}

:is(.sidebar nav > section ul li > a,
    .sidebar nav > section ul li > button,
    .sidebar nav > section ul li > details > summary) {
    height: auto;
    min-height: 30px;
    padding-block: 5px;
    align-items: center;
}

/* ==========================================================================
   Menu lateral: no debe plegarse y reabrirse cuando aparece un SweetAlert
   --------------------------------------------------------------------------
   Choque entre dos librerias que usan el mismo atributo para cosas distintas,
   sin ningun error en consola:

   1. SweetAlert2, al abrir un popup, marca aria-hidden="true" en TODOS los
      hijos directos del <body> que no contienen su contenedor, para sacarlos
      del lector de pantalla. Antes de pisarlo guarda el valor que hubiera en
      data-previous-aria-hidden, y al cerrar el popup lo restaura y borra ese
      rastro.
   2. Basecoat usa ESE MISMO atributo como estado abierto/cerrado del menu:
        :is(.sidebar[data-side=left])[aria-hidden=true] nav -> translate -100%
        :is(.sidebar[data-side=left])[aria-hidden=true] + * -> margin-left 0
      las dos con 300 ms de transicion.

   Como #femSidebar es hijo directo del <body>, cada SweetAlert lo pliega y lo
   vuelve a desplegar con animacion: el ShowLoading() que precede a la carga de
   un modal, el aviso de exito al guardar, una confirmacion antes de borrar.

   La correccion se apoya en data-previous-aria-hidden porque conserva el
   estado REAL del menu y solo existe mientras el popup esta abierto: si valia
   "false" el menu estaba desplegado y aqui se lo mantiene asi; si el usuario
   lo tenia plegado el atributo vale "true", la regla no aplica y sigue
   plegado. Al cerrarse el popup el atributo desaparece y el estado vuelve a
   manos de Basecoat.

   Va en este archivo —y no en la vista ni en la libreria vendorizada— porque
   pisa una regla de Basecoat: al no estar dentro de ninguna @layer, le gana a
   su @layer components sin depender de la especificidad.
   ========================================================================== */
.sidebar[data-previous-aria-hidden="false"] > nav {
    translate: none;
}

@media (min-width: 48rem) {
    :is(.sidebar:not([data-side]),
        .sidebar[data-side="left"])[data-previous-aria-hidden="false"] + * {
        margin-left: var(--sidebar-width);
    }
}
