/* ═══════════════════════════════════════════════════════════════════════════
   quorbex — login compartido · hoja única de estilos (LOGIN-COMPARTIDO-001)

   ORIGEN: el login de quorbex 360 (templates/home.html) tal como quedó con
   LOGIN-UX-CSRF-001 (PRs #551/#552, 2026-09-24): la referencia que eligió el
   founder. Las reglas son las mismas; lo que cambia respecto del inline de 360:
     1. el acento no está escrito a mano: sale de variables por producto
        (html[data-product="..."]) con los colores UI de BRAND_GUIDELINES §5;
     2. la tipografía se auto-aloja (fonts/, SEC-WEB-1), nada de Google Fonts;
     3. tres huecos opcionales que 360 no tenía y otros sí: .btn-sec (passkey
        de host), .alt (enlace secundario) y .forgot (go/host).

   CÓMO SE USA (dos líneas en la plantilla del producto; el resto es el
   esqueleto HTML del README):
     <link rel="stylesheet" href="/shared/login/quorbex-login.css">
     <script src="/shared/login/quorbex-login.js" defer></script>
   y en el <html>: data-product="360|host|bill|go|crm|clinic|build|people|ecom".

   DUEÑO: auditor de web y servidor (DEC-048). Cambios por PR en quorbex-server,
   con el arnés (shared/login/arnes/) en verde y VV del founder. Servido por nginx
   en /shared/login/ con Cache-Control: no-cache (ETag): no hace falta ?v=.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Tipografía auto-alojada (misma declaración que landing/fonts, SEC-WEB-1) ── */
@font-face {
  font-family: 'Varela Round';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/varela-round-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Varela Round';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/varela-round-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ── Acento por producto: BRAND_GUIDELINES §5 (UI = --accent, Claro = --accent-2).
      --btn-fg: color del texto del botón. Oscuro sobre acentos claros (como 360);
      blanco sobre los acentos oscuros (host, crm, ecom), donde #121316 no llega
      al contraste mínimo. Si falta data-product, se ve como 360. ───────────── */
:root,
html[data-product="360"]    { --accent:#2EC4B6; --accent-rgb:46,196,182;  --accent-2:#5cd4c9; --btn-fg:#121316; }
html[data-product="host"]   { --accent:#6b3df0; --accent-rgb:107,61,240;  --accent-2:#7c5cff; --btn-fg:#ffffff; }
html[data-product="bill"]   { --accent:#22c55e; --accent-rgb:34,197,94;   --accent-2:#22c55e; --btn-fg:#121316; }
html[data-product="go"]     { --accent:#06b6d4; --accent-rgb:6,182,212;   --accent-2:#22d3ee; --btn-fg:#121316; }
html[data-product="crm"]    { --accent:#ef4444; --accent-rgb:239,68,68;   --accent-2:#dc2626; --btn-fg:#ffffff; }
html[data-product="clinic"] { --accent:#bc875c; --accent-rgb:188,135,92;  --accent-2:#dabda4; --btn-fg:#121316; }
html[data-product="build"]  { --accent:#ffb020; --accent-rgb:255,176,32;  --accent-2:#ffb020; --btn-fg:#121316; }
html[data-product="people"] { --accent:#facc15; --accent-rgb:250,204,21;  --accent-2:#fde047; --btn-fg:#121316; }
html[data-product="ecom"]   { --accent:#688391; --accent-rgb:104,131,145; --accent-2:#87a1ab; --btn-fg:#ffffff; }
/* Escala oscura común del ecosistema, sin azul visible (founder 2026-10-23; BRAND_GUIDELINES §10.1):
   barra lateral #121316 · fondo #17191D · cards #202328 · inputs/hover #26292F · bordes #2E3238. */
:root { --qx-lateral:#121316; --qx-fondo:#17191D; --qx-card:#202328; --qx-input:#26292F; --qx-borde:#2E3238; --bg:var(--qx-fondo); }
:root { --accent-glow: rgba(var(--accent-rgb), .25); --focus: var(--accent); --focus-glow: var(--accent-glow); }
/* Foco de los campos: por defecto el acento. En crm el acento es rojo, el mismo color de los errores; ahí el foco es un gris
   claro neutro (= --qx-border-strong del DS, #cbd5e1) y el rojo queda solo para los errores (founder, 2026-10-12). */
html[data-product="crm"] { --focus:#cbd5e1; --focus-glow: rgba(203,213,225,.25); }

/* ── A partir de acá: el CSS de 360, con el acento por variable ─────────────── */
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:'Varela Round',sans-serif; background:var(--bg); color:#e5e7eb; height:100vh;height:100dvh; overflow:hidden; -webkit-font-smoothing:antialiased; }

.bg { position:fixed; inset:0; z-index:0; overflow:hidden; }
.bg .o { position:absolute; border-radius:50%; filter:blur(120px); animation:of 20s infinite ease-in-out; }
.bg .o1 { width:600px; height:600px; background:rgba(var(--accent-rgb),.12); top:-15%; right:-10%; }
.bg .o2 { width:500px; height:500px; background:rgba(var(--accent-rgb),.09); bottom:-20%; left:-15%; animation-delay:-7s; }
.bg .o3 { width:400px; height:400px; background:rgba(var(--accent-rgb),.14); top:35%; left:45%; animation-delay:-14s; }
@keyframes of { 0%,100%{transform:translate(0,0) scale(1)} 33%{transform:translate(30px,-20px) scale(1.05)} 66%{transform:translate(-20px,15px) scale(.95)} }

/* Red de partículas: la MISMA de quorbex.com (landing/pricing/360). Canvas fijo
   detrás de todo, sin interceptar clics. El color lo toma el JS de --accent-rgb. */
#net { position:fixed; inset:0; z-index:0; pointer-events:none; }

.page { position:relative; z-index:1; width:100%; height:100%; display:flex; align-items:center; justify-content:center; padding:24px; }

.card {
  width:100%; max-width:420px;
  background:var(--qx-card);
  border:1px solid var(--qx-borde);
  border-radius:24px;
  padding:44px 36px 36px;
  backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);
  box-shadow:0 24px 80px rgba(0,0,0,.4);
  animation:ci .6s ease;
}
@keyframes ci { from{opacity:0;transform:translateY(20px) scale(.97)} to{opacity:1;transform:translateY(0) scale(1)} }

.brand { text-align:center; margin-bottom:32px; }
.brand img { height:40px; margin-bottom:10px; }
.brand .sub { font-size:.8rem; color:#9ca3af; }

/* Mensajes del servidor (django.contrib.messages o {{ error }}): .err (error, de 360) y .ok (éxito/info,
   pedido de go y crm, 2026-10-09). Van entre .brand y el <form>; cada mensaje en su propio <div>. */
.err { background:rgba(239,68,68,.08); border:1px solid rgba(239,68,68,.2); color:#fca5a5; padding:10px 14px; border-radius:12px; font-size:.85rem; margin-bottom:1.2rem; text-align:center; }
.ok  { background:rgba(var(--accent-rgb),.08); border:1px solid rgba(var(--accent-rgb),.25); color:#e5e7eb; padding:10px 14px; border-radius:12px; font-size:.85rem; margin-bottom:1.2rem; text-align:center; }
.msgs .err, .msgs .ok { margin-bottom:.6rem; } .msgs { margin-bottom:.6rem; }

.fg { margin-bottom:1.2rem; }
.fg label { display:block; margin-bottom:6px; color:#9ca3af; font-size:.8rem; }
.fi {
  width:100%; padding:13px 16px;
  border:1px solid var(--qx-borde);
  border-radius:12px; font-size:.95rem;
  font-family:'Varela Round',sans-serif;
  background:var(--qx-input);
  color:#e5e7eb; transition:all .25s;
}
.fi:focus { outline:none; border-color:var(--focus); box-shadow:0 0 0 3px var(--focus-glow); background:var(--qx-input); }
/* Autofill: el navegador pinta el input de BLANCO y no se puede cambiar con
   `background`. El único camino es una sombra interna gigante del color del
   tema + forzar el color del texto. La transición se apaga porque Chrome la usa
   para colar su amarillo/blanco durante el fundido. */
.fi:-webkit-autofill,
.fi:-webkit-autofill:hover,
.fi:-webkit-autofill:focus,
.fi:-webkit-autofill:active {
  -webkit-box-shadow: 0 0 0 1000px var(--qx-input) inset !important;
  box-shadow: 0 0 0 1000px var(--qx-input) inset !important;
  -webkit-text-fill-color: #e5e7eb !important;
  caret-color: #e5e7eb;
  transition: background-color 9999s ease-in-out 0s;
}
.fi:-webkit-autofill:focus { -webkit-box-shadow: 0 0 0 1000px var(--qx-input) inset, 0 0 0 3px var(--focus-glow) !important; }
.fi::placeholder { color:rgba(255,255,255,.18); }

.pw { position:relative; }
.pw .fi { padding-right:2.5rem; }
.pw .eye { position:absolute; right:14px; top:50%; transform:translateY(-50%); cursor:pointer; color:rgba(255,255,255,.25); font-size:1rem; user-select:none; transition:color .2s; }
.pw .eye:hover, .pw .eye:focus-visible { color:rgba(255,255,255,.5); outline:none; }
.pw .eye[aria-pressed="true"] { color:var(--accent); }

.btn {
  width:100%; padding:14px;
  background:linear-gradient(135deg,var(--accent),var(--accent-2));
  color:var(--btn-fg); border:none; border-radius:12px;
  font-size:.95rem; font-family:'Varela Round',sans-serif;
  cursor:pointer; transition:transform .25s, box-shadow .25s;
  margin-top:.5rem;
}
.btn:hover { transform:translateY(-2px); box-shadow:0 10px 36px var(--accent-glow); }

/* LOGIN-UX-CSRF-001: respuesta inmediata al tocar "Entrar". El botón se hunde
   (escala .97, un poco más oscuro, 120 ms) y queda deshabilitado. */
.btn:active { transform:scale(.97); filter:brightness(.88); transition-duration:.12s; }
.btn:disabled { opacity:.75; cursor:default; pointer-events:none; }
.btn:disabled:hover { transform:none; box-shadow:none; }

/* Huecos opcionales (no están en 360; los usan host y go):
   .btn-sec: botón secundario (passkey de host), .alt: enlace para alternar,
   .forgot: "¿Olvidaste tu contraseña?". */
.btn-sec {
  width:100%; padding:14px; margin-bottom:1.2rem;
  background:var(--qx-input); color:#e5e7eb;
  border:1px solid var(--qx-borde); border-radius:12px;
  font-size:.95rem; font-family:'Varela Round',sans-serif; cursor:pointer;
  display:flex; align-items:center; justify-content:center; gap:10px;
  transition:background .2s, border-color .2s;
}
.btn-sec:hover { background:rgba(255,255,255,.09); border-color:rgba(255,255,255,.18); }
.alt, .forgot { display:block; text-align:center; font-size:.8rem; color:rgba(255,255,255,.45); text-decoration:none; cursor:pointer; transition:color .2s; }
.alt { margin-bottom:1.2rem; }
.forgot { margin-top:16px; }
.alt:hover, .forgot:hover { color:rgba(255,255,255,.75); }
/* Con el atributo `hidden` (host esconde el passkey si el navegador no lo
   soporta) el display de arriba le ganaba al del navegador: igual que
   .qx-cargando[hidden], se fuerza a none en los tres huecos (propuesta de
   host, 2026-10-10; .forgot sumado por el founder, 2026-10-11). */
.btn-sec[hidden], .alt[hidden], .forgot[hidden] { display:none; }

/* Capa "Ingresando": fondo desenfocado y levemente oscurecido; al centro el
   isotipo oficial del producto girando una vuelta por segundo (64 px en
   pantalla grande, 56 px en celular); debajo "Ingresando" con los tres
   puntos apareciendo de a uno (~400 ms por paso), solo CSS, con el ancho
   de los puntos reservado para que la palabra no se mueva. */
.qx-cargando {
  position:fixed; inset:0; z-index:50;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:16px;
  background:rgba(23,25,29,.55);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
}
.qx-cargando[hidden] { display:none; }
.qx-cargando .iso { width:56px; height:56px; animation:qxgiro 1s linear infinite; }
@media (min-width:768px) { .qx-cargando .iso { width:64px; height:64px; } }
@keyframes qxgiro { to { transform:rotate(360deg); } }
.qx-cargando .txt { font-size:.9rem; color:#e5e7eb; }
.qx-cargando .dots { display:inline-block; width:1.05em; text-align:left; }
.qx-cargando .dots span { opacity:0; animation:qxpunto 1.2s linear infinite; }
.qx-cargando .dots span:nth-child(2) { animation-delay:.4s; }
.qx-cargando .dots span:nth-child(3) { animation-delay:.8s; }
@keyframes qxpunto { 0%{opacity:0} 33%,100%{opacity:1} }
@keyframes qxlatido { 0%,100%{opacity:1} 50%{opacity:.4} }
@media (prefers-reduced-motion: reduce) {
  .bg .o { animation:none; }
  .card { animation:none; }
  .qx-cargando .iso { animation:qxlatido 1.6s ease-in-out infinite; }
  .qx-cargando .dots span { animation:none; opacity:1; }
}

.back { display:block; text-align:center; margin-top:20px; font-size:.8rem; color:rgba(255,255,255,.3); text-decoration:none; transition:color .2s; }
.back:hover { color:rgba(255,255,255,.6); }

/* ── Variantes de acceso (founder 2026-10-12): cambiar contraseña (obligatoria), olvidé mi contraseña, restablecer, y
      páginas de mensaje (enlace vencido, enlace enviado, 403). Mismo fondo, card, logo, campos con ojo y botón que el
      login; el esqueleto de cada una está en el README. Nada de esto cambia el login. */
.titulo { font-size:1.15rem; font-weight:normal; color:#f3f4f6; text-align:center; margin:-14px 0 .5rem; }
.texto { font-size:.85rem; color:#9ca3af; text-align:center; line-height:1.55; margin-bottom:1.5rem; }
.ayuda { margin-top:7px; padding-left:1.1rem; font-size:.72rem; color:#6b7280; line-height:1.55; }
.fi-err { margin-top:6px; font-size:.75rem; color:#fca5a5; }
.fi[aria-invalid="true"] { border-color:rgba(239,68,68,.5); }
a.btn { display:block; text-align:center; text-decoration:none; }
/* Variantes más altas que la pantalla (3 campos + ayuda en un celular chico): <body class="largo"> deja hacer scroll
   en vez de cortar la card. El login no lleva la clase. */
body.largo { overflow-y:auto; }
body.largo .page { height:auto; min-height:100%; padding:40px 24px 56px; }

.ft { position:fixed; bottom:20px; left:0; right:0; text-align:center; font-size:.65rem; color:rgba(255,255,255,.12); z-index:1; }
