/* =========================================================================
   PCG · Login -- versión "orbit box" (adaptada de la plantilla que
   compartió el usuario), con la paleta real del sistema PCG.
   -------------------------------------------------------------------------
   Reemplaza a vault-login.css como hoja del login.

   Comportamiento (controlado por pcg-login.js vía data-state en .login-box):
     idle           -> borde/ring neutros (marca PCG)
     focus          -> AMARILLO brillante (clic dentro de cualquier campo)
     authenticating -> se mantiene el color de foco, botón en carga
     error          -> TODO el login (caja + anillo) en ROJO
     success        -> VERDE; los dos campos se funden en un panel con
                        check "AUTORIZADO" que luego da paso al logo PCG

   Tema claro/oscuro: el login ahora sigue el MISMO selector de tema que el
   resto de la plataforma (atributo data-theme en <html>, persistido en
   localStorage bajo la misma llave "pcg-theme" -- ver pcg-login.js). El
   logo PCGRENDER.png en la esquina superior derecha es el interruptor,
   igual que en el header del resto del sitio (app.css / app.js).

   CSP: sin 'unsafe-inline' -- todo vive acá y en pcg-login.js.
   ========================================================================= */

:root {
    /* -------- Tema claro (por defecto) -------- */
    --login-bg: #eef5f3;

    /* Paleta real de PCG (public/assets/css/app.css) */
    --login-brand: #0ea394;
    --login-brand-2: #34d8b0;

    --login-yellow: #c4900c;
    --login-yellow-glow: rgba(196, 144, 12, .40);
    --login-yellow-dim: #f6e3ad;

    --login-green: #0e9463;
    --login-green-glow: rgba(14, 148, 99, .38);
    --login-green-dim: #c9ecdc;

    --login-red: #d6392e;
    --login-red-glow: rgba(214, 57, 46, .36);
    --login-red-dim: #f5d6d2;

    --login-idle-dim: #d7ece7;

    --login-text: #16324f;
    --login-muted: #64748b;
    /* CAMBIOS PCG #1 + #13: glassmorphism al extremo -- el panel vuelve a
       ser bien translúcido (la ronda anterior lo había subido a .68 para
       "que se viera legible", pero el usuario pidió justo lo contrario:
       que la foto de fondo y el vidrio esmerilado se noten de verdad).
       El blur mucho más fuerte (--login-glass) es lo que mantiene el
       texto legible incluso con menos opacidad -- difumina lo que hay
       detrás en vez de taparlo con blanco sólido. */
    --login-panel: rgba(255, 255, 255, .40);
    --login-panel-border: rgba(255, 255, 255, .80);
    --login-panel-solid: #f5f9fd;
    --login-input-bg: rgba(255, 255, 255, .55);
    --login-input-border: rgba(22, 50, 79, .14);
    --login-shadow: 0 1px 0 rgba(255,255,255,.7) inset, 0 34px 80px -24px rgba(15, 42, 60, .40);
    --login-glass: blur(8px) saturate(260%) brightness(1.15) contrast(1.05); /*EL BLUR CONTROLA EL NIVEL DE DIFUMINADO DEL CONTENEDOR DEL LOGIN, ESTABA EN 68px Muy difuminado, a menor valor más transparencia.*/

    --login-logo-filter: none;
    --login-lm-filter: brightness(0) opacity(.82);
    --login-render-filter: brightness(2.2) contrast(1.3) sepia(.9) saturate(3.5) hue-rotate(-10deg);
    --login-render-glow-opacity: 1;

    --login-accent: var(--login-brand);
    --login-accent-glow: rgba(14, 163, 148, .32);
    --login-accent-dim: var(--login-idle-dim);

    /* Anillo orbital -- diámetro base. Todo lo que depende del tamaño del
       anillo (ancho/alto + el radio usado por cada segmento) se deriva de
       esta única variable, así que si la caja crece, basta ajustar este
       valor una vez y el anillo crece proporcionalmente con ella. */
    --login-ring: 264px;

    /* Transición compartida para que ningún cambio de color (foco / error
       / éxito) se sienta como un salto brusco -- todo cruza suavemente. */
    --login-transition: 550ms cubic-bezier(.4, 0, .2, 1);
    --login-transition-slow: 700ms cubic-bezier(.4, 0, .2, 1);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --login-bg: #060b0b;
        --login-brand: #34d8b0;
        --login-brand-2: #7ee8d0;

        --login-yellow: #ffd23f;
        --login-yellow-glow: rgba(255, 210, 63, .48);
        --login-yellow-dim: #4a3a12;

        --login-green: #35d17a;
        --login-green-glow: rgba(53, 209, 122, .48);
        --login-green-dim: #133a26;

        --login-red: #ff5a4d;
        --login-red-glow: rgba(255, 90, 77, .50);
        --login-red-dim: #4a201c;

        --login-idle-dim: #1c3733;

        --login-text: #eaf7f4;
        --login-muted: #8fa8a3;
        --login-panel: rgba(18, 32, 30, .32);
        --login-panel-border: rgba(255, 255, 255, .16);
        --login-panel-solid: #101c1a;
        --login-input-bg: rgba(255, 255, 255, .05);
        --login-input-border: rgba(255, 255, 255, .16);
        --login-shadow: 0 1px 0 rgba(255,255,255,.10) inset, 0 34px 76px -22px rgba(0, 0, 0, .65);
        --login-glass: blur(8px) saturate(280%) brightness(1.16) contrast(1.10);

        --login-lm-filter: brightness(0) invert(1);
        --login-render-filter: brightness(1.2) contrast(1.1) sepia(.3) saturate(2) hue-rotate(-5deg);
        --login-render-glow-opacity: .18;

        --login-accent-glow: rgba(52, 216, 176, .42);
    }
}
:root[data-theme="dark"] {
    --login-bg: #060b0b;
    --login-brand: #34d8b0;
    --login-brand-2: #7ee8d0;

    --login-yellow: #ffd23f;
    --login-yellow-glow: rgba(255, 210, 63, .35);
    --login-yellow-dim: #4a3a12;

    --login-green: #35d17a;
    --login-green-glow: rgba(53, 209, 122, .35);
    --login-green-dim: #133a26;

    --login-red: #ff5a4d;
    --login-red-glow: rgba(255, 90, 77, .38);
    --login-red-dim: #4a201c;

    --login-idle-dim: #1c3733;

    --login-text: #eaf7f4;
    --login-muted: #8fa8a3;
    --login-panel: rgba(18, 32, 30, .32);
    --login-panel-border: rgba(255, 255, 255, .16);
    --login-panel-solid: #101c1a;
    --login-input-bg: rgba(255, 255, 255, .05);
    --login-input-border: rgba(255, 255, 255, .16);
    --login-shadow: 0 1px 0 rgba(255,255,255,.10) inset, 0 34px 76px -22px rgba(0, 0, 0, .65);
    --login-glass: blur(8px) saturate(280%) brightness(1.16) contrast(1.10);

    --login-lm-filter: brightness(0) invert(1);
    --login-render-filter: brightness(1.2) contrast(1.1) sepia(.3) saturate(2) hue-rotate(-5deg);
    --login-render-glow-opacity: .18;

    --login-accent-glow: rgba(52, 216, 176, .30);
}

.pcg-login, .pcg-login *, .pcg-login *::before, .pcg-login *::after {
    box-sizing: border-box;
}
/* Ronda 8 correctiva (referencia visual absoluta del usuario): fondo de
   foto de Valdivia (misma imagen que ya usa el banner de Mi Semana VIP,
   public/assets/images/valdivia-welcome.jpeg -- ningún archivo nuevo)
   desenfocada a pantalla completa, en vez del degradé abstracto de
   antes. Vive en ::before (no en "background" de body directamente) para
   poder aplicarle blur() con filter sin que ese blur alcance también al
   texto/tarjeta -- filter en el propio body difuminaría TODO su
   contenido, no solo el fondo. */
/* CAMBIOS PCG #13: antes este selector era "body:has(.pcg-login)" --
   :has() no tiene soporte universal (Safari/Chrome viejos, algunos
   navegadores corporativos) y cuando no aplica, NO da error ni avisa:
   simplemente el fondo nunca se dibuja, sin que se note por qué. Eso
   explica que la imagen "no se viera en lo absoluto" para el usuario
   aunque las capturas de prueba (con un navegador moderno) sí la
   mostraban. Se reemplaza por una clase directa en <body>
   (.pcg-login-page, ver login.php) que funciona en cualquier navegador. */
body.pcg-login-page {
    margin: 0;
    min-height: 100vh;
    background: var(--login-bg);
    color: var(--login-text);
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    -webkit-font-smoothing: antialiased;
    transition: background 400ms ease, color var(--login-transition);
    position: relative;
}
/* CAMBIOS PCG #1 + #13: el lavado de color sobre la foto (el gradiente
   claro/oscuro superpuesto) bajó bastante de opacidad -- antes ~.55-.62
   casi tapaba la foto entera; ahora se alcanza a reconocer la costanera
   de verdad detrás, como en la imagen de referencia, y el blur baja un
   poco (22px -> 16px) para que se note que ES una foto, no una mancha de
   color lisa. */
/* CAMBIOS PCG #13: la foto se veía "en exceso difuminada" -- blur bajado
   de 16px a 5px (queda nítida sin dejar de leerse como fondo, no como
   protagonista) y el lavado de color de encima bajó de opacidad de nuevo
   (.22/.30 -> .10/.14) para que se reconozca la costanera de verdad, no
   una mancha de color con textura. */
body.pcg-login-page::before {
    content: '';
    position: fixed;
    inset: -3%;
    z-index: 0;
    background-image:
        linear-gradient(180deg, rgba(238,245,251,.10), rgba(226,238,250,.14)),
        url('/assets/images/valdivia-welcome.jpeg');
    background-size: cover;
    background-position: center;
    filter: blur(3px) saturate(128%); /*BLUR: CONTROLA EL NIVEL DE DIFUMINADO DE LA IMAGEN DE FONDO DEL LOGIN. 5px ERA EL ORIGINAL*/
    transform: scale(1.05);
    pointer-events: none;
}
:root[data-theme="dark"] body.pcg-login-page::before {
    background-image:
        linear-gradient(180deg, rgba(6,11,11,.28), rgba(6,11,11,.34)),
        url('/assets/images/valdivia-welcome.jpeg');
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) body.pcg-login-page::before {
        background-image:
            linear-gradient(180deg, rgba(6,11,11,.28), rgba(6,11,11,.34)),
            url('/assets/images/valdivia-welcome.jpeg');
    }
}
.pcg-login {
    position: relative;
    z-index: 1;
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2.5rem 1.25rem;
    overflow-x: hidden;
}
.pcg-login button { font-family: inherit; cursor: pointer; }
.pcg-login input { font-family: inherit; color-scheme: light dark; }

/* =========================================================================
   Fondo -- esferas de agua sutiles y transparentes que se mueven muy
   despacio (item 16 del pedido). position:fixed sobre todo el viewport,
   detrás de la caja/anillo (z-index:0) -- .pcg-login no tiene transform/
   filter/backdrop-filter propio, así que esto queda anclado al viewport
   real, no a un contenedor recortado (ver la nota de "containing block"
   en app.css sobre .header-mascot--free para el mismo cuidado).
   ========================================================================= */
.login-bubbles {
    /* Ocultas (referencia visual absoluta del usuario: ninguna de las 9
       imágenes compartidas muestra esferas de agua) -- se deja el DOM
       intacto en vez de borrarlo en login.php porque pcg-login.js nunca
       lo toca (confirmado), así display:none no cambia ningún
       comportamiento y evita tocar ese script. Las reglas de sus spans
       de más abajo quedan igual (no importan con el padre oculto). */
    display: none;
    position: fixed;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    pointer-events: none;
}
.login-bubbles span {
    position: absolute;
    border-radius: 50%;
    /* Esfera de agua: resalte claro arriba-izquierda que se apaga hacia
       el borde, más un aro finito -- no un círculo de color plano. */
    background: radial-gradient(circle at 32% 26%, rgba(255, 255, 255, .5), rgba(255, 255, 255, .06) 45%, transparent 72%);
    border: 1px solid rgba(255, 255, 255, .16);
    box-shadow: inset 0 0 26px rgba(255, 255, 255, .1), 0 12px 30px -14px rgba(14, 100, 90, .18);
    filter: blur(.5px);
    opacity: .45;
    will-change: transform, opacity;
}
:root[data-theme="dark"] .login-bubbles span { opacity: .3; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .login-bubbles span { opacity: .3; } }
.login-bubbles span:nth-child(1) {
    width: 190px; height: 190px; top: 8%; left: 6%;
    animation: pcgBubbleDrift1 26s ease-in-out infinite;
}
.login-bubbles span:nth-child(2) {
    width: 120px; height: 120px; top: 64%; left: 10%;
    animation: pcgBubbleDrift2 32s ease-in-out infinite; animation-delay: -9s;
}
.login-bubbles span:nth-child(3) {
    width: 270px; height: 270px; bottom: -70px; right: -50px;
    animation: pcgBubbleDrift3 38s ease-in-out infinite; animation-delay: -19s;
}
.login-bubbles span:nth-child(4) {
    width: 95px; height: 95px; top: 18%; right: 12%;
    animation: pcgBubbleDrift4 22s ease-in-out infinite; animation-delay: -5s;
}
@keyframes pcgBubbleDrift1 {
    0%, 100% { transform: translate(0, 0) scale(1); }
    50% { transform: translate(46px, -34px) scale(1.08); }
}
@keyframes pcgBubbleDrift2 {
    0%, 100% { transform: translate(0, 0) scale(1); }
    50% { transform: translate(-30px, 40px) scale(.92); }
}
@keyframes pcgBubbleDrift3 {
    0%, 100% { transform: translate(0, 0) scale(1); }
    50% { transform: translate(-50px, -36px) scale(1.06); }
}
@keyframes pcgBubbleDrift4 {
    0%, 100% { transform: translate(0, 0) scale(1); }
    50% { transform: translate(34px, 44px) scale(.9); }
}
@media (prefers-reduced-motion: reduce) {
    .login-bubbles span { animation: none !important; }
}

/* =========================================================================
   Cabecera de la TARJETA -- escudo municipal (LM.png) a la izquierda,
   interruptor de tema (PCGRENDER.png) a la derecha. Antes vivían fijos en
   las esquinas de la ventana (.login-topbar); referencia visual absoluta
   del usuario: las 9 imágenes compartidas siempre los muestran DENTRO del
   panel de vidrio, así que se mudan a la cabecera de .login-box. Mismo
   id="theme-toggle" de siempre -- pcg-login.js lo busca por id, no le
   importa dónde vive en el DOM.
   ========================================================================= */
.login-box__head {
    position: relative;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: .7rem;
}

.login-box__crest { width: 84px; height: 84px; flex-shrink: 0; transition: filter var(--login-transition); }
.login-box__crest img { width: 100%; height: 100%; object-fit: contain; filter: var(--login-lm-filter); }

.login-box__theme-toggle {
    width: 36px; height: 36px; flex-shrink: 0; position: relative;
    border: none; background: none; padding: 0; cursor: pointer;
}
.login-box__theme-toggle img {
    width: 100%; height: 100%; object-fit: contain; position: relative; z-index: 2;
    filter: var(--login-render-filter);
    transition: filter var(--login-transition), transform 200ms ease;
}
.login-box__theme-toggle:hover img { transform: scale(1.05); }
.login-box__theme-toggle::before {
    content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
    width: 280%; height: 280%;
    background: radial-gradient(ellipse at center, rgba(255, 215, 0, .7) 0%, rgba(255, 215, 0, .3) 40%, rgba(255, 215, 0, 0) 70%);
    filter: blur(16px); pointer-events: none; border-radius: 50%; z-index: 1;
    opacity: var(--login-render-glow-opacity); transition: opacity var(--login-transition);
}
.login-box__theme-toggle::after {
    content: ''; position: absolute; top: 22%; left: 36%; transform: translate(-50%, -50%);
    width: 22px; height: 22px; border-radius: 50%; pointer-events: none; z-index: 3;
    background: radial-gradient(circle, rgba(255, 255, 220, 1) 0%, rgba(255, 240, 150, .95) 25%, rgba(255, 215, 0, .8) 50%, rgba(255, 200, 50, .3) 75%, transparent 100%);
    opacity: .85; filter: blur(1px);
    transition: opacity var(--login-transition), width 200ms ease, height 200ms ease;
}
:root[data-theme="dark"] .login-box__theme-toggle::after { opacity: .2; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .login-box__theme-toggle::after { opacity: .2; } }
.login-box__theme-toggle:hover::before { filter: blur(14px); }
.login-box__theme-toggle:hover::after { width: 30px; height: 30px; opacity: 1; }

/* -------- foto de Valdivia embebida (misma imagen que el fondo) -------- */
.login-box__photo {
    position: relative;
    z-index: 3;
    margin: 0 0 1.1rem;
    border-radius: 16px;
    overflow: hidden;
    box-shadow: 0 10px 26px -14px rgba(15, 42, 38, .35);
}
.login-box__photo img { display: block; width: 100%; height: 128px; object-fit: cover; }
.login-box__photo-caption {
    position: absolute; left: 10px; bottom: 10px;
    display: inline-flex; align-items: center; gap: .35rem;
    padding: .3rem .6rem; border-radius: 999px;
    background: rgba(10, 20, 18, .55);
    color: #fff; font-size: .72rem; font-weight: 700;
    backdrop-filter: blur(6px);
}
.login-box__photo-caption i { color: var(--login-red); font-size: .7rem; }

/* =========================================================================
   Escenario -- envuelve el anillo orbital y la caja. data-state vive acá
   (no en .login-box) porque ambos elementos son hermanos posicionados de
   forma independiente; así una sola fuente de verdad colorea tanto el
   borde/resplandor de la caja como el anillo que la rodea.
   ========================================================================= */
.login-stage {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
}
.login-stage[data-state="focus"],
.login-stage[data-state="authenticating"] {
    --login-accent: var(--login-yellow);
    --login-accent-glow: var(--login-yellow-glow);
    --login-accent-dim: var(--login-yellow-dim);
}
.login-stage[data-state="error"] {
    --login-accent: var(--login-red);
    --login-accent-glow: var(--login-red-glow);
    --login-accent-dim: var(--login-red-dim);
}
.login-stage[data-state="success"] {
    --login-accent: var(--login-green);
    --login-accent-glow: var(--login-green-glow);
    --login-accent-dim: var(--login-green-dim);
}

/* Halo ambiental detrás del anillo: un lavado de color grande y difuso
   que sí se puede cruzar de un color a otro con una transición larga y
   pareja (a diferencia de los segmentos del anillo, que se recolorean en
   cada vuelta de su propia animación). Es lo que hace que el cambio de
   amarillo/verde/rojo se perciba suave en vez de "de golpe". */
.login-stage::before {
    content: '';
    position: absolute;
    inset: -16%;
    z-index: 0;
    background: radial-gradient(circle, var(--login-accent-glow) 0%, transparent 72%);
    filter: blur(42px);
    opacity: 1;
    pointer-events: none;
    transition: background var(--login-transition-slow), opacity var(--login-transition-slow);
}

/* =========================================================================
   Anillo orbital decorativo -- 50 segmentos que "persiguen" la luz
   alrededor de la caja, coloreados según el estado actual. Su tamaño
   sigue la variable --login-ring, así que crece o se achica junto con
   la caja sin tener que tocar cada regla por separado.
   ========================================================================= */
.login-orbit {
    /* Oculto (referencia visual absoluta del usuario: ninguna de las 9
       imágenes muestra un anillo orbital) -- mismo criterio que
       .login-bubbles: se deja el DOM intacto (pcg-login.js nunca lo
       toca) y se apaga solo por CSS. .login-box ya no depende de este
       elemento para su tamaño/centrado, ver la nota junto a
       "position: relative" en .login-box más abajo. */
    display: none;
    position: relative;
    z-index: 1;
    width: var(--login-ring);
    height: var(--login-ring);
    align-items: center;
    justify-content: center;
    pointer-events: none;
}
.login-orbit span {
    position: absolute;
    left: 0;
    width: 22px;
    height: 5px;
    border-radius: 8px;
    /* Aspecto metalizado: una banda de brillo/sombra (como metal cepillado)
       superpuesta al color de acento real con mix-blend-mode -- el
       resultado se ve como si la luz neón del propio segmento fuera
       refractada por una superficie metálica, en vez de un tubo de color
       plano. La capa de color de abajo sigue siendo la variable de estado
       real, así que el metal se tiñe de amarillo/verde/rojo según toque. */
    background:
        linear-gradient(90deg,
            rgba(255, 255, 255, .6) 0%,
            rgba(255, 255, 255, 0) 20%,
            rgba(0, 0, 0, .35) 48%,
            rgba(255, 255, 255, .5) 72%,
            rgba(255, 255, 255, 0) 100%),
        var(--login-accent-dim);
    background-blend-mode: overlay;
    transform-origin: calc(var(--login-ring) / 2);
    animation: pcgOrbitChase 3s linear infinite;
    /* Halo permanente y sutil incluso "apagado" -- un tubo de neón real
       nunca se ve completamente negro entre destellos, solo menos vívido. */
    box-shadow: 0 0 5px var(--login-accent-glow);
    transition: background var(--login-transition), box-shadow var(--login-transition);
}
@keyframes pcgOrbitChase {
    0% {
        background:
            linear-gradient(90deg,
                rgba(255, 255, 255, .75) 0%,
                rgba(255, 255, 255, 0) 20%,
                rgba(0, 0, 0, .3) 48%,
                rgba(255, 255, 255, .6) 72%,
                rgba(255, 255, 255, 0) 100%),
            var(--login-accent);
        background-blend-mode: overlay;
        /* Neón en capas: núcleo compacto y brillante + dos halos cada vez
           más anchos y difusos, como un tubo de neón real visto de cerca. */
        box-shadow:
            0 0 4px var(--login-accent),
            0 0 12px var(--login-accent-glow),
            0 0 26px var(--login-accent-glow),
            0 0 44px var(--login-accent-glow);
    }
    25% {
        background:
            linear-gradient(90deg,
                rgba(255, 255, 255, .6) 0%,
                rgba(255, 255, 255, 0) 20%,
                rgba(0, 0, 0, .35) 48%,
                rgba(255, 255, 255, .5) 72%,
                rgba(255, 255, 255, 0) 100%),
            var(--login-accent-dim);
        background-blend-mode: overlay;
        box-shadow: 0 0 5px var(--login-accent-glow);
    }
}

/* Ángulo y demora de cada uno de los 50 segmentos. Valores fijos (en vez
   de la custom property --i por elemento de la plantilla original) para
   cumplir la CSP del sitio: style-src no permite 'unsafe-inline', así
   que ningún <span> lleva atributo style="" -- ver app/Views/auth/login.php.
   El radio real del círculo lo da transform-origin (arriba, ligado a
   --login-ring); acá solo se fija el ángulo de cada segmento. */
.login-orbit span:nth-child(1) { transform: scale(2.2) rotate(0deg); animation-delay: 0s; }
.login-orbit span:nth-child(2) { transform: scale(2.2) rotate(7.2deg); animation-delay: 0.06s; }
.login-orbit span:nth-child(3) { transform: scale(2.2) rotate(14.4deg); animation-delay: 0.12s; }
.login-orbit span:nth-child(4) { transform: scale(2.2) rotate(21.6deg); animation-delay: 0.18s; }
.login-orbit span:nth-child(5) { transform: scale(2.2) rotate(28.8deg); animation-delay: 0.24s; }
.login-orbit span:nth-child(6) { transform: scale(2.2) rotate(36deg); animation-delay: 0.3s; }
.login-orbit span:nth-child(7) { transform: scale(2.2) rotate(43.2deg); animation-delay: 0.36s; }
.login-orbit span:nth-child(8) { transform: scale(2.2) rotate(50.4deg); animation-delay: 0.42s; }
.login-orbit span:nth-child(9) { transform: scale(2.2) rotate(57.6deg); animation-delay: 0.48s; }
.login-orbit span:nth-child(10) { transform: scale(2.2) rotate(64.8deg); animation-delay: 0.54s; }
.login-orbit span:nth-child(11) { transform: scale(2.2) rotate(72deg); animation-delay: 0.6s; }
.login-orbit span:nth-child(12) { transform: scale(2.2) rotate(79.2deg); animation-delay: 0.66s; }
.login-orbit span:nth-child(13) { transform: scale(2.2) rotate(86.4deg); animation-delay: 0.72s; }
.login-orbit span:nth-child(14) { transform: scale(2.2) rotate(93.6deg); animation-delay: 0.78s; }
.login-orbit span:nth-child(15) { transform: scale(2.2) rotate(100.8deg); animation-delay: 0.84s; }
.login-orbit span:nth-child(16) { transform: scale(2.2) rotate(108deg); animation-delay: 0.9s; }
.login-orbit span:nth-child(17) { transform: scale(2.2) rotate(115.2deg); animation-delay: 0.96s; }
.login-orbit span:nth-child(18) { transform: scale(2.2) rotate(122.4deg); animation-delay: 1.02s; }
.login-orbit span:nth-child(19) { transform: scale(2.2) rotate(129.6deg); animation-delay: 1.08s; }
.login-orbit span:nth-child(20) { transform: scale(2.2) rotate(136.8deg); animation-delay: 1.14s; }
.login-orbit span:nth-child(21) { transform: scale(2.2) rotate(144deg); animation-delay: 1.2s; }
.login-orbit span:nth-child(22) { transform: scale(2.2) rotate(151.2deg); animation-delay: 1.26s; }
.login-orbit span:nth-child(23) { transform: scale(2.2) rotate(158.4deg); animation-delay: 1.32s; }
.login-orbit span:nth-child(24) { transform: scale(2.2) rotate(165.6deg); animation-delay: 1.38s; }
.login-orbit span:nth-child(25) { transform: scale(2.2) rotate(172.8deg); animation-delay: 1.44s; }
.login-orbit span:nth-child(26) { transform: scale(2.2) rotate(180deg); animation-delay: 1.5s; }
.login-orbit span:nth-child(27) { transform: scale(2.2) rotate(187.2deg); animation-delay: 1.56s; }
.login-orbit span:nth-child(28) { transform: scale(2.2) rotate(194.4deg); animation-delay: 1.62s; }
.login-orbit span:nth-child(29) { transform: scale(2.2) rotate(201.6deg); animation-delay: 1.68s; }
.login-orbit span:nth-child(30) { transform: scale(2.2) rotate(208.8deg); animation-delay: 1.74s; }
.login-orbit span:nth-child(31) { transform: scale(2.2) rotate(216deg); animation-delay: 1.8s; }
.login-orbit span:nth-child(32) { transform: scale(2.2) rotate(223.2deg); animation-delay: 1.86s; }
.login-orbit span:nth-child(33) { transform: scale(2.2) rotate(230.4deg); animation-delay: 1.92s; }
.login-orbit span:nth-child(34) { transform: scale(2.2) rotate(237.6deg); animation-delay: 1.98s; }
.login-orbit span:nth-child(35) { transform: scale(2.2) rotate(244.8deg); animation-delay: 2.04s; }
.login-orbit span:nth-child(36) { transform: scale(2.2) rotate(252deg); animation-delay: 2.1s; }
.login-orbit span:nth-child(37) { transform: scale(2.2) rotate(259.2deg); animation-delay: 2.16s; }
.login-orbit span:nth-child(38) { transform: scale(2.2) rotate(266.4deg); animation-delay: 2.22s; }
.login-orbit span:nth-child(39) { transform: scale(2.2) rotate(273.6deg); animation-delay: 2.28s; }
.login-orbit span:nth-child(40) { transform: scale(2.2) rotate(280.8deg); animation-delay: 2.34s; }
.login-orbit span:nth-child(41) { transform: scale(2.2) rotate(288deg); animation-delay: 2.4s; }
.login-orbit span:nth-child(42) { transform: scale(2.2) rotate(295.2deg); animation-delay: 2.46s; }
.login-orbit span:nth-child(43) { transform: scale(2.2) rotate(302.4deg); animation-delay: 2.52s; }
.login-orbit span:nth-child(44) { transform: scale(2.2) rotate(309.6deg); animation-delay: 2.58s; }
.login-orbit span:nth-child(45) { transform: scale(2.2) rotate(316.8deg); animation-delay: 2.64s; }
.login-orbit span:nth-child(46) { transform: scale(2.2) rotate(324deg); animation-delay: 2.7s; }
.login-orbit span:nth-child(47) { transform: scale(2.2) rotate(331.2deg); animation-delay: 2.76s; }
.login-orbit span:nth-child(48) { transform: scale(2.2) rotate(338.4deg); animation-delay: 2.82s; }
.login-orbit span:nth-child(49) { transform: scale(2.2) rotate(345.6deg); animation-delay: 2.88s; }
.login-orbit span:nth-child(50) { transform: scale(2.2) rotate(352.8deg); animation-delay: 2.94s; }

/* =========================================================================
   Caja de login
   ========================================================================= */
.login-box {
    /* Antes "absolute" (centrado por el flex de .login-stage sobre un
       contenedor vacío, con el tamaño real puesto por .login-orbit) --
       con el anillo oculto (ver nota junto a .login-bubbles) ya no hay
       nada que le dé tamaño a .login-stage, así que .login-box pasa a
       flujo normal: es un hijo centrado más de ese mismo flex, y ahora
       es ÉL quien le da su tamaño real a .login-stage. Mismo
       centrado visual, más robusto. */
    position: relative;
    z-index: 1;
    width: min(430px, 92vw);
    padding: 1.8rem 2rem 1.7rem;
    border-radius: 26px;
    /* Antes tenía un segundo reflejo estático (gradiente 155deg) además
       del barrido diagonal animado de .login-box::before -- a pedido
       explícito del usuario se deja UN SOLO reflejo (el diagonal
       animado); acá solo queda el panel de vidrio real. */
    background: var(--login-panel);
    border: 1px solid var(--login-panel-border);
    box-shadow: var(--login-shadow);
    backdrop-filter: var(--login-glass);
    -webkit-backdrop-filter: var(--login-glass);
    transition: border-color var(--login-transition), box-shadow var(--login-transition),
        background var(--login-transition-slow);
}
/* CAMBIOS PCG #10: se elimina el reflejo/barrido diagonal que recorría la
   tarjeta (.login-box::before + @keyframes pcgLoginShine) -- la referencia
   no lo tiene. Queda solo el panel de vidrio real (--login-glass). */
.login-stage[data-state="focus"] .login-box,
.login-stage[data-state="authenticating"] .login-box {
    border-color: var(--login-yellow);
    box-shadow:
        0 0 0 1px var(--login-yellow-glow),
        0 0 18px var(--login-yellow-glow),
        0 0 42px var(--login-yellow-glow),
        0 0 70px var(--login-yellow-glow),
        var(--login-shadow);
}
.login-stage[data-state="error"] .login-box {
    border-color: var(--login-red);
    box-shadow:
        0 0 0 1px var(--login-red-glow),
        0 0 18px var(--login-red-glow),
        0 0 42px var(--login-red-glow),
        0 0 70px var(--login-red-glow),
        var(--login-shadow);
    animation: pcgLoginShake 420ms ease;
}
.login-stage[data-state="success"] .login-box {
    border-color: var(--login-green);
    box-shadow:
        0 0 0 1px var(--login-green-glow),
        0 0 20px var(--login-green-glow),
        0 0 48px var(--login-green-glow),
        0 0 80px var(--login-green-glow),
        var(--login-shadow);
}
@keyframes pcgLoginShake {
    0%, 100% { transform: translateX(0); }
    20% { transform: translateX(-6px); }
    40% { transform: translateX(6px); }
    60% { transform: translateX(-3px); }
    80% { transform: translateX(3px); }
}

/* -------- título: "¡Bienvenido!" + logo pequeño + insignia -------- */
.login-box__title {
    position: relative;
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    margin-bottom: .6rem;
}
.login-logo {
    display: block;
    max-width: 640px;
    width: 80%;
    height: auto;
    margin-bottom: .5rem;
    filter: var(--login-logo-filter);
    transition: filter var(--login-transition), transform 220ms ease;
}
.login-logo:hover { transform: scale(1.02); }
.login-box__title h1 {
    margin: 0;
    font-size: 1.55rem;
    font-weight: 800;
    color: var(--login-green);
    letter-spacing: -.01em;
}
.login-box__title p {
    margin: .3rem 0 .7rem;
    font-size: .84rem;
    color: var(--login-muted);
    font-weight: 500;
}
.login-box__badge {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .35rem .85rem;
    border-radius: 999px;
    background: linear-gradient(135deg, #ffe9ad, #f0c563);
    color: #6b4a06;
    font-size: .74rem;
    font-weight: 800;
    letter-spacing: .02em;
    box-shadow: 0 8px 18px -10px rgba(196, 144, 12, .55);
}
.login-box__tag {
    position: relative;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    margin: .7rem 0 0;
    padding: .5rem .9rem;
    border-radius: 999px;
    background: var(--login-green-dim);
    color: var(--login-green);
    font-size: .78rem;
    font-weight: 700;
    text-align: center;
}
:root[data-theme="dark"] .login-box__tag { background: rgba(53, 209, 122, .16); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .login-box__tag { background: rgba(53, 209, 122, .16); } }

.login-box__divider {
    position: relative;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 1.1rem 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--login-panel-border) 30%, var(--login-panel-border) 70%, transparent);
}
.login-box__divider i {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px; border-radius: 50%;
    background: var(--login-panel-solid);
    color: var(--login-green);
    font-size: .68rem;
    box-shadow: 0 0 0 1px var(--login-panel-border);
}

.login-box__help, .login-box__footer {
    position: relative;
    z-index: 3;
    text-align: center;
    font-size: .74rem;
    color: var(--login-muted);
    margin: 0;
}
.login-box__help { margin-top: 1.1rem; }
.login-box__help i { color: var(--login-brand); margin-right: .3rem; }
.login-box__footer { margin-top: .55rem; padding-top: .8rem; border-top: 1px solid var(--login-panel-border); }
.login-box__footer span { color: var(--login-brand-2); font-weight: 700; }

/* -------- campos -------- */
.login-fields {
    display: block;
    overflow: visible;
}
/* CAMBIOS PCG #12: placeholders "tradicionales" -- .input-box ahora es un
   bloque normal (label arriba, campo abajo), no un contenedor con una
   etiqueta flotando ENCIMA del texto. */
.input-box {
    position: relative;
    margin: 0 0 20px;
    /* CAMBIOS PCG #9: 90px alcanzaba para label+input; ahora el campo de
       RUT suma además .rut-feedback debajo (~20px), así que sube a
       116px -- solo importa en el estado de reposo, en "success" sigue
       colapsando a 0 igual que antes. */
    max-height: 116px;
    opacity: 1;
    transform: translateY(0);
    transition: max-height 500ms ease, opacity 350ms ease, margin 500ms ease, transform 400ms ease;
}
.input-box label {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin-bottom: .4rem;
    font-size: .8em;
    font-weight: 700;
    color: var(--login-text);
    transition: color var(--login-transition);
}
.input-box label i { font-size: .85em; color: var(--login-brand); flex-shrink: 0; }
.login-stage[data-state="focus"] .input-box label,
.login-stage[data-state="authenticating"] .input-box label { color: var(--login-yellow); }
.login-stage[data-state="error"] .input-box label { color: var(--login-red); }

/* Envuelve solo el <input> -- posicionamiento relativo aparte de <label>
   porque acá adentro vive también .rut-liquid (ítem #11, ver abajo). */
.input-box__control { position: relative; }
.input-box input {
    position: relative;
    z-index: 1;
    width: 100%;
    height: 50px;
    background: var(--login-input-bg);
    border: 2px solid var(--login-input-border);
    outline: none;
    border-radius: 16px;
    font-size: .95em;
    font-weight: 700;
    letter-spacing: .01em;
    color: var(--login-text);
    padding: 0 18px;
    transition: border-color var(--login-transition), background var(--login-transition);
}
.input-box input::placeholder { color: var(--login-muted); opacity: .8; font-weight: 500; }
.input-box input:disabled { opacity: .55; }
.login-stage[data-state="focus"] .input-box input,
.login-stage[data-state="authenticating"] .input-box input { border-color: var(--login-yellow); }
.login-stage[data-state="error"] .input-box input { border-color: var(--login-red); }

/* =========================================================================
   CAMBIOS PCG #9/#11: caja de RUT.
   - .rut-liquid vive DETRÁS del <input> (mismo .input-box__control,
     z-index 0 contra el z-index 1 del input) y con el input SIN su
     propio fondo (--login-input-bg pasa a esta capa) para que el agua se
     alcance a ver a través. El propio <input> queda transparente (ver
     .input-box--rut input más abajo) -- el texto que se escribe queda
     siempre legible porque flota encima del agua, nunca detrás.
   - .rut-liquid__fill crece de izquierda a derecha con clases de paso
     fijo (--p0 .. --p100, togglendas por pcg-login.js según cuánto se ha
     escrito) -- nunca con el.style.width (CSP style-src sin
     'unsafe-inline', misma regla que el resto del archivo).
   - Colores: turquesa de marca (--login-brand/--login-brand-2), NO el
     degradé rojo/amarillo/verde de .login-success__fill-liquid -- ese
     degradé queda reservado para la fase de "carga tras validar" (ítem
     #10), para que ambos efectos de agua se lean como momentos
     distintos (llenándose mientras se escribe vs. confirmado por el
     servidor).
   ========================================================================= */
.input-box--rut input {
    background: transparent;
    caret-color: var(--login-brand);
}
.rut-liquid {
    position: absolute;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    border-radius: 14px;
    background: var(--login-input-bg);
    pointer-events: none;
}
/* CAMBIOS PCG #15: rediseño explícito a pedido del usuario -- el reflejo
   diagonal (pcgLiquidGlare) y la textura de olitas que recorría la
   superficie EN HORIZONTAL (pcgWaveScroll) quedaban lindos pero no eran
   lo que se pidió: "no quiero un simple reflejo que simule ondas... y
   quita los reflejos". Se reemplaza todo por dos efectos distintos,
   ninguno con movimiento horizontal:
     1) El propio BORDE que avanza (el límite del relleno) ondula en su
        lugar -- clip-path: polygon(...) con un zigzag suave en el lado
        derecho, animado entre dos formas (pcgLiquidWave) para que el
        borde se sienta vivo/ondulante. clip-path es puramente CSS
        (CSP-safe) y recorta TODO lo que hay dentro del elemento --
        incluido su ::before -- así que las burbujas de abajo también
        quedan automáticamente contenidas dentro de esa forma ondulada,
        sin necesitar un segundo recorte.
     2) ::before -- burbujas chicas (varias capas de radial-gradient,
        cada una de un tamaño/posición distinto) que SUBEN en bucle
        (pcgBubblesRise, solo background-position-y, nunca X) para el
        efecto "efervescente" pedido.
   Las @keyframes (pcgLiquidWave/pcgBubblesRise) se declaran una sola vez
   acá y las reutiliza también .login-success__fill-liquid (barra
   0->100% tras validar, ver más abajo) para que ambos momentos del
   "agua" se lean como el mismo efecto. prefers-reduced-motion ya las
   apaga todas de golpe (regla global .pcg-login * al final del
   archivo).
   CAMBIOS PCG #17: a pedido explícito -- 1) la amplitud de la ola baja
   de ~3 puntos porcentuales a 0.9 (ver @keyframes pcgLiquidWave más
   abajo), para que el borde ondule apenas, "muy sutil", en vez de
   notarse a simple vista. 2) se agrega un efecto de VIDRIO real:
   backdrop-filter (blur + saturate) sobre el propio relleno, que
   difumina/satura lo que se alcanza a ver A TRAVÉS de él (el fondo de
   .rut-liquid detrás, y la caja de vidrio del login detrás de eso) --
   esó es lo que da la sensación de "mirar a través de un vidrio
   esmerilado teñido de turquesa", no un brillo blanco pintado encima.
   El box-shadow también se reemplaza: antes era un halo blanco amplio
   (inset 0 0 16px) que se leía como "brillo"; ahora es un filo fino de
   luz arriba (el menisco real de un líquido, 1px) más una sombra
   interior muy sutil, sin ninguna capa blanca grande. */
.rut-liquid__fill {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 0%;
    background: linear-gradient(90deg, rgba(14, 163, 148, .45), rgba(52, 216, 176, .62));
    backdrop-filter: blur(3px) saturate(165%);
    -webkit-backdrop-filter: blur(3px) saturate(165%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .30),
        inset 0 -1px 0 rgba(4, 35, 29, .12),
        inset 0 0 10px rgba(4, 35, 29, .05);
    transition: width 260ms cubic-bezier(.4, 0, .2, 1);
    clip-path: polygon(0% 0%, 0% 100%, 99.0% 100%, 97.9% 95%, 97.3% 90%, 97.3% 85%, 97.9% 80%, 99.0% 75%, 100.0% 70%, 100.0% 65%, 100.0% 60%, 100.0% 55%, 99.0% 50%, 97.9% 45%, 97.3% 40%, 97.3% 35%, 97.9% 30%, 99.0% 25%, 100.0% 20%, 100.0% 15%, 100.0% 10%, 100.0% 5%, 99.0% 0%);
    animation: pcgLiquidWave 3.6s linear infinite;
}
/* CAMBIOS PCG #18: a pedido explícito -- el intento anterior (9 capas
   de 1-1.8px, transparent 60%) las dejó casi invisibles. Se vuelve a
   burbujas GRANDES y de borde casi sólido (transparent 85%, muy poco
   "difuminado" en el centro) como las tenía el usuario originalmente
   (circle 4-5px, transparent 90%) -- pero en vez de 5 capas quedan 9,
   así se gana la sensación "efervescente" (más burbujas, ritmos de
   subida distintos) sin sacrificar tamaño/visibilidad. */
.rut-liquid__fill::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image:
        radial-gradient(circle 5px at 12% 85%, rgba(255, 255, 255, .9), transparent 85%),
        radial-gradient(circle 3.5px at 25% 68%, rgba(255, 255, 255, .75), transparent 85%),
        radial-gradient(circle 6px at 38% 90%, rgba(255, 255, 255, .65), transparent 85%),
        radial-gradient(circle 4px at 50% 62%, rgba(255, 255, 255, .8), transparent 85%),
        radial-gradient(circle 5.5px at 62% 88%, rgba(255, 255, 255, .7), transparent 85%),
        radial-gradient(circle 3px at 72% 70%, rgba(255, 255, 255, .85), transparent 85%),
        radial-gradient(circle 6.5px at 82% 92%, rgba(255, 255, 255, .6), transparent 85%),
        radial-gradient(circle 4.5px at 90% 65%, rgba(255, 255, 255, .78), transparent 85%),
        radial-gradient(circle 5px at 96% 84%, rgba(255, 255, 255, .72), transparent 85%);
    background-repeat: repeat-y;
    background-size: 100% 46px, 100% 34px, 100% 58px, 100% 40px, 100% 50px, 100% 30px, 100% 64px, 100% 44px, 100% 48px;
    animation: pcgBubblesRise 2.6s linear infinite;
}
/* CAMBIOS PCG #16: a pedido explícito -- el zigzag de pocos puntos se
   veía "puntiagudo" (líneas rectas entre vértices muy separados, sin
   curvatura real) y el vaivén "alternate" entre dos formas se sentía
   como un bamboleo en el lugar, no como una ola viajando. Se reemplaza
   por:
     1) Un polygon() de 21 puntos (cada 5% de alto) en vez de 11 -- con
        tantos vértices juntos, los tramos rectos entre ellos son tan
        cortos que el ojo los lee como una curva suave (sinusoide), no
        como triángulos.
     2) 6 pasos de keyframe (0/20/40/60/80/100%) en vez de un simple
        from/to -- cada paso es la MISMA onda pero con la fase corrida
        matemáticamente un poco hacia arriba (el punto que en un paso
        está en cierta altura, en el siguiente paso aparece un poco más
        arriba en la misma forma) -- así se lee como una ola real
        subiendo, no como un rebote de ida y vuelta. El paso "100%" es
        IDÉNTICO al "0%" a propósito (una fase completa = un ciclo de la
        onda) para que el loop no tenga ningún salto visible al
        reiniciar. animation: ...linear infinite (nunca alternate, para
        que el movimiento sea siempre hacia el mismo lado: arriba).
   Compartidas por .rut-liquid__fill y .login-success__fill-liquid (ver
   comentario más arriba). */
@keyframes pcgLiquidWave {
    0% { clip-path: polygon(0% 0%, 0% 100%, 99.0% 100%, 97.9% 95%, 97.3% 90%, 97.3% 85%, 97.9% 80%, 99.0% 75%, 100.0% 70%, 100.0% 65%, 100.0% 60%, 100.0% 55%, 99.0% 50%, 97.9% 45%, 97.3% 40%, 97.3% 35%, 97.9% 30%, 99.0% 25%, 100.0% 20%, 100.0% 15%, 100.0% 10%, 100.0% 5%, 99.0% 0%); }
    20% { clip-path: polygon(0% 0%, 0% 100%, 100.0% 100%, 100.0% 95%, 99.0% 90%, 97.9% 85%, 97.3% 80%, 97.3% 75%, 97.9% 70%, 99.0% 65%, 100.0% 60%, 100.0% 55%, 100.0% 50%, 100.0% 45%, 99.0% 40%, 97.9% 35%, 97.3% 30%, 97.3% 25%, 97.9% 20%, 99.0% 15%, 100.0% 10%, 100.0% 5%, 100.0% 0%); }
    40% { clip-path: polygon(0% 0%, 0% 100%, 100.0% 100%, 100.0% 95%, 100.0% 90%, 100.0% 85%, 99.0% 80%, 97.9% 75%, 97.3% 70%, 97.3% 65%, 97.9% 60%, 99.0% 55%, 100.0% 50%, 100.0% 45%, 100.0% 40%, 100.0% 35%, 99.0% 30%, 97.9% 25%, 97.3% 20%, 97.3% 15%, 97.9% 10%, 99.0% 5%, 100.0% 0%); }
    60% { clip-path: polygon(0% 0%, 0% 100%, 97.9% 100%, 99.0% 95%, 100.0% 90%, 100.0% 85%, 100.0% 80%, 100.0% 75%, 99.0% 70%, 97.9% 65%, 97.3% 60%, 97.3% 55%, 97.9% 50%, 99.0% 45%, 100.0% 40%, 100.0% 35%, 100.0% 30%, 100.0% 25%, 99.0% 20%, 97.9% 15%, 97.3% 10%, 97.3% 5%, 97.9% 0%); }
    80% { clip-path: polygon(0% 0%, 0% 100%, 97.3% 100%, 97.3% 95%, 97.9% 90%, 99.0% 85%, 100.0% 80%, 100.0% 75%, 100.0% 70%, 100.0% 65%, 99.0% 60%, 97.9% 55%, 97.3% 50%, 97.3% 45%, 97.9% 40%, 99.0% 35%, 100.0% 30%, 100.0% 25%, 100.0% 20%, 100.0% 15%, 99.0% 10%, 97.9% 5%, 97.3% 0%); }
    100% { clip-path: polygon(0% 0%, 0% 100%, 99.0% 100%, 97.9% 95%, 97.3% 90%, 97.3% 85%, 97.9% 80%, 99.0% 75%, 100.0% 70%, 100.0% 65%, 100.0% 60%, 100.0% 55%, 99.0% 50%, 97.9% 45%, 97.3% 40%, 97.3% 35%, 97.9% 30%, 99.0% 25%, 100.0% 20%, 100.0% 15%, 100.0% 10%, 100.0% 5%, 99.0% 0%); }
}
@keyframes pcgBubblesRise {
    from { background-position: 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0; }
    to { background-position: 0 -46px, 0 -34px, 0 -58px, 0 -40px, 0 -50px, 0 -30px, 0 -64px, 0 -44px, 0 -48px; }
}
.rut-liquid__fill--p0 { width: 0%; }
.rut-liquid__fill--p10 { width: 10%; }
.rut-liquid__fill--p20 { width: 20%; }
.rut-liquid__fill--p30 { width: 30%; }
.rut-liquid__fill--p40 { width: 40%; }
.rut-liquid__fill--p50 { width: 50%; }
.rut-liquid__fill--p60 { width: 60%; }
.rut-liquid__fill--p70 { width: 70%; }
.rut-liquid__fill--p80 { width: 80%; }
.rut-liquid__fill--p90 { width: 90%; }
.rut-liquid__fill--p100 {
    width: 100%;
    /* Al completarse, un brillo interior levemente más marcado -- refuerza
       "lleno" antes incluso de que llegue el mensaje de validez. */
    box-shadow: inset 0 0 20px rgba(255, 255, 255, .32);
}

/* .login-stage delante a propósito: sube la especificidad a la par de
   ".login-stage[data-state=focus] .input-box input" (ver más arriba) --
   sin esto, escribir un RUT inválido mientras el campo sigue enfocado
   dejaba el borde AMARILLO de foco ganando por especificidad, tapando el
   rojo de "inválido" que se supone debe verse de inmediato. */
.login-stage .input-box--rut.is-rut-valid input { border-color: var(--login-green); }
.login-stage .input-box--rut.is-rut-invalid input { border-color: var(--login-red); }
/* El agua misma también cambia de color con la validez -- verde cuando
   el RUT ya cierra bien, rojo cuando el dígito verificador no calza --
   así el efecto "líquido" refuerza el mismo mensaje que el texto de
   abajo, no solo el borde. */
.input-box--rut.is-rut-valid .rut-liquid__fill {
    background: linear-gradient(90deg, rgba(14, 148, 99, .48), rgba(53, 209, 122, .64));
}
.input-box--rut.is-rut-invalid .rut-liquid__fill {
    background: linear-gradient(90deg, rgba(198, 52, 42, .42), rgba(230, 96, 82, .56));
}

/* Mensaje "RUT válido"/"RUT inválido" -- independiente de .login-status
   (esa línea queda solo para el resultado del envío al servidor, nunca
   se pisan entre sí). */
.rut-feedback {
    display: flex;
    align-items: center;
    gap: .35rem;
    margin: .4rem 0 0;
    padding-left: .2rem;
    font-size: .76rem;
    font-weight: 700;
    min-height: 1rem;
    opacity: 0;
    transform: translateY(-2px);
    transition: opacity 200ms ease, transform 200ms ease;
}
.rut-feedback.is-visible { opacity: 1; transform: translateY(0); }
.rut-feedback.is-valid { color: var(--login-green); }
.rut-feedback.is-invalid { color: var(--login-red); }
.login-stage[data-state="success"] .rut-feedback { opacity: 0; }

/* Cuando la caja entra en estado de éxito, los campos y el botón se
   colapsan (se "funden") para dejar paso al panel de éxito. */
.login-stage[data-state="success"] .input-box,
.login-stage[data-state="success"] #login-button {
    max-height: 0;
    opacity: 0;
    margin: 0;
    padding-top: 0;
    padding-bottom: 0;
    pointer-events: none;
    transform: translateY(-6px);
}
.login-stage[data-state="success"] .login-status { opacity: 0; max-height: 0; margin: 0; }

/* -------- estado / mensaje (aria-live) -------- */
.login-status {
    min-height: 1.1rem;
    margin: -10px 0 14px;
    font-size: .82em;
    font-weight: 600;
    text-align: center;
    transition: opacity 300ms ease, max-height 300ms ease, margin 300ms ease;
}
.login-status__line { opacity: 0; transition: opacity 250ms ease, color var(--login-transition); }
.login-status__line.is-visible { opacity: 1; }
.login-stage[data-state="error"] .login-status__line { color: var(--login-red); }

/* -------- botón -------- */
#login-button {
    position: relative;
    width: 100%;
    height: 48px;
    border: none;
    outline: none;
    border-radius: 40px;
    font-size: 1em;
    font-weight: 700;
    letter-spacing: .02em;
    color: #04231d;
    background: linear-gradient(135deg, var(--login-brand-2), var(--login-brand));
    box-shadow: 0 10px 26px -10px rgba(52, 216, 176, .5);
    transition: transform 180ms ease, box-shadow var(--login-transition), opacity 200ms ease,
        background var(--login-transition);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.login-stage[data-state="focus"] #login-button,
.login-stage[data-state="authenticating"] #login-button {
    background: linear-gradient(135deg, #ffe27a, var(--login-yellow));
}
#login-button:hover:not(:disabled) { transform: translateY(-1px); }
#login-button:disabled { cursor: not-allowed; opacity: .8; }
#login-button .btn-spinner { display: none; align-items: center; gap: .5rem; }
#login-button.is-loading .btn-label { display: none; }
#login-button.is-loading .btn-spinner { display: inline-flex; }
.btn-spinner__ring {
    width: 15px; height: 15px; border-radius: 50%;
    border: 2px solid rgba(4, 35, 29, .35);
    border-top-color: #04231d;
    animation: pcgLoginSpin 700ms linear infinite;
}
@keyframes pcgLoginSpin { to { transform: rotate(360deg); } }

/* =========================================================================
   CAMBIOS PCG #9/#11: .login-form-stage envuelve <form> y .login-success
   como HERMANOS. min-height es el alto real del campo de RUT (label ~20px
   + gap .4rem + input 50px + rut-feedback ~20px + margin 20px = 116px) +
   el mensaje de estado (~22px) + el botón (48px) -- ese "piso" fijo es lo
   que evita que la TARJETA entera se achique cuando el campo colapsa a
   max-height:0 en el estado "success" (antes no existía este límite, así
   que la caja se encogía). Con position:relative acá (no en .login-box),
   .login-success (inset:0) cae EXACTO sobre el área del campo, ni un
   pixel más arriba/abajo, sin necesidad de un inset calculado a mano. */
.login-form-stage {
    position: relative;
    min-height: 200px;
}
.login-success {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transform: scale(.94);
    pointer-events: none;
    transition: opacity 450ms ease, transform 450ms ease;
}
.login-stage[data-state="success"] .login-success {
    opacity: 1;
    transform: scale(1);
}
.login-success__check {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .6rem;
    transition: opacity 500ms ease, transform 500ms ease;
}
.login-success__check {
    color: var(--login-green);
    /* Antes visible desde el inicio del estado "success"; ahora hay una
       fase previa (.login-success__fill, el líquido 0-100%) delante suyo,
       así que arranca oculto y solo aparece cuando JS agrega .is-checked
       a .login-box (ver pcg-login.js: startSuccessSequence). */
    opacity: 0;
    transform: scale(.9);
}
.login-box.is-checked .login-success__check {
    opacity: 1;
    transform: scale(1);
}
.login-success__check i {
    font-size: 2.6rem;
    filter: drop-shadow(0 0 16px var(--login-green-glow));
}
.login-success__check span {
    font-size: .82rem;
    font-weight: 800;
    letter-spacing: .22em;
}
/* Fase 0 -- "líquido" verde que se llena de 0 a 100% (ver login.php e
   ítem 15 del pedido). Vive delante de .login-success__check y se oculta
   apenas pcg-login.js agrega .is-checked a .login-box (mismo mecanismo
   que .is-revealed más abajo, pero un paso antes). */
.login-success__fill {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .9rem;
    opacity: 1;
    transform: scale(1);
    transition: opacity 400ms ease, transform 400ms ease;
}
.login-box.is-checked .login-success__fill,
.login-box.is-revealed .login-success__fill {
    opacity: 0;
    transform: scale(.92);
    pointer-events: none;
}
.login-success__fill-track {
    position: relative;
    width: 78%;
    max-width: 230px;
    height: 44px;
    border-radius: 999px;
    border: 1px solid var(--login-panel-border);
    background: rgba(127, 127, 127, .16);
    overflow: hidden;
    box-shadow: inset 0 2px 10px rgba(0, 0, 0, .25);
}
/* Relleno HORIZONTAL (izquierda -> derecha), no vertical: crece en
   "width" (no "height") desde el borde izquierdo del track. El
   degradé rojo/amarillo/verde vive fijo cubriendo el 100% del ancho
   final del track; como .login-success__fill-track ya tiene
   overflow:hidden, al ir creciendo el "width" de este elemento solo
   se va revelando progresivamente la porción izquierda de ese
   degradé -- el efecto visual es una barra que avanza de izquierda a
   derecha y cuyo borde de avance pasa suavemente de rojo a amarillo y
   a verde según se acerca al 100%, en vez de un verde sólido fijo. */
/* CAMBIOS PCG #15: mismo tratamiento que .rut-liquid__fill (ver
   comentario extenso ahí, y las @keyframes pcgLiquidWave/pcgBubblesRise
   compartidas, definidas en esa misma sección) -- borde ondulante vía
   clip-path + burbujas en ::before, sin reflejo y sin scroll horizontal.
   Acá las animaciones NO quedan infinitas por defecto: solo corren
   mientras .login-success__fill tiene .is-filling (ver más abajo),
   igual que ya pasaba con pcgLiquidFill. */
.login-success__fill-liquid {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 0%;
    background: linear-gradient(90deg, var(--login-red), var(--login-yellow), var(--login-green));
    backdrop-filter: blur(3px) saturate(165%);
    -webkit-backdrop-filter: blur(3px) saturate(165%);
    box-shadow:
        0 0 18px var(--login-green-glow),
        inset 0 1px 0 rgba(255, 255, 255, .30),
        inset 0 -1px 0 rgba(4, 35, 29, .12);
    clip-path: polygon(0% 0%, 0% 100%, 99.0% 100%, 97.9% 95%, 97.3% 90%, 97.3% 85%, 97.9% 80%, 99.0% 75%, 100.0% 70%, 100.0% 65%, 100.0% 60%, 100.0% 55%, 99.0% 50%, 97.9% 45%, 97.3% 40%, 97.3% 35%, 97.9% 30%, 99.0% 25%, 100.0% 20%, 100.0% 15%, 100.0% 10%, 100.0% 5%, 99.0% 0%);
}
.login-success__fill-liquid::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image:
        radial-gradient(circle 5px at 12% 85%, rgba(255, 255, 255, .9), transparent 85%),
        radial-gradient(circle 3.5px at 25% 68%, rgba(255, 255, 255, .75), transparent 85%),
        radial-gradient(circle 6px at 38% 90%, rgba(255, 255, 255, .65), transparent 85%),
        radial-gradient(circle 4px at 50% 62%, rgba(255, 255, 255, .8), transparent 85%),
        radial-gradient(circle 5.5px at 62% 88%, rgba(255, 255, 255, .7), transparent 85%),
        radial-gradient(circle 3px at 72% 70%, rgba(255, 255, 255, .85), transparent 85%),
        radial-gradient(circle 6.5px at 82% 92%, rgba(255, 255, 255, .6), transparent 85%),
        radial-gradient(circle 4.5px at 90% 65%, rgba(255, 255, 255, .78), transparent 85%),
        radial-gradient(circle 5px at 96% 84%, rgba(255, 255, 255, .72), transparent 85%);
    background-repeat: repeat-y;
    background-size: 100% 46px, 100% 34px, 100% 58px, 100% 40px, 100% 50px, 100% 30px, 100% 64px, 100% 44px, 100% 48px;
    pointer-events: none;
}
/* La animación de llenado solo corre cuando JS agrega .is-filling (recién
   al confirmarse el login real) -- así nunca arranca sola si alguien deja
   el markup de éxito cargado sin JS (progresivo: sin JS nunca se llega a
   data-state="success"). animation-fill-mode:both se queda en 100% al
   terminar en vez de volver a 0%. Duración y curva LINEAR a propósito:
   coincide exacto con el conteo 0->100% que arma pcg-login.js cuadro a
   cuadro también de forma lineal (ver runFillPhase). CAMBIOS PCG #12: se
   acorta de 1.9s a 1.2s (pedido explícito de un llenado más rápido) --
   si se toca este valor, hay que tocar también "duration" en
   runFillPhase() de pcg-login.js para que no se desincronicen. */
.login-success__fill.is-filling .login-success__fill-liquid {
    animation: pcgLiquidFill 1.2s linear both, pcgLiquidWave 3.6s linear infinite;
}
.login-success__fill.is-filling .login-success__fill-liquid::before {
    animation: pcgBubblesRise 2.6s linear infinite;
}
@keyframes pcgLiquidFill {
    from { width: 0%; }
    to { width: 100%; }
}
.login-success__fill-pct {
    font-size: .95rem;
    font-weight: 800;
    letter-spacing: .04em;
    color: var(--login-text);
    font-variant-numeric: tabular-nums;
}
/* CAMBIOS PCG #11: se retira .login-success__welcome (saludo por nombre) --
   era redundante con el "¡Bienvenido!" estático de más arriba en la
   tarjeta. La secuencia ahora es solo barra 0->100% -> check "Autorizado"
   -> redirect (ver pcg-login.js, startSuccessSequence). */

/* =========================================================================
   Responsive
   ========================================================================= */
@media (max-width: 520px) {
    :root { --login-ring: 208px; }
    .login-box { padding: 1.9rem 1.4rem 1.7rem; min-height: 27rem; }
    .login-logo { max-width: 148px; }
}

@media (prefers-reduced-motion: reduce) {
    .pcg-login, .pcg-login * {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
    }
}

.pcg-login .sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}