/* Estética de la app, en el navegador.
 *
 * Los valores NO están a ojo: salen de `lib/config/theme.dart`,
 * `lib/config/rase_type.dart` y `lib/widgets/rase_design.dart`. Si allá se
 * cambia un token, aquí hay que cambiarlo a mano — son dos plataformas, no hay
 * forma de compartirlos. Cada bloque dice de dónde viene.
 *
 * Solo tema claro, a propósito. La app deja apagar el modo oscuro desde el
 * panel (ver `adminSettings`), y esta página no tiene forma de saber qué eligió
 * la persona: si siguiera al sistema, alguien con el oscuro apagado en la app
 * abriría un correo y vería una página negra de Rase. Se queda en el aspecto
 * por defecto de la app.
 */

/* ── Poppins, servida desde este mismo dominio ──
   Nada de fonts.googleapis.com: esta página maneja códigos de un solo uso y no
   tiene por qué avisar a un tercero cada vez que alguien la abre. Además así el
   CSP puede quedarse en `font-src 'self'` sin excepciones. */
@font-face{
  font-family:'Poppins';font-style:normal;font-weight:400;font-display:swap;
  src:url('fonts/Poppins-Regular.woff2') format('woff2');
}
@font-face{
  font-family:'Poppins';font-style:normal;font-weight:500;font-display:swap;
  src:url('fonts/Poppins-Medium.woff2') format('woff2');
}
@font-face{
  font-family:'Poppins';font-style:normal;font-weight:600;font-display:swap;
  src:url('fonts/Poppins-SemiBold.woff2') format('woff2');
}

:root{
  /* theme.dart */
  --bg:#FDFDFD;              /* RaseTheme.background */
  --surface:#FFFFFF;         /* RaseTheme.surface */
  --ink:#1A1D2E;             /* textPrimary */
  --ink-dim:#6B7280;         /* textSecondary */
  --ink-hint:#888F9B;        /* textHint */
  --line:rgba(229,231,235,.9); /* divider #E5E7EB a 0.6 sobre blanco */
  --blue:#0A6CFF;            /* accent */
  --blue-l:#3B8AFF;          /* primaryLight */
  --success:#34C759;
  --error:#FF3B30;
  --dot-empty:#C9CFD9;       /* starEmpty — el punto del requisito pendiente */
  /* rase_design.dart */
  --r-field:14px;            /* radiusField  = radiusM */
  --r-btn:20px;              /* radiusButton = radiusL */
}

*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;background:var(--bg);color:var(--ink);
  font-family:'Poppins',system-ui,-apple-system,'Segoe UI',sans-serif;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  display:flex;flex-direction:column;align-items:center;
  /* 16px de aire a los lados en teléfono, que es donde se abre esto */
  padding:28px 16px 40px;
}
.sheet{width:100%;max-width:400px;display:flex;flex-direction:column;flex:1}

.mark{display:flex;justify-content:center;margin-bottom:26px}

/* rase_type.dart — screenTitle 28/w600/-0.5/1.2, ajustado a 25 en pantalla
   estrecha para que "Contraseña actualizada" no parta en tres líneas. */
h1{font-size:25px;font-weight:600;letter-spacing:-.5px;line-height:1.2;margin:0 0 8px}
@media (min-width:380px){h1{font-size:27px}}
/* body 14/regular/1.4 */
.sub{font-size:14px;line-height:1.45;color:var(--ink-dim);margin:0 0 20px}
/* El texto bajo el loader: sin margen inferior, que ya lo centra `.mid`. */
.sub-loading{margin:18px 0 0}

/* ── Fila de la cuenta ──
   Esto es lo que pediste: antes de escribir nada, la página dice de QUÉ cuenta
   es el enlace. El correo no sale de la URL — sale de la respuesta de Firebase
   al validar el código, así que si aparece es que el código era bueno. */
.acct{
  display:flex;align-items:center;gap:9px;margin:0 0 18px;padding:12px 14px;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-field);
  box-shadow:0 1px 2px rgba(15,23,42,.04);
}
.acct svg{flex:0 0 auto}
.acct span{font-size:13.5px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ── Campo ──
   premium_text_field.dart: nombre ESTÁTICO arriba (el floating label de
   Material se quitó en septiembre de 2026), superficie blanca, canto de pelo,
   y el acento solo al enfocar. */
.field{margin-bottom:14px}
.field>label{display:block;font-size:13px;font-weight:500;line-height:1.3;color:var(--ink-dim);padding:0 0 7px 4px}
.fwrap{position:relative}
.field input{
  width:100%;height:50px;padding:0 46px 0 16px;
  font-family:inherit;font-size:15px;font-weight:500;color:var(--ink);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-field);
  outline:none;transition:border-color .16s ease,box-shadow .16s ease;
}
.field input::placeholder{color:var(--ink-hint);font-weight:400}
.field input:focus{border-color:var(--blue);box-shadow:inset 0 0 0 .5px var(--blue)}
.field input:disabled{opacity:.55}
.eye{
  position:absolute;right:8px;top:7px;width:36px;height:36px;padding:0;margin:0;
  display:flex;align-items:center;justify-content:center;
  background:none;border:0;cursor:pointer;color:var(--ink-hint);
}
.eye:focus-visible{outline:2px solid var(--blue);outline-offset:-2px;border-radius:9px}

/* Error de un campo — auth_type.dart helper 12/w400/1.4 */
.ferr{font-size:12px;line-height:1.4;color:var(--error);padding:6px 4px 0;margin:0}

/* ── Requisitos de la contraseña ──
   password_strength_checklist.dart: dos columnas, sin caja. Punto gris lo
   pendiente, check verde suelto lo cumplido. */
.rules{display:grid;grid-template-columns:1fr 1fr;gap:8px 12px;padding:2px 4px 0;margin:0 0 20px;list-style:none}
.rules li{display:flex;align-items:center;gap:7px;font-size:12px;line-height:1.4;color:var(--ink-hint)}
.rules .mk{width:14px;height:14px;flex:0 0 auto;display:flex;align-items:center;justify-content:center}
.rules .mk i{width:5px;height:5px;border-radius:50%;background:var(--dot-empty)}
.rules .mk svg{display:none}
.rules li.ok{color:var(--ink)}
.rules li.ok .mk i{display:none}
.rules li.ok .mk svg{display:block}

/* ── Botón ──
   rase_design.dart, variante `glass`: gradiente de marca, radio 20, alto 52,
   etiqueta 16/w600. Sin backdrop-blur aquí: detrás no hay nada que desenfocar,
   y el blur en web cuesta caro en teléfonos de gama baja. */
.btn{
  width:100%;height:52px;border:0;border-radius:var(--r-btn);cursor:pointer;
  font-family:inherit;font-size:16px;font-weight:600;letter-spacing:-.2px;color:#fff;
  background:linear-gradient(135deg,var(--blue-l),var(--blue));
  box-shadow:0 10px 24px -12px rgba(10,108,255,.85);
  display:flex;align-items:center;justify-content:center;gap:2px;
  transition:transform .12s ease,opacity .16s ease;
}
.btn:active{transform:scale(.985)}
.btn:focus-visible{outline:2px solid var(--blue);outline-offset:3px}
.btn[disabled]{background:#DFE3EA;box-shadow:none;cursor:default}
/* Mientras envía, el botón NO se apaga: conserva el gradiente y solo cambia la
   etiqueta por los puntos, igual que RaseButton con `isLoading`. Sigue estando
   `disabled` —eso es lo que impide el doble envío—, pero un botón gris durante
   la espera se lee como "esto no se puede", y sí se está haciendo. */
.btn.loading[disabled]{
  background:linear-gradient(135deg,var(--blue-l),var(--blue));
  box-shadow:0 10px 24px -12px rgba(10,108,255,.85);
}
.btn.narrow{max-width:220px;margin:0 auto}
.tlink{
  display:block;margin:14px auto 0;padding:6px;background:none;border:0;
  font-family:inherit;font-size:13.5px;font-weight:500;color:var(--ink-dim);
  text-align:center;text-decoration:none;cursor:pointer;
}

.hint{font-size:12px;line-height:1.45;color:var(--ink-hint);text-align:center;margin:16px 0 0}
.grow{flex:1}

/* Estados centrados (cargando, éxito, error) */
.mid{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center}
.mid h1{margin-bottom:9px}
.mid .sub{margin-bottom:24px;max-width:250px}

[hidden]{display:none !important}

/* ═══════════════════════════════════════════════════════════════════
   RaseRouteLoader — el isotipo recorrido como una ruta
   ═══════════════════════════════════════════════════════════════════
   Puerto fiel de `lib/widgets/rase_route_loader.dart`. La geometría es la
   MISMA que allá (medida sobre el icono de 1024²), así que el dibujo es
   idéntico al de la app:
       nodo abajo (350,743) · quiebres (556,645) y (468,380) · nodo arriba
       (662,279) · radio 111 · grosor 120 · caja 239,168 → 783,854
   Los tiempos también: ciclo de 1750 ms, la ruta se dibuja entre el 8 % y el
   58 %, el destino aterriza entre el 50 % y el 66 %, y el grupo entero se
   desvanece al final en vez de recoger el trazo.

   Va SOLO en "Comprobando el enlace": según la tabla de la propia app, el
   isotipo es para una PANTALLA que se abre. Una espera de fondo lleva puntos. */
.rloader{display:block}
.rloader g{animation:rl-group 1.75s linear infinite}
.rloader .track{
  fill:none;stroke:#0E6DFB;stroke-width:120;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:1;stroke-dashoffset:1;animation:rl-track 1.75s linear infinite;
}
.rloader .node{fill:#0E6DFB;transform-box:fill-box;transform-origin:center}
.rloader .from{animation:rl-from 1.75s linear infinite}
.rloader .to{animation:rl-to 1.75s linear infinite}
/* 0.92 y no 1: RaseTheme.primary es ARGB(235,…), no es opaco. El alfa se
   aplica al GRUPO —no a cada pieza— para que el solape del nodo con el trazo
   no se vea más oscuro, igual que el saveLayer del CustomPainter. */
@keyframes rl-group{0%{opacity:0}6%{opacity:.92}82%{opacity:.92}100%{opacity:0}}
@keyframes rl-track{
  0%,8%{stroke-dashoffset:1;animation-timing-function:cubic-bezier(.645,.045,.355,1)} /* easeInOutCubic */
  58%,100%{stroke-dashoffset:0}
}
@keyframes rl-from{
  0%{transform:scale(0);animation-timing-function:cubic-bezier(.215,.61,.355,1)}      /* easeOutCubic */
  12%,100%{transform:scale(1)}
}
@keyframes rl-to{
  0%,50%{transform:scale(0);animation-timing-function:cubic-bezier(.34,1.56,.64,1)}   /* easeOutBack */
  66%,100%{transform:scale(1)}
}

/* ═══════════════════════════════════════════════════════════════════
   RaseDotsLoader — tres puntos que respiran
   ═══════════════════════════════════════════════════════════════════
   Puerto de `lib/widgets/rase_dots_loader.dart`: ciclo de 1150 ms, cada punto
   desfasado 0.16 del ciclo (= 184 ms), y la opacidad va de 0.28 a 1 y vuelve
   dentro del primer 35 % — por eso hay un tramo plano al final: es el punto
   esperando su turno, que es lo que hace que se lea como una onda.
   Va en las esperas de ACCIÓN: dentro de un botón. */
.dots{display:flex;align-items:center;gap:4.9px}
.dots i{width:7px;height:7px;border-radius:50%;background:currentColor;opacity:.28;animation:dots 1.15s linear infinite}
.dots i:nth-child(2){animation-delay:.184s}
.dots i:nth-child(3){animation-delay:.368s}
@keyframes dots{0%{opacity:.28}17.5%{opacity:1}35%,100%{opacity:.28}}

/* ═══════════════════════════════════════════════════════════════════
   RaseSuccessCheck — el gancho de éxito
   ═══════════════════════════════════════════════════════════════════
   `lib/widgets/rase_success_check.dart`: el círculo hace pop con easeOutBack
   y la palomita entra escalando en la segunda mitad. 66 px, verde de éxito.
   El botón de debajo va AZUL, no verde: el verde es del check. */
.check{
  width:66px;height:66px;border-radius:50%;background:var(--success);
  display:flex;align-items:center;justify-content:center;margin-bottom:22px;
  animation:ck-pop .64s cubic-bezier(.34,1.56,.64,1) both;
}
.check svg{animation:ck-tick .64s .27s ease-out both}
@keyframes ck-pop{from{transform:scale(.72);opacity:0}to{transform:scale(1);opacity:1}}
@keyframes ck-tick{from{transform:scale(.4);opacity:0}to{transform:scale(1);opacity:1}}

/* El aviso de enlace muerto: glifo suelto en rojo. Sin fondo cuadrado ni
   circular detrás — eso es lenguaje de Material y la app lo dejó. */
.warn{margin-bottom:20px;color:var(--error)}

/* "Reducir movimiento": todo se muestra ya montado. Igual que el
   `MediaQuery.disableAnimations` que respeta RaseSuccessCheck. */
@media (prefers-reduced-motion:reduce){
  .rloader g,.rloader .track,.rloader .node,.dots i,.check,.check svg{
    animation:none !important;
  }
  .rloader g{opacity:.92}
  .rloader .track{stroke-dashoffset:0}
  .dots i{opacity:.7}
}
