/* =========================================================================
   PANTALLAS PÚBLICAS DE ACCESO
   Lo comparten las tres vistas que se montan sobre Views/Template/acceso_inicio.php:
   el login y los dos pasos de la recuperación de contraseña.
   Panel de marca (izquierda) con un tejido de líneas SVG que ondulan lento,
   + formulario sobrio (derecha).
   El panel de marca usa una paleta FIJA (--marca-*, definida más abajo): el
   cliente pidió el fondo azul, así que ya no sigue al tema activo. El resto
   de la pantalla (formulario, campos, botón) sí sale del tema
   (--erp-primary / --erp-secondary / --erp-card / ...), de modo que los 14
   temas de Assets/js/tema.js se siguen viendo coherentes sin tocar nada.
   ========================================================================= */

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
    margin: 0;
    font-family: 'Inter', var(--bs-font-sans-serif);
    background: var(--erp-card);
    color: var(--erp-text);
    -webkit-font-smoothing: antialiased;
}

.login-shell {
    min-height: 100vh;
    display: grid;
    grid-template-columns: 1.1fr 1fr;
}

/* ============================ PALETA DEL LOGIN =========================== */
/* Paleta FIJA de toda la pantalla de acceso. Por pedido del cliente el login va
   en azul, así que NO sigue al tema guardado en la cookie: el panel de marca ya
   usaba estos --marca-*, pero el formulario seguía saliendo del tema activo y con
   el tema por defecto se veía naranja/morado (botón "Ingresar", foco de los
   campos, chip del correo, iconos). Acá se pisan --erp-primary / --erp-secondary
   SOLO dentro del login: se declaran en <body> y tema.js los escribe en <html>,
   así que esta declaración gana para todo el árbol del body sin tocar tema.js ni
   el resto del sistema, que siguen funcionando igual.
   Lo que sí se deja al tema es el fondo, el texto y los bordes (--erp-card,
   --erp-text, --erp-border-*), de modo que el modo oscuro se sigue respetando.
   El selector repite body.dark-mode a propósito: theme.css declara ahí sus
   propios --erp-primary/--erp-secondary y, con más especificidad que un `body`
   pelado, en modo oscuro el formulario se volvía cian otra vez.
   Para pasar el login a rojo basta comentar este bloque y descomentar el de
   abajo — es el único lugar del archivo donde se decide el color. */
body, body.dark-mode {
    --marca-1: 37, 99, 235;    /* azul  — acento principal */
    --marca-2: 56, 189, 248;   /* celeste — acento secundario */
    --marca-3: 129, 140, 248;  /* índigo — punto medio de la trama */
    --marca-top: #12305f;      /* arranque del degradado de fondo */
    --marca-bottom: #050c1c;   /* cierre del degradado de fondo */

    --erp-primary: #2563eb;
    --erp-primary-rgb: var(--marca-1);
    --erp-secondary: #38bdf8;
    --erp-secondary-rgb: var(--marca-2);
}
/* Variante ROJA (alternativa aprobada): descomentar y comentar el bloque azul.
body, body.dark-mode {
    --marca-1: 220, 38, 38;
    --marca-2: 248, 113, 113;
    --marca-3: 249, 115, 22;
    --marca-top: #4c1020;
    --marca-bottom: #180509;

    --erp-primary: #dc2626;
    --erp-primary-rgb: var(--marca-1);
    --erp-secondary: #f87171;
    --erp-secondary-rgb: var(--marca-2);
}
*/

/* ============================ PANEL DE MARCA ============================ */
.brand {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: clamp(2.25rem, 4vw, 3.75rem);
    color: #fff;
    background:
        radial-gradient(120% 90% at 12% 8%, rgba(var(--marca-1), .42) 0%, transparent 55%),
        radial-gradient(110% 80% at 88% 92%, rgba(var(--marca-2), .30) 0%, transparent 58%),
        linear-gradient(155deg, var(--marca-top) 0%, var(--marca-bottom) 100%);
}
/* Grano finísimo: le quita el aspecto "plano de degradado". */
.brand::after {
    content: '';
    position: absolute; inset: 0; z-index: 2;
    pointer-events: none;
    opacity: .18;
    background-image: radial-gradient(rgba(255, 255, 255, .09) 1px, transparent 1px);
    background-size: 3px 3px;
}
.brand > * { position: relative; z-index: 3; }

/* --- Tejido de líneas --- */
.seda { position: absolute; inset: -12% -6%; z-index: 1; width: 112%; height: 124%; }
/* Trazo fino y grano bajo: el cliente eligió la variante "Calma" de la pantalla de
   propuestas, que es exactamente esto —trama apenas insinuada, sin barrido de luz—.
   Antes la trama iba a 1.15 y el grano al 50%, y entre las dos el panel se leía
   "activo": competían con el nombre del sistema en vez de acompañarlo. */
.seda path {
    fill: none;
    stroke: url(#trazoSeda);
    stroke-width: .8;
    vector-effect: non-scaling-stroke;
    transform-origin: 50% 50%;
    animation: ondular var(--dur, 18s) cubic-bezier(.45, 0, .55, 1) var(--delay, 0s) infinite;
    will-change: transform, opacity;
}
/* Cada línea se estira/desplaza un poco distinto: el desfase entre todas
   es lo que produce la sensación de tela moviéndose, no cada línea sola. */
@keyframes ondular {
    0%, 100% { transform: translate3d(0, 0, 0) scaleY(1); opacity: .5; }
    50%      { transform: translate3d(-2.5%, -1.6%, 0) scaleY(1.16); opacity: .95; }
}
/* Barrido de luz que recorría el tejido muy despacio. RETIRADO con la variante
   "Calma": era el tercer movimiento del panel (ondas + grano + barrido) y el que
   menos aportaba. Se deja la regla —y el <div class="brillo"> de la plantilla— por
   si se quiere recuperar: basta con quitar el display: none. */
.brillo {
    display: none;
    position: absolute; z-index: 2; inset: 0;
    background: linear-gradient(105deg, transparent 38%, rgba(255, 255, 255, .07) 50%, transparent 62%);
    transform: translateX(-60%);
    animation: barrido 11s ease-in-out infinite;
}
@keyframes barrido { 0%, 100% { transform: translateX(-60%); } 50% { transform: translateX(60%); } }

/* El rótulo del portal vive dentro de .brand-logo, pegado bajo el logo: el
   cliente pidió subirlo para que se lea junto a ENKRO y no suelto en el medio. */
.brand-logo { display: flex; flex-direction: column; align-items: flex-start; gap: .7rem; }
.brand-logo img { max-width: 200px; max-height: 74px; object-fit: contain; }
.brand-logo .marca-texto {
    font-size: clamp(1.5rem, 2.4vw, 2rem);
    font-weight: 800; letter-spacing: .18em; text-transform: uppercase; line-height: 1.1;
}

/* Rótulo del portal: texto pelado. El cliente pidió retirar el punto y el marco
   de píldora, y dejarlo alineado con ENKRO — por eso no lleva padding izquierdo:
   cualquier relleno lo correría respecto del borde del logo de arriba. */
.eyebrow {
    display: block;
    align-self: flex-start;
    padding: 0;
    /* .12em (antes .16em) porque el rótulo pasó de 2 a 6 palabras: con el
       tracking anterior se iba a dos líneas en pantallas medianas. */
    font-size: .7rem; font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
    color: rgba(255, 255, 255, .82);
}

/* Un solo tipo y un solo grosor en las tres líneas (pedido del cliente): antes
   convivían 300 / 700 / 800 y tres tracking distintos en el mismo bloque. Lo
   único que sigue distinguiendo al nombre del sistema es el color de marca —
   el degradado no cambia ni la familia ni el peso. */
.brand h1 {
    margin: 0;
    font-size: clamp(1.9rem, 3vw, 2.9rem);
    font-weight: 600;
    line-height: 1.18;
    letter-spacing: -.01em;
}
.brand h1 strong,
.brand h1 em { font-weight: inherit; letter-spacing: inherit; font-style: normal; }
.brand h1 em {
    background: linear-gradient(100deg, rgb(var(--marca-1)), rgb(var(--marca-2)));
    -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* El bloque central crece y se centra por sí solo; el logo queda arriba y
   .brand-abajo pegado al pie. Antes el sello vivía dentro de este bloque y
   dejaba un hueco muerto de ~150px entre él y el copyright. */
.brand-centro { flex: 1 1 auto; display: flex; flex-direction: column; justify-content: center; }

/* Pie del panel de marca. La marca de certificación va SIN texto de apoyo (el
   cliente pidió dejar solo el logo) y a la misma altura que los documentos
   públicos: Política de datos personales y Código de conducta. Debajo, el
   copyright en su propia línea. */
.brand-abajo { display: flex; flex-direction: column; gap: 1.1rem; margin-top: 2.5rem; }

/* Las tres piezas van JUNTAS y pegadas al extremo DERECHO del panel (así lo pidió el
   cliente, con un boceto). Antes iban repartidas con space-between: el sello solo en
   una punta y los documentos en la otra, y la línea se leía como dos cosas sin
   relación. align-items: stretch es lo que iguala la altura de las tres cajas: las
   dos de texto crecen hasta la placa del sello. */
.brand-pie {
    display: flex; align-items: stretch; justify-content: flex-end;
    gap: .5rem; flex-wrap: wrap;
    padding-top: 1.15rem;
    border-top: 1px solid rgba(255, 255, 255, .12);
}

/* Sello de certificación — enlaza a /certificadoiso, que descarga el PDF original
   (ver Controllers/Certificadoiso.php). Va sobre una placa blanca a propósito: la
   guía de marca de LL-C prohíbe alterar o reemplazar sus colores, así que no se
   puede invertir ni teñir para el panel oscuro; se le da el fondo blanco que la
   propia guía especifica ("creada en azul y gris sobre un fondo blanco"). */
.sello-cert {
    display: inline-flex; align-items: center; justify-content: center;
    flex: 0 0 auto; padding: .45rem .6rem; border-radius: 12px;
    background: #fff; box-shadow: 0 10px 24px rgba(0, 0, 0, .28);
    transition: transform .25s ease, box-shadow .25s ease;
}
/* 124×48 mantiene el viewBox 392×152 de la marca y es exactamente el mínimo de
   reproducción digital que fija la guía de LL-C (105×48 px): es todo lo que se
   puede achicar el sello sin salirse de la guía. */
.sello-cert img { width: 124px; height: 48px; display: block; }
.sello-cert:hover, .sello-cert:focus-visible {
    transform: translateY(-3px); box-shadow: 0 16px 32px rgba(0, 0, 0, .36);
}

/* Los dos documentos públicos, en fila y DELANTE del sello: es el orden del boceto
   —Política de datos · Código de conducta · sello—, con el sello cerrando contra el
   borde derecho del panel. El sello se manda al final con order y no reordenando el
   HTML, donde sigue yendo primero porque es el enlace principal del pie. */
.brand-legal { display: flex; align-items: stretch; gap: .5rem; order: 1; }
.sello-cert { order: 2; }
/* Enmarcados como el sello —mismo radio, misma caja— en vez del subrayado suelto
   que tenían: es lo que hace que la línea se lea uniforme. El texto va chico y en
   dos líneas dentro de su caja, también como el boceto; sin icono, que a este
   tamaño solo ensuciaba. */
.brand-legal a {
    display: flex; align-items: center; justify-content: center; text-align: center;
    max-width: 9.5rem; padding: .4rem .7rem;
    font-size: .66rem; line-height: 1.35;
    border-radius: 12px;
    color: rgba(255, 255, 255, .8); text-decoration: none;
    background: rgba(255, 255, 255, .06);
    border: 1px solid rgba(255, 255, 255, .18);
    transition: color .15s ease, border-color .15s ease, background-color .15s ease;
}
.brand-legal a i { display: none; }
.brand-legal a:hover, .brand-legal a:focus-visible {
    color: #fff; background: rgba(255, 255, 255, .12); border-color: rgba(255, 255, 255, .45);
}

.brand-copy { margin: 0; font-size: .74rem; color: rgba(255, 255, 255, .45); text-align: right; }

/* ============================= FORMULARIO ============================== */
.panel {
    display: flex; align-items: center; justify-content: center;
    padding: clamp(2rem, 5vw, 3.5rem) 1.5rem;
    background: var(--erp-card);
}
.form-wrap { width: 100%; max-width: 384px; animation: subir .55s cubic-bezier(.2, .8, .25, 1) both; }
@keyframes subir { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

.form-logo { display: none; text-align: center; margin-bottom: 1.75rem; }
.form-logo img { max-width: 160px; max-height: 58px; object-fit: contain; }

.form-wrap h2 { margin: 0 0 .4rem; font-size: 1.65rem; font-weight: 700; letter-spacing: -.02em; }
.form-wrap .sub { margin: 0 0 2rem; font-size: .92rem; color: var(--erp-text-muted); }

/* --- Campo con etiqueta flotante --- */
.campo { position: relative; margin-bottom: 1.15rem; }
.campo input {
    width: 100%; height: 58px;
    padding: 1.5rem 3rem .45rem 1rem;
    font-size: .95rem; font-weight: 500;
    color: var(--erp-text);
    background: var(--erp-inner-panel-bg, rgba(148, 163, 184, .07));
    border: 1px solid var(--erp-border-input);
    border-radius: 12px;
    outline: none;
    transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
}
.campo input::placeholder { color: transparent; }  /* solo sirve para disparar :placeholder-shown */
/* El --erp-border-input del tema (#CBD5E1) sobre el panel casi blanco dejaba los
   campos prácticamente invisibles. Se sube un paso el contraste SOLO en claro: en
   oscuro el borde del tema ya recorta de sobra contra el fondo. */
body:not(.dark-mode) .campo input { border-color: #AFBCCD; }
.campo input:hover { border-color: rgba(var(--erp-primary-rgb), .45); }
.campo input:focus {
    border-color: rgb(var(--erp-primary-rgb));
    box-shadow: 0 0 0 4px rgba(var(--erp-primary-rgb), .14);
}
.campo label {
    position: absolute; left: 1.02rem; top: 9px;
    font-size: .7rem; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
    color: var(--erp-text-muted);
    pointer-events: none;
    transition: top .16s ease, font-size .16s ease, color .16s ease, letter-spacing .16s ease;
}
.campo input:placeholder-shown:not(:focus) ~ label {
    top: 19px; font-size: .92rem; font-weight: 400; letter-spacing: 0; text-transform: none;
}
.campo input:focus ~ label { color: rgb(var(--erp-primary-rgb)); }
/* La línea de acento crece desde el centro al enfocar.
   Va anclada al ALTO del input (top: 56px = 58px del campo menos su propio grosor) y no
   a bottom: 0 del contenedor: dentro de .campo también viven el aviso de Bloq Mayús y el
   medidor de fuerza, y anclada abajo la línea se despegaba del campo en cuanto uno de
   los dos aparecía. */
.campo .subrayado {
    position: absolute; left: 12px; right: 12px; top: 56px; height: 2px;
    border-radius: 2px;
    background: linear-gradient(90deg, rgb(var(--erp-primary-rgb)), rgb(var(--erp-secondary-rgb)));
    transform: scaleX(0);
    transition: transform .25s cubic-bezier(.2, .8, .25, 1);
}
.campo input:focus ~ .subrayado { transform: scaleX(1); }
/* El autocompletado de Chrome pinta su propio fondo y rompe el campo. */
.campo input:-webkit-autofill,
.campo input:-webkit-autofill:hover,
.campo input:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--erp-text);
    -webkit-box-shadow: 0 0 0 1000px var(--erp-card) inset;
    caret-color: var(--erp-text);
}

.btn-ojo {
    position: absolute; right: .5rem; top: 50%; transform: translateY(-50%);
    width: 40px; height: 40px; line-height: 1;
    border: 0; border-radius: 10px;
    background: transparent; color: var(--erp-text-muted);
    transition: color .15s ease, background .15s ease;
}
.btn-ojo:hover { color: rgb(var(--erp-primary-rgb)); background: rgba(var(--erp-primary-rgb), .09); }

/* Autoservicio de recuperación. Controllers/Recuperarpassword.php existía y ya
   estaba en PUBLIC_CONTROLLERS, pero no lo enlazaba nadie: a /recuperarpassword
   solo se llegaba escribiendo la URL a mano. Va discreto y a la derecha, pegado
   al campo de contraseña, que es donde se busca cuando hace falta. */
.olvide { margin: -.25rem 0 0; text-align: right; font-size: .8rem; }
.olvide a {
    color: var(--erp-text-muted); text-decoration: none;
    transition: color .15s ease;
}
.olvide a:hover, .olvide a:focus-visible {
    color: rgb(var(--erp-primary-rgb));
    text-decoration: underline; text-underline-offset: 3px;
}

.caps-aviso {
    display: none; align-items: center; gap: .35rem;
    margin-top: .5rem; font-size: .78rem; color: var(--erp-warning);
}
.caps-aviso.show { display: flex; }

/* --- Error en línea --- */
.login-error {
    display: none; align-items: flex-start; gap: .55rem;
    margin-bottom: 1.15rem; padding: .75rem .9rem;
    font-size: .85rem; line-height: 1.4;
    color: var(--erp-danger);
    background: rgba(var(--erp-danger-rgb), .08);
    border: 1px solid rgba(var(--erp-danger-rgb), .3);
    border-radius: 12px;
}
.login-error.show { display: flex; animation: sacudir .34s ease; }
@keyframes sacudir { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } }

/* --- Botón --- */
/* Azul plano y sombra neutra. Antes llevaba degradado azul→cian, un halo de color
   al 28% y un reflejo que lo cruzaba al pasar el mouse: los tres juntos le daban
   aire de app de consumo. El acento sigue saliendo de --erp-primary, así que el
   botón cambia solo con la paleta del login. */
.btn-ingresar {
    width: 100%; height: 52px;
    display: inline-flex; align-items: center; justify-content: center; gap: .55rem;
    margin-top: .95rem;
    font-size: .95rem; font-weight: 600; letter-spacing: .01em;
    color: #fff; border: 0; border-radius: 12px;
    background: rgb(var(--erp-primary-rgb));
    box-shadow: 0 2px 6px rgba(15, 23, 42, .12);
    transition: filter .16s ease, box-shadow .16s ease;
}
/* brightness y no un segundo color: así el hover sirve igual con la variante roja. */
.btn-ingresar:hover:not(:disabled) { filter: brightness(.93); box-shadow: 0 4px 12px rgba(15, 23, 42, .16); }
.btn-ingresar:active:not(:disabled) { filter: brightness(.88); box-shadow: 0 1px 3px rgba(15, 23, 42, .14); }
.btn-ingresar:disabled { opacity: .72; cursor: progress; }
.btn-ingresar:focus-visible { outline: 3px solid rgba(var(--erp-primary-rgb), .4); outline-offset: 2px; }

/* Pie de ayuda del formulario. Es SOLO móvil: lo legal y los documentos públicos ya
   viven en el pie del panel de marca, y el cliente pidió no repetirlos. Reaparece por
   debajo de 992px, que es donde el panel de marca se oculta entero (ver RESPONSIVE):
   sin esto, en móvil no quedaría un solo acceso a la Política de datos personales ni
   al Código de conducta.
   Ya no incluye la línea de soporte ("¿No puedes ingresar? Escríbenos a ..."): ese
   buzón se da en la pantalla de ¿Olvidaste tu contraseña?, que es adonde va quien no
   puede entrar, así que en el login era ruido duplicado. */
.ayuda {
    display: none;
    margin-top: 1.75rem; padding-top: 1.25rem;
    border-top: 1px solid var(--erp-border-soft);
    font-size: .8rem; color: var(--erp-text-muted); text-align: center;
}
.ayuda i { color: rgb(var(--erp-primary-rgb)); }
/* text-wrap: balance reparte las líneas en vez de dejar una palabra suelta al final.
   Donde no está soportado simplemente se ignora. */
.ayuda-legal { margin: 0; font-size: .74rem; line-height: 1.55; opacity: .9; text-wrap: balance; }
.ayuda-legal a { color: var(--erp-text-muted); text-decoration: underline; text-underline-offset: 2px; }
.ayuda-legal a:hover { color: rgb(var(--erp-primary-rgb)); }

/* Documentos públicos de la empresa (solo móvil, ver .ayuda). */
.ayuda-docs {
    display: flex; flex-wrap: wrap; justify-content: center;
    gap: .45rem; margin: .8rem 0 0; font-size: .72rem;
}
.ayuda-docs a {
    display: inline-flex; align-items: center; gap: .35rem;
    padding: .3rem .65rem; border-radius: 8px;
    border: 1px solid var(--erp-border-soft);
    color: var(--erp-text-muted); text-decoration: none;
    transition: border-color .15s ease, color .15s ease;
}
.ayuda-docs a:hover { color: rgb(var(--erp-primary-rgb)); border-color: rgba(var(--erp-primary-rgb), .35); }

/* ============================== RESPONSIVE ============================== */
@media (min-width: 992px) {
    /* Centrado óptico. El panel de marca ancla arriba (el logo) y el formulario
       quedaba clavado en el centro matemático, lo que lo hace ver caído. El
       margen inferior lo sube la mitad de su valor —así funciona el centrado
       flex— sin tocar el centrado horizontal. */
    .form-wrap { margin-bottom: clamp(2rem, 8vh, 5rem); }
}

@media (max-width: 991.98px) {
    .login-shell { grid-template-columns: 1fr; }
    /* En móvil el tejido pasa a ser una franja superior: se conserva la
       identidad sin comerse la pantalla del formulario. */
    .brand { min-height: 230px; padding: 1.75rem 1.5rem; justify-content: center; text-align: center; align-items: center; }
    /* Se oculta .brand-abajo entero (sello + documentos + copyright) y no cada hijo
       por separado: si no, queda un contenedor flex vacío aportando su gap y su
       margin-top. A cambio, el pie legal del formulario —oculto en escritorio
       porque duplicaba al del panel— vuelve a mostrarse: es el único acceso que
       queda a la Política de datos personales y al Código de conducta. */
    .brand .eyebrow, .brand-abajo { display: none; }
    .brand-pie { justify-content: center; }
    .brand-legal { flex-wrap: wrap; justify-content: center; }
    .brand-copy { text-align: center; }
    .ayuda { display: block; }
    .brand-logo { align-items: center; gap: 0; }
    .brand-centro { flex: 0 0 auto; }
    .brand h1 { font-size: 1.55rem; margin: 1rem 0 0; }
    .panel { padding: 2.25rem 1.25rem 3rem; }
}
@media (max-width: 575.98px) {
    .brand { min-height: 190px; }
    .brand h1 { font-size: 1.3rem; }
}

/* Respeta a quien pidió menos movimiento en el sistema operativo. */
@media (prefers-reduced-motion: reduce) {
    .seda path, .brillo, .form-wrap, .login-error.show { animation: none !important; }
    .seda path { opacity: .7; }
}


/* =========================================================================
   RECUPERACIÓN DE CONTRASEÑA
   Piezas que solo usan Views/Recuperarpassword/*. Todo lo demás —panel de marca,
   campos, botón, pie de ayuda— es exactamente el mismo del login: esa es la razón
   de que este archivo exista.
   ========================================================================= */

/* Volver al login: va ARRIBA del título, en el mismo sitio donde el login no tiene
   nada, para que el salto entre las tres pantallas no mueva el bloque de lugar. */
.volver-login {
    display: inline-flex; align-items: center; gap: .4rem;
    margin-bottom: 1.1rem;
    font-size: .82rem; font-weight: 500; text-decoration: none;
    color: var(--erp-text-muted);
    transition: color .15s ease;
}
.volver-login:hover, .volver-login:focus-visible {
    color: rgb(var(--erp-primary-rgb));
    text-decoration: underline; text-underline-offset: 3px;
}

/* Confirmación. Mismo molde que .login-error pero en verde: el mensaje de éxito de
   la recuperación es deliberadamente NEUTRO (no dice si el correo existe), así que
   tiene que leerse como una confirmación tranquila y no como una alerta. */
.login-ok {
    display: none; align-items: flex-start; gap: .55rem;
    margin-bottom: 1.15rem; padding: .75rem .9rem;
    font-size: .85rem; line-height: 1.4;
    color: var(--erp-success);
    background: rgba(var(--erp-success-rgb), .08);
    border: 1px solid rgba(var(--erp-success-rgb), .3);
    border-radius: 12px;
}
.login-ok.show { display: flex; }

/* Nota sobre la vigencia del enlace. */
.aviso-confidencial {
    display: flex; align-items: flex-start; gap: .6rem;
    margin-top: 1.5rem; padding: .85rem .95rem;
    font-size: .8rem; line-height: 1.55;
    color: var(--erp-text-muted);
    background: var(--erp-inner-panel-bg, rgba(148, 163, 184, .07));
    border: 1px solid var(--erp-border-soft);
    border-radius: 12px;
}
.aviso-confidencial i { color: rgb(var(--erp-primary-rgb)); margin-top: .1rem; }
.aviso-confidencial strong { color: var(--erp-text); font-weight: 600; }
.aviso-confidencial a { color: rgb(var(--erp-primary-rgb)); text-decoration: underline; text-underline-offset: 3px; }

/* Medidor de fuerza: cuatro barras y una línea de texto. El nivel lo pone el JS de
   la vista en data-nivel (0..4) y el color sale de la semántica del tema. */
.fuerza { margin-top: .6rem; }
.fuerza-barras { display: flex; gap: .3rem; }
.fuerza-barras span {
    flex: 1; height: 4px; border-radius: 2px;
    background: var(--erp-border-input);
    transition: background .2s ease;
}
.fuerza-texto { margin-top: .4rem; font-size: .76rem; color: var(--erp-text-muted); }
.fuerza[data-nivel="1"] .fuerza-barras span:nth-child(-n+1),
.fuerza[data-nivel="2"] .fuerza-barras span:nth-child(-n+2) { background: var(--erp-danger); }
.fuerza[data-nivel="3"] .fuerza-barras span:nth-child(-n+3) { background: var(--erp-warning); }
.fuerza[data-nivel="4"] .fuerza-barras span { background: var(--erp-success); }

/* Enlace vencido: la pantalla no tiene formulario, así que el bloque se centra y el
   icono hace de título visual. */
.token-invalido { text-align: center; }
.token-invalido .icono-grande {
    display: inline-flex; align-items: center; justify-content: center;
    width: 68px; height: 68px; margin-bottom: 1.1rem;
    font-size: 1.9rem; border-radius: 50%;
    color: var(--erp-warning);
    background: rgba(var(--erp-warning-rgb), .12);
}
.token-invalido .sub { margin-bottom: 1.6rem; }
.token-invalido .btn-ingresar { margin-top: 0; text-decoration: none; }