/* =====================================================================
   Portal Meridantis · hoja de estilos

   SIN DEPENDENCIAS EXTERNAS. La CSP declara default-src 'none' con
   style-src 'self' y font-src 'self': no hay Tailwind, ni Google Fonts,
   ni ningun CDN. Todo lo de aqui es CSS nativo sobre la pila del sistema.

   UN SOLO TEMA. La pagina es oscura de principio a fin. Antes el login
   era una tarjeta blanca entre dos pantallas oscuras y se sentia como
   entrar a otro sitio a mitad de camino.

   TRES ESCALAS Y NADA SUELTO. Tipografia, espacio y radio salen de las
   escalas de abajo. Un valor a ojo en mitad del archivo es lo que hace
   que una interfaz se vea improvisada aunque cada pieza este bien.

   MOVIMIENTO: el logo usa transform y opacidad; cuatro trazos SVG breves
   guian la mirada durante la bienvenida. El campo de fondo sigue siendo
   el lienzo existente y se apaga para quien pide menos movimiento.
   ===================================================================== */

:root {
  /* ---- Marca (manual de Meridantis) -------------------------------- */
  --hondo:      #06182E;
  --hondo-alto: #0B2D5B;
  --azul:       #2563EB;
  --cian:       #06B6D4;
  --cian-vivo:  #22D3EE;
  --tinta:      #0B2D5B;
  --papel:      #FFFFFF;
  --nieve:      #E8EEF6;
  --apagado:    #93A7C0;

  /* ---- Superficies del tema oscuro --------------------------------- */
  --capa:       rgba(255, 255, 255, .045);
  --capa-alta:  rgba(255, 255, 255, .075);
  --hueco:      rgba(2, 10, 22, .42);
  --borde:      rgba(147, 174, 196, .16);
  --borde-alto: rgba(147, 174, 196, .3);
  --borde-vivo: rgba(34, 211, 238, .5);
  --ambar:      #FFD08A;

  /* ---- Tipografia -------------------------------------------------- */
  /* Segoe UI Variable existe en Windows 11, que es lo que hay en faena;
     su corte Display tiene el asta mas ajustada en tamanos grandes. Si
     no esta, la pila cae a Segoe UI normal sin que se note el cambio. */
  --letra: "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system,
           "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --letra-titulo: "Segoe UI Variable Display", "Segoe UI", system-ui,
                  -apple-system, "Helvetica Neue", Arial, sans-serif;

  --t-titulo:  clamp(1.15rem, 1.02rem + .5vw, 1.34rem);
  --t-cuerpo:  .9375rem;
  --t-menor:   .8125rem;
  --t-micro:   .6875rem;

  /* ---- Espacio ------------------------------------------------------ */
  --e1: 6px;
  --e2: 10px;
  --e3: 16px;
  --e4: 24px;
  --e5: 36px;
  --e6: 56px;

  /* ---- Radio -------------------------------------------------------- */
  /* La regla, para no volver a tener seis radios distintos sueltos:
     interactivo pequeno = chico, contenedor = medio, contenedor mayor =
     grande, cualquier cosa con forma de pastilla = pastilla. */
  --r-chico:   10px;
  --r-medio:   16px;
  --r-grande:  22px;
  --r-pastilla: 999px;

  /* ---- Curvas ------------------------------------------------------- */
  /* Una sola familia de curvas en todo el portal. 'salida' es una expo
     que arranca rapido y frena largo: es la que hace que algo parezca
     que llega solo en vez de que lo empujen. */
  --salida: cubic-bezier(.16, 1, .3, 1);
  --suave:  cubic-bezier(.4, 0, .2, 1);

  /* El guion sobreescribe esto con la duracion real de la bienvenida,
     para que la barra de avance no se desincronice de la espera. */
  --bienvenida: 3100ms;
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--letra);
  font-size: 16px;
  line-height: 1.5;
  color: var(--nieve);
  /* El degradado vive en el body y no en un pseudoelemento: admin.html no
     lleva el lienzo del campo, y si el fondo estuviera solo ahi esa
     pagina se quedaria con un azul plano. En el portal el lienzo lo tapa. */
  background:
    radial-gradient(58% 46% at 50% 4%,  rgba(6, 182, 212, .14), transparent 70%),
    radial-gradient(52% 52% at 90% 98%, rgba(37, 99, 235, .24), transparent 72%),
    linear-gradient(168deg, var(--hondo-alto), var(--hondo) 62%);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* El fondo lo pinta ahora js/campo.js en un lienzo: el mismo campo de
   propagacion del sitio corporativo. Aqui solo queda el color de
   seguridad, que es lo que se ve si el guion no llega a cargar o el
   navegador no tiene canvas. */
.lienzo-fondo {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: -1;
  /* Un solo mando para toda la intensidad del campo. A plena opacidad las
     ondas y las etiquetas se leen antes que el contenido. El degradado de
     respaldo ya vive en el body, asi que si el guion no carga no se nota. */
  opacity: .55;
}

/* Un velo por encima del campo. Va en body::after y no en un truco sobre
   el enlace de salto: ::after viene despues del lienzo en el arbol, asi
   que con el mismo z-index lo tapa. admin.html no lleva lienzo y no lo
   necesita. */
body:not(.admin)::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(62% 50% at 50% 50%, rgba(6, 24, 46, .9), rgba(6, 24, 46, .5) 60%, rgba(6, 24, 46, .1));
  pointer-events: none;
}

.salto {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--papel);
  color: var(--tinta);
  padding: var(--e2) var(--e3);
  border-radius: 0 0 var(--r-chico) 0;
  z-index: 50;
}
.salto:focus { left: 0; }

/* ---------- Pantallas ---------------------------------------------- */
/* Solo una es visible a la vez. El atributo hidden manda sobre el
   display:flex, que si no la dejaria a la vista igual. */
.pantalla {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--e5) var(--e4);
}
.pantalla[hidden] { display: none; }

.pantalla--visible { animation: aparecer .5s var(--salida) both; }

@keyframes aparecer {
  from { opacity: 0; transform: translate3d(0, 16px, 0); }
  to   { opacity: 1; transform: none; }
}

/* La pantalla que se va sube un poco y se achica: da sensacion de
   avance hacia la siguiente en vez de un corte seco. */
.pantalla--saliendo { animation: retirarse .42s var(--suave) both; }

@keyframes retirarse {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translate3d(0, -20px, 0) scale(.985); }
}

/* ---------- 1. Bienvenida: el campo converge en la marca ----------- */
.intro-escena {
  position: relative;
  width: min(100%, 1000px);
  height: min(72dvh, 560px);
  min-height: 310px;
  display: grid;
  place-items: center;
  isolation: isolate;
}
.intro-red {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.intro-trazo,
.intro-senal {
  fill: none;
  stroke-linecap: round;
  stroke-width: 1.3;
  vector-effect: non-scaling-stroke;
}
.intro-trazo {
  stroke: rgba(34, 211, 238, .45);
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
  animation: introTrazar .88s var(--salida) both;
}
.intro-trazo--1 { animation-delay: .10s; }
.intro-trazo--2 { animation-delay: .26s; }
.intro-trazo--3 { animation-delay: .18s; }
.intro-trazo--4 { animation-delay: .34s; }
.intro-senal {
  stroke: #8beaff;
  stroke-width: 2.5;
  stroke-dasharray: 34 966;
  stroke-dashoffset: 1000;
  opacity: 0;
  animation: introViajar .9s var(--suave) both;
}
.intro-senal--1 { animation-delay: .58s; }
.intro-senal--2 { animation-delay: .74s; }
.intro-senal--3 { animation-delay: .66s; }
.intro-senal--4 { animation-delay: .82s; }
.intro-nodo {
  fill: #3bcbea;
  opacity: 0;
  animation: introNodo .42s var(--salida) both;
}
.intro-nodo--1, .intro-nodo--3 { animation-delay: .06s; }
.intro-nodo--2, .intro-nodo--4 { animation-delay: .21s; }
.intro-nodo--5, .intro-nodo--7 { animation-delay: .78s; }
.intro-nodo--6, .intro-nodo--8 { animation-delay: .94s; }
@keyframes introTrazar { to { stroke-dashoffset: 0; } }
@keyframes introViajar {
  0% { opacity: 0; stroke-dashoffset: 1000; }
  12% { opacity: 1; }
  85% { opacity: 1; }
  100% { opacity: 0; stroke-dashoffset: 0; }
}
@keyframes introNodo { to { opacity: .85; } }

.intro-marca {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: min(380px, 88vw);
  padding: 24px 0 28px;
  background: radial-gradient(ellipse 72% 62% at 50% 48%, rgba(6, 24, 46, .88), rgba(6, 24, 46, 0));
}
.marca-grande {
  display: block;
  position: relative;
  z-index: 1;
  width: min(240px, 61vw);
  height: auto;
  opacity: 0;
  animation: introMarca .72s var(--salida) .84s both;
}
.intro-nombre {
  position: relative;
  z-index: 1;
  margin-left: .2em;
  margin-top: -11px;
  color: #f3f8ff;
  font: 750 clamp(1.2rem, 2.1vw, 1.85rem)/1.2 var(--letra-titulo);
  letter-spacing: .2em;
  text-shadow: 0 2px 14px rgba(2, 10, 22, .6);
  opacity: 0;
  animation: introNombre .7s var(--salida) 1.08s both;
}
.intro-descriptor {
  position: relative;
  z-index: 1;
  margin-top: 12px;
  color: #a9c3dc;
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .24em;
  opacity: 0;
  animation: introNombre .55s var(--salida) 1.45s both;
}
.intro-pulso {
  position: absolute;
  z-index: 0;
  left: 50%;
  top: 42%;
  width: 190px;
  aspect-ratio: 1;
  border: 1px solid rgba(34, 211, 238, .65);
  border-radius: 50%;
  box-shadow: 0 0 32px rgba(6, 182, 212, .1), inset 0 0 32px rgba(6, 182, 212, .05);
  opacity: 0;
  animation: introPulso 1.05s var(--salida) 1.5s both;
}
@keyframes introMarca {
  from { opacity: 0; transform: translateY(9px) scale(.96); }
  to { opacity: 1; transform: none; }
}
@keyframes introNombre {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
@keyframes introPulso {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(.7); }
  20% { opacity: .65; }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(2); }
}

.avance {
  position: absolute;
  bottom: 35px;
  width: 156px;
  height: 2px;
  border-radius: var(--r-pastilla);
  background: rgba(147, 174, 196, .22);
  overflow: hidden;
}
.avance::after {
  content: "";
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--azul), var(--cian-vivo));
  transform-origin: left center;
  animation: avanzar var(--bienvenida) linear both;
}
@keyframes avanzar {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}
.bienvenida--esperando .avance::after {
  animation: introEspera 1.1s var(--suave) infinite alternate;
}
@keyframes introEspera {
  from { opacity: .45; transform: scaleX(.35); }
  to { opacity: 1; transform: scaleX(1); }
}
.intro-espera {
  position: absolute;
  bottom: 0;
  margin: 0;
  color: var(--apagado);
  font-size: var(--t-menor);
}
.intro-espera[hidden] { display: none; }

.omitir {
  position: absolute;
  bottom: max(20px, env(safe-area-inset-bottom, 0px) + 16px);
  left: 50%;
  min-width: 100px;
  min-height: 44px;
  background: rgba(10, 30, 54, .72);
  border: 1px solid rgba(176, 206, 228, .52);
  color: #d6e5f3;
  font: inherit;
  font-size: var(--t-menor);
  padding: 9px 20px;
  border-radius: var(--r-pastilla);
  cursor: pointer;
  transform: translateX(-50%);
  transition: color .2s var(--suave), border-color .2s var(--suave), background .2s var(--suave);
}
.omitir:hover { color: #fff; border-color: var(--cian-vivo); background: rgba(10, 40, 67, .88); }

.intro--sin-animacion .intro-red,
.intro--sin-animacion .intro-pulso,
.intro--sin-animacion .avance { display: none; }
.intro--sin-animacion .marca-grande,
.intro--sin-animacion .intro-nombre,
.intro--sin-animacion .intro-descriptor {
  animation: none;
  opacity: 1;
  transform: none;
}

/* En ventanas apaisadas y bajas, la linea de avance queda dentro de la
   escena y el control de omision conserva su propia franja tactil. */
@media (max-height: 520px) {
  #bienvenida { padding-block: 8px 64px; }
  .intro-escena { height: min(60dvh, 290px); min-height: 175px; }
  .marca-grande { width: min(160px, 36dvh); }
  .intro-marca { padding: 8px 0 22px; }
  .intro-nombre { margin-top: -8px; font-size: 1.1rem; }
  .intro-descriptor { margin-top: 6px; }
  .intro-pulso { width: 140px; }
  .avance { bottom: 0; }
  .omitir { bottom: max(8px, env(safe-area-inset-bottom, 0px) + 8px); }
}

/* ---------- 2 y 3. Tarjetas de formulario --------------------------- */
/* Misma familia de superficie que las tarjetas de plataforma: el login
   pertenece a la misma pagina, no es un formulario prestado. */
.tarjeta {
  position: relative;
  width: 100%;
  max-width: 404px;
  /* Opaca, no translucida: detras hay un fondo animado y una superficie
     al 4,5% dejaba leer las ondas a traves del formulario. */
  background: rgba(10, 30, 54, .93);
  border: 1px solid var(--borde);
  color: var(--nieve);
  border-radius: var(--r-grande);
  padding: var(--e5) var(--e5) var(--e4);
  display: flex;
  flex-direction: column;
  gap: var(--e3);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .07),
    0 28px 64px rgba(0, 8, 18, .5);
}

/* Cada pieza del formulario entra un poco despues que la anterior. El
   ojo sigue el orden en que hay que rellenarlo. El retardo va por
   nth-child porque la CSP prohibe estilos en linea. */
.tarjeta > * { animation: aparecer .5s var(--salida) both; }
.tarjeta > :nth-child(1) { animation-delay: .04s; }
.tarjeta > :nth-child(2) { animation-delay: .10s; }
.tarjeta > :nth-child(3) { animation-delay: .16s; }
.tarjeta > :nth-child(4) { animation-delay: .22s; }
.tarjeta > :nth-child(5) { animation-delay: .28s; }
.tarjeta > :nth-child(6) { animation-delay: .34s; }

/* La marca del formulario. El logotipo es apaisado (488 x 225): se le da
   ancho y la altura sale sola, que si se le fija un alto se deforma. */
.logotipo {
  width: 100%;
  max-width: 230px;
  height: auto;
  align-self: center;
  margin-bottom: var(--e2);
}

.tarjeta__nota {
  margin: calc(var(--e1) * -1) 0 0;
  font-size: var(--t-cuerpo);
  color: var(--apagado);
  text-align: center;
}

.campo { display: flex; flex-direction: column; gap: var(--e1); }

.campo label {
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--apagado);
}

.campo input {
  font: inherit;
  color: var(--nieve);
  background: var(--hueco);
  border: 1px solid var(--borde);
  border-radius: var(--r-chico);
  padding: 12px 14px;
  transition: border-color .18s var(--suave), box-shadow .18s var(--suave),
              background .18s var(--suave);
}
.campo input:hover { border-color: var(--borde-alto); }
.campo input:focus {
  outline: none;
  background: rgba(2, 10, 22, .6);
  border-color: var(--cian-vivo);
  box-shadow: 0 0 0 3px rgba(34, 211, 238, .18);
}
/* Chrome pinta el autorrelleno de blanco y borra el tema oscuro. El
   relleno interior enorme es el unico modo de taparlo sin !important. */
.campo input:-webkit-autofill {
  -webkit-text-fill-color: var(--nieve);
  -webkit-box-shadow: 0 0 0 40px #0A2038 inset;
  caret-color: var(--nieve);
}

.aviso {
  margin: 0;
  font-size: var(--t-menor);
  color: #FFB4B8;
  background: rgba(196, 42, 51, .14);
  border: 1px solid rgba(255, 150, 155, .32);
  border-radius: var(--r-chico);
  padding: var(--e2) 12px;
  animation: sacudir .34s var(--suave);
}
.aviso[hidden] { display: none; }

/* Un temblor corto y pequeno. Comunica el rechazo sin que haya que
   releer, y termina rapido para no estorbar. */
@keyframes sacudir {
  0%, 100% { transform: none; }
  22%      { transform: translate3d(-5px, 0, 0); }
  55%      { transform: translate3d(4px, 0, 0); }
  80%      { transform: translate3d(-2px, 0, 0); }
}

/* ---------- Botones -------------------------------------------------- */
.boton {
  font: inherit;
  font-weight: 600;
  letter-spacing: .01em;
  border: 0;
  border-radius: var(--r-chico);
  padding: 13px 18px;
  cursor: pointer;
  transition: transform .12s var(--suave), box-shadow .22s var(--suave),
              filter .22s var(--suave), opacity .2s var(--suave);
}
/* Hundir de verdad al pulsar. Un boton que no cede al dedo se siente
   roto en una pantalla tactil, que es donde mas se usa esto. */
.boton:active { transform: scale(.982) translateY(1px); }
.boton[disabled] { opacity: .6; cursor: progress; }

/* El turquesa NO sirve de fondo para texto blanco: son 2,4:1. El boton
   se queda en la familia del azul electrico, que da 5,1:1 con blanco, y
   el turquesa se reserva para acentos y foco. */
.boton--primario {
  color: #fff;
  background: linear-gradient(135deg, var(--azul) 0%, #1D4FD0 100%);
  box-shadow: 0 6px 18px rgba(37, 99, 235, .32);
}
.boton--primario:hover:not([disabled]) {
  filter: brightness(1.08);
  box-shadow: 0 10px 26px rgba(37, 99, 235, .46);
}

/* ---------- 4. Plataformas ------------------------------------------- */
#portales {
  justify-content: flex-start;
  padding-top: var(--e4);
  padding-bottom: var(--e6);
  isolation: isolate;
}
#portales::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background: rgba(3, 16, 32, .18);
  pointer-events: none;
}

.barra {
  width: 100%;
  max-width: 1240px;
  display: flex;
  align-items: center;
  gap: var(--e2);
  min-height: 56px;
  margin-bottom: 0;
}
.barra__hueco { flex: 1; }

.catalogo-encabezado {
  width: 100%;
  max-width: 1240px;
  margin: clamp(36px, 5vw, 66px) auto 42px;
}
.catalogo-encabezado__eyebrow {
  margin: 0 0 10px;
  color: var(--cian-vivo);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: .17em;
}
.catalogo-encabezado h1 {
  margin: 0;
  color: #f3f8ff;
  font: 750 clamp(1.9rem, 2.7vw, 2.65rem)/1.12 var(--letra-titulo);
  letter-spacing: -.035em;
}
.catalogo-encabezado h1:focus { outline: none; }

/* En la barra va el bloque horizontal (simbolo + nombre), no el simbolo
   suelto: a 74 px el isotipo solo se leia como un garabato azul, sobre
   todo ahora que detras hay un campo en movimiento. La sombra lo despega
   del fondo. */
.marca-chica {
  width: 190px;
  height: auto;
  flex: none;
  filter: drop-shadow(0 2px 6px rgba(2, 10, 22, .55));
}

.icono-boton {
  font: inherit;
  font-size: var(--t-menor);
  /* Sin esto, en pantallas angostas el texto se parte en dos lineas y el
     radio de pastilla convierte el boton en un globo. */
  white-space: nowrap;
  color: var(--apagado);
  background: var(--capa);
  border: 1px solid var(--borde);
  border-radius: var(--r-pastilla);
  padding: 8px 16px;
  cursor: pointer;
  text-decoration: none;
  transition: color .18s var(--suave), background .18s var(--suave),
              border-color .18s var(--suave);
}
.icono-boton:hover {
  color: var(--nieve);
  background: var(--capa-alta);
  border-color: var(--borde-alto);
}
.icono-boton[hidden] { display: none; }

.catalogo {
  width: 100%;
  max-width: 1240px;
  display: grid;
  gap: 52px;
}
.grupo {
  min-width: 0;
  --acento-tarjeta: #4cdded;
  --acento-rgb: 76, 221, 237;
}
.grupo--flotas { --acento-tarjeta: #6ba7ff; --acento-rgb: 107, 167, 255; }
.grupo--gestion { --acento-tarjeta: #a5bcff; --acento-rgb: 165, 188, 255; }
.grupo--otras { --acento-tarjeta: #a9d4e8; --acento-rgb: 169, 212, 232; }
.grupo__encabezado {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  column-gap: var(--e3);
  padding: 0 0 17px 18px;
  margin-bottom: 18px;
  border-left: 2px solid var(--acento-tarjeta);
  border-bottom: 1px solid rgba(147, 174, 196, .2);
  background: linear-gradient(90deg, rgba(6, 24, 46, .92), rgba(6, 24, 46, .68) 54%, rgba(6, 24, 46, .14));
}
.grupo__encabezado h2 {
  margin: 0;
  color: #f3f8ff;
  font: 700 clamp(1.2rem, 1.5vw, 1.45rem)/1.2 var(--letra-titulo);
  letter-spacing: -.02em;
}
.grupo__cantidad {
  color: var(--apagado);
  font-size: var(--t-menor);
  white-space: nowrap;
}
.grupo__detalle {
  grid-column: 1 / -1;
  margin: 8px 0 0;
  color: #a9bed4;
  font-size: var(--t-cuerpo);
}
.rejilla {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
}
@media (min-width: 1180px) {
  .grupo--rf .rejilla,
  .grupo--gestion .rejilla { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.portal {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 23px 23px 20px;
  min-height: 272px;
  border-radius: 20px;
  text-decoration: none;
  color: var(--nieve);
  background:
    radial-gradient(260px 170px at 95% 0%, rgba(var(--acento-rgb), .13), transparent 78%),
    linear-gradient(148deg, rgba(13, 38, 66, .97), rgba(7, 24, 45, .98) 72%);
  border: 1px solid rgba(var(--acento-rgb), .19);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06),
              0 12px 30px rgba(0, 8, 21, .16);
  overflow: hidden;
  opacity: 1;
  animation: subir .55s var(--salida) backwards;
  transition: transform .3s var(--salida), border-color .3s var(--suave),
              box-shadow .3s var(--suave), opacity .3s var(--suave);
}

/* Escalonado por clase, no por atributo style: la CSP prohibe estilos en
   linea, asi que el retardo tiene que estar aqui. */
.portal.r1 { animation-delay: .06s; }
.portal.r2 { animation-delay: .13s; }
.portal.r3 { animation-delay: .20s; }
.portal.r4 { animation-delay: .27s; }
.portal.r5 { animation-delay: .34s; }
.portal.r6 { animation-delay: .41s; }
.portal.r7 { animation-delay: .48s; }
.portal.r8 { animation-delay: .55s; }

@keyframes subir {
  from { opacity: 0; transform: translate3d(0, 22px, 0) scale(.985); }
  to   { opacity: 1; transform: none; }
}

.portal:hover, .portal:focus-visible {
  transform: translateY(-6px);
  border-color: rgba(var(--acento-rgb), .68);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .11),
              0 24px 48px rgba(0, 8, 21, .42),
              0 0 30px rgba(var(--acento-rgb), .08);
}

/* Un foco de luz bajo el cursor, no el barrido diagonal de antes. En una
   rejilla de tarjetas iguales el barrido era adorno; esto senala cual
   esta activa, que es informacion. Las coordenadas las pone el guion en
   --mx / --my; sin guion, el foco queda centrado y no molesta. */
.portal::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(
    300px circle at var(--mx, 50%) var(--my, 0%),
    rgba(var(--acento-rgb), .23),
    transparent 64%);
  opacity: 0;
  transition: opacity .35s var(--suave);
  pointer-events: none;
}
.portal:hover::before, .portal:focus-visible::before { opacity: 1; }
.portal::after {
  content: "";
  position: absolute;
  inset: 0 auto auto 0;
  width: 100%;
  height: 2px;
  background: linear-gradient(90deg, var(--acento-tarjeta), rgba(var(--acento-rgb), .35), transparent 82%);
  transform: scaleX(.38);
  transform-origin: left;
  transition: transform .42s var(--salida);
  pointer-events: none;
}
.portal:hover::after, .portal:focus-visible::after { transform: scaleX(1); }
.portal > * { position: relative; z-index: 1; }

.portal__cabecera {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 22px;
}

/* El icono va en su propia caja. Suelto a 42px flotaba sin anclaje en la
   esquina; encajado da un punto de entrada claro a la tarjeta y separa el
   dibujo del nombre sin necesidad de mas espacio. */
.portal__icono {
  width: 52px;
  height: 52px;
  flex: none;
  padding: 11px;
  border-radius: 14px;
  background: linear-gradient(150deg, rgba(var(--acento-rgb), .2), rgba(var(--acento-rgb), .055));
  border: 1px solid rgba(var(--acento-rgb), .32);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .09),
              0 8px 20px rgba(var(--acento-rgb), .09);
  color: var(--acento-tarjeta);
  transition: transform .34s var(--salida), background .26s var(--suave),
              border-color .26s var(--suave);
}
.portal:hover .portal__icono {
  background: rgba(var(--acento-rgb), .21);
  border-color: rgba(var(--acento-rgb), .6);
}
.portal:hover .portal__icono, .portal:focus-visible .portal__icono { transform: translateY(-3px); }

.portal__familia {
  color: var(--acento-tarjeta);
  font-size: .66rem;
  font-weight: 750;
  line-height: 1.2;
  letter-spacing: .13em;
  text-align: right;
  text-transform: uppercase;
  padding-top: 5px;
}

.portal__nombre {
  font-family: var(--letra-titulo);
  font-size: clamp(1.2rem, 1.5vw, 1.45rem);
  font-weight: 750;
  /* En tamanos de titulo la pila del sistema abre demasiado; cerrarla un
     poco es lo que separa un titulo de un parrafo en negrita. */
  letter-spacing: -.025em;
  line-height: 1.12;
  margin: 0 0 12px;
}

.portal__detalle {
  font-size: var(--t-cuerpo);
  line-height: 1.48;
  color: #bbcbdd;
  margin: 0 0 20px;
  max-width: 44ch;
}

.portal__accion {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: auto;
  padding-top: 15px;
  border-top: 1px solid rgba(var(--acento-rgb), .16);
  color: var(--acento-tarjeta);
  font-size: var(--t-menor);
  font-weight: 700;
  line-height: 1;
}
.portal__accion::after {
  content: "↗";
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  flex: none;
  border: 1px solid rgba(var(--acento-rgb), .35);
  border-radius: 50%;
  font-size: 1rem;
  font-weight: 400;
  transition: transform .26s var(--salida), background .26s var(--suave);
}
.portal:hover .portal__accion::after,
.portal:focus-visible .portal__accion::after {
  transform: translate(2px, -2px);
  background: rgba(var(--acento-rgb), .17);
}

/* Solo se muestra cuando falta poco: enterarse de que el acceso vencio
   despues de perderlo es la peor forma de enterarse. */
.portal__vence {
  align-self: flex-start;
  margin-top: var(--e1);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--ambar);
  background: rgba(255, 176, 60, .12);
  border: 1px solid rgba(255, 176, 60, .3);
  border-radius: var(--r-pastilla);
  padding: 4px 11px;
}

.rechazo {
  width: 100%;
  max-width: 1120px;
  margin: 0 auto var(--e4);
  font-size: var(--t-cuerpo);
  color: var(--ambar);
  background: rgba(255, 176, 60, .1);
  border: 1px solid rgba(255, 176, 60, .3);
  border-radius: var(--r-chico);
  padding: 12px var(--e3);
  animation: aparecer .4s var(--salida) both;
}
.rechazo[hidden] { display: none; }

.vacio { color: var(--apagado); font-size: var(--t-cuerpo); }
.vacio[hidden] { display: none; }

/* Confirmacion al abrir una plataforma.
   Entre el clic y la plataforma hay un canje de pase: el portal comprueba
   el permiso, emite un pase de un solo uso y redirige. Son unos cientos de
   milisegundos en los que la pantalla se queda igual y parece que el clic
   no hizo nada. La tarjeta elegida se adelanta y las demas se retiran, asi
   que el sistema responde antes de que el navegador se mueva. */
.portal--yendo {
  transform: translateY(-5px) scale(1.01);
  border-color: var(--acento-tarjeta);
  box-shadow: 0 22px 48px rgba(0, 8, 18, .5);
  z-index: 1;
}
.portal--yendo::before { opacity: 1; }
.catalogo--yendo .portal:not(.portal--yendo) {
  opacity: .42;
  transform: scale(.985);
}
.catalogo--yendo .portal { transition-duration: .3s; }

/* La barra entra antes que la rejilla: primero el sitio donde uno esta,
   despues lo que puede abrir. */
.barra { animation: aparecer .5s var(--salida) both; }

/* ---------- Foco visible en todo lo interactivo --------------------- */
a:focus-visible, button:focus-visible, input:focus-visible {
  outline: 2px solid var(--cian-vivo);
  outline-offset: 3px;
}

/* ---------- Menos movimiento ---------------------------------------- */
/* Quien pidio menos animacion en su sistema no recibe ninguna: anillos,
   escalonados y desplazamientos se apagan. La bienvenida sigue
   existiendo pero se resuelve con una aparicion simple, y el guion
   ademas la acorta. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .intro-red, .intro-pulso, .avance { display: none; }
  .portal--yendo { transform: none; }
  .catalogo--yendo .portal:not(.portal--yendo) { opacity: 1; transform: none; }
  .marca-grande, .intro-nombre, .intro-descriptor, .portal, .omitir, .tarjeta > * { opacity: 1; }
  .portal:hover, .portal:focus-visible { transform: none; }
  .boton:active { transform: none; }
}

/* El desenfoque de la tarjeta cuesta GPU y hay quien lo tiene desactivado
   a proposito. Sin el, la superficie se rellena opaca para que el texto
   no pierda contraste. */
@media (prefers-reduced-transparency: reduce) {
  .tarjeta {
    background: #0C2440;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .portal { background: #0b2745; }
}

/* ---------- Pantallas chicas ---------------------------------------- */
@media (max-width: 560px) {
  .pantalla { padding: var(--e4) var(--e3); }
  .intro-escena { height: min(64dvh, 400px); min-height: 280px; }
  .intro-red { opacity: .58; }
  .intro-marca { width: min(300px, 90vw); }
  .marca-grande { width: min(200px, 58vw); }
  .intro-nombre { font-size: 1.4rem; }
  .intro-descriptor { font-size: .6rem; }
  .intro-pulso { width: 150px; }
  /* En pantalla angosta el bloque entero no cabe junto a los dos botones
     de la barra (356 px contra 343 disponibles). En vez de cargar un
     segundo archivo se recorta el mismo: el simbolo ocupa el primer
     34 % del ancho, asi que 65 x 35 con object-fit deja solo el simbolo. */
  .marca-chica {
    width: 65px;
    height: 35px;
    object-fit: cover;
    object-position: left center;
  }
  .avance { bottom: 15px; width: 120px; }
  .tarjeta { padding: var(--e4) var(--e4) var(--e3); border-radius: var(--r-medio); }
  .rejilla { grid-template-columns: 1fr; gap: var(--e3); }
  .catalogo { gap: 38px; }
  .catalogo-encabezado { margin: 36px auto 34px; }
  .grupo__encabezado { padding-left: 14px; }
  .grupo__encabezado { grid-template-columns: 1fr; }
  .grupo__cantidad { margin-top: 7px; }
  .grupo__detalle { margin-top: 8px; }
  .portal { min-height: 216px; }
  .portal__cabecera { margin-bottom: 17px; }
  .barra { margin-bottom: 0; }
}

/* Marca canonica 2026-10-16: isotipo pixel a pixel del SVG aprobado. */
.marca-completa{display:flex;flex-direction:column;align-items:center;gap:0;width:100%;align-self:center;margin-bottom:var(--e2)}
.marca-completa img{width:122px;height:auto;display:block}
.marca-completa span{color:#fff;font-size:1.42rem;font-weight:750;letter-spacing:.19em;line-height:1.3;white-space:nowrap;margin-left:.19em}
.marca-barra{display:inline-flex;align-items:center;gap:10px;flex:none;filter:drop-shadow(0 2px 6px rgba(2,10,22,.55))}
.marca-barra img{display:block;width:64px;height:auto}
.marca-barra span{color:#fff;font-weight:750;letter-spacing:.18em;font-size:1rem;white-space:nowrap}
@media(max-width:560px){.marca-barra span{display:none}.marca-barra img{width:62px}}
@media (max-width: 380px) {
  .barra { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; row-gap: 12px; }
  .marca-barra { grid-column: 1 / -1; }
  .barra__hueco { display: none; }
  #enlaceAdmin { grid-column: 2; }
  #botonSalir { grid-column: 3; }
  .catalogo-encabezado { margin: 20px auto 24px; }
  .grupo__encabezado { grid-template-columns: minmax(0, 1fr) auto; padding-bottom: 12px; margin-bottom: 14px; }
  .grupo__encabezado h2 { font-size: 1.12rem; }
  .grupo__cantidad { margin-top: 0; font-size: .7rem; }
  .grupo__detalle { margin-top: 6px; font-size: .875rem; }
  .portal {
    display: grid;
    grid-template-columns: 52px minmax(0, 1fr);
    align-items: center;
    gap: 10px 13px;
    min-height: 0;
    padding: 18px 18px 15px;
  }
  .portal__cabecera { grid-column: 1; grid-row: 1; margin: 0; }
  .portal__familia { display: none; }
  .portal__nombre { grid-column: 2; grid-row: 1; margin: 0; }
  .portal__detalle, .portal__vence, .portal__accion { grid-column: 1 / -1; }
  .portal__detalle { margin-bottom: 0; }
  .portal__vence { justify-self: start; }
  .portal__accion { margin-top: 0; padding-top: 10px; }
}
