/* ============================================================================
   Valdra · Portal de administración — sistema visual

   Los tokens de color son los de docs/brand/tokens.css, copiados aquí en lugar
   de importados: ese archivo no se sirve como estático y un @import remoto sería
   justo la dependencia de red que la plataforma promete no tener. Cuando cambie
   la paleta se cambia en los dos sitios; es el precio de poder demostrar el
   portal con el cable desconectado.

   Reglas del sistema, en orden de importancia:

   1. Un acento y uno solo: ámbar. Distribución de superficie 70 neutro /
      20 canvas / 7 ámbar / 3 estado, y el degradado de marca aparece solo en el
      logotipo. Esto es una consola de infraestructura financiera, no una
      aplicación de IA de consumo.
   2. El ámbar de marca #F59E0B no va sobre superficie clara: da 2,06:1 y no es
      legible. Sobre claro se usa --accent, que vale #B45309. Nunca un color
      literal en una vista; siempre la variable.
   3. Densidad alta. Un administrador quiere más información en pantalla, no
      más aire. Filas de 34 px, tarjetas sin relleno decorativo, el ancho
      aprovechado hasta 1600 px.
   4. La monoespaciada se reserva para identificadores, códigos y cifras. Las
      etiquetas van en la tipografía de texto: una etiqueta monoespaciada en
      mayúsculas convierte cualquier producto en una herramienta de programador.
   5. Los efectos son funcionales y cortos: realce de fila, anillo de foco,
      sombra de superficie elevada, 120–160 ms. Ni desenfoques, ni resplandores,
      ni sombras de color, ni animaciones en bucle.
   ============================================================================ */

:root {
  color-scheme: light dark;

  /* ── Marca ─────────────────────────────────────────────────────────────────
     El ámbar de marca y el ámbar utilizable son DOS variables distintas, y esa
     separación no es un capricho de nomenclatura: medido sobre --bg, #F59E0B da
     2,06:1. No es legible, no lo es «casi», y no hay tamaño de letra que lo
     arregle. Sobre el canvas oscuro el mismo ámbar da 9,37:1.

     Consecuencia: --brand-amber solo lo lleva el núcleo del isotipo, que es
     idéntico en los dos temas porque el manual prohíbe recolorear la marca.
     Todo lo demás —texto, borde activo, enlace, icono— usa --accent, que baja
     a ámbar profundo en claro y sube al ámbar de marca en oscuro. */
  --brand-amber: #F59E0B;
  --accent:       #B45309;   /* 4,81:1 sobre --bg */
  --accent-hover: #92400E;
  --accent-deep:  #78350F;
  --accent-soft:  #FCD34D;
  --ink:          #111827;
  --canvas:       #030712;
  --grad: linear-gradient(135deg,#FCD34D 0%,#F59E0B 40%,#B45309 72%,#78350F 100%);

  /* ── Neutros ───────────────────────────────────────────────────────────── */
  --bg:            #F9FAFB;
  --surface:       #FFFFFF;
  --surface-2:     #F3F4F6;
  --surface-3:     #E5E7EB;
  --border:        #E5E7EB;
  --border-strong: #D1D5DB;
  --text:          #111827;
  --text-2:        #4B5563;
  --text-muted:    #6B7280;
  --disabled:      #D1D5DB;

  /* ── Semántica ─────────────────────────────────────────────────────────────
     El manual de marca no tiene paleta de estado: éxito, aviso y error se
     resuelven en ámbar y neutros. Aquí sí la hay, y es una desviación asumida:
     esto no es la web de la marca, es la pantalla donde alguien distingue un
     nodo caído de un lote pendiente durante ocho horas seguidas. El color va
     siempre acompañado de texto, nunca solo. */
  --success: #15803D; --success-bg: #F0FDF4;
  --warning: #B45309; --warning-bg: #FFFBEB;
  --error:   #B91C1C; --error-bg:   #FEF2F2;
  --info:    #4B5563; --info-bg:    #F3F4F6;

  --class-confidential: #A16207;

  /* Fondo de la mitad de marca de la puerta de acceso. Un blanco con un punto
     de calidez, medio grado por delante de --surface: separa el panel del
     formulario sin necesidad de meter una línea más. */
  --gate-aside-bg: #FDFCFB;

  /* ── Barra lateral ─────────────────────────────────────────────────────────
     Canvas casi negro en los dos temas: es la superficie nativa de la marca y
     la constante que hace reconocible la aplicación al cambiar de tema. Sobre
     ella el ámbar de marca sí cumple, así que --rail-accent es el puro. */
  --rail-bg:      #030712;
  --rail-line:    rgba(255,255,255,.08);
  --rail-text:    #9CA3AF;
  --rail-text-hi: #F9FAFB;
  --rail-muted:   #6B7280;
  --rail-hover:   rgba(255,255,255,.06);
  --rail-active:  rgba(245,158,11,.14);
  --rail-accent:  #F59E0B;

  /* ── Tipografía ────────────────────────────────────────────────────────── */
  /* Inter y JetBrains Mono llegan de /assets/brand.css, empaquetadas con el
     producto. La pila del sistema queda detrás como red: si la cara no carga,
     la interfaz sigue leyéndose en vez de quedarse en blanco. El manual fija
     Inter para todo lo que se lee y el mono SOLO para terminal, eyebrows y
     captions numéricos: nunca cuerpo, botones, navegación ni pie. */
  --sans: "Inter", system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --mono: "JetBrains Mono", ui-monospace,"SF Mono",SFMono-Regular,Menlo,Consolas,monospace;

  /* ── Escala de espaciado de 4 px ───────────────────────────────────────── */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 20px; --s6: 24px; --s7: 32px; --s8: 40px; --s9: 56px;

  /* ── Radios ────────────────────────────────────────────────────────────── */
  --r1: 4px; --r2: 6px; --r3: 8px; --r4: 10px; --r5: 12px;

  /* ── Elevación: dos niveles y ninguno de color ─────────────────────────── */
  --shadow:    0 1px 2px rgba(3,7,18,.05);
  --shadow-2:  0 1px 2px rgba(3,7,18,.06), 0 8px 24px -16px rgba(3,7,18,.24);
  --shadow-lg: 0 12px 40px -14px rgba(3,7,18,.30);

  /* ── Movimiento ────────────────────────────────────────────────────────── */
  --mo: 140ms cubic-bezier(.2,.6,.3,1);
  --mo-fast: 120ms cubic-bezier(.2,.6,.3,1);

  --ring: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
  --canvas-max: 1600px;
  --rail-w: 236px;
}

/* ── Tema oscuro ─────────────────────────────────────────────────────────────
   Aquí el tema oscuro NO es una inversión del claro: es el original. El canvas
   casi negro con el acento ámbar es la superficie que define la marca, y el
   tema claro es la traducción para quien trabaja en una sucursal con la
   persiana subida.

   Va escrito dos veces a propósito. Una bajo prefers-color-scheme, para quien
   no ha elegido nada; otra bajo [data-theme="dark"], para quien sí. Definir el
   valor una sola vez dentro de la media query dejaría el conmutador manual sin
   nada que sobreescribir al pedir oscuro desde un sistema en claro, y esa es la
   mitad de los casos.                                                          */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:            #030712;
    --surface:       #0B1220;
    --surface-2:     #111A2B;
    --surface-3:     #1B2436;
    --border:        rgba(255,255,255,.08);
    --border-strong: rgba(255,255,255,.16);
    --text:          #F9FAFB;
    --text-2:        #D1D5DB;
    --text-muted:    #9CA3AF;
    --disabled:      #4B5563;

    /* Sobre el canvas el ámbar de marca da 9,37:1 y ya no hace falta rebajarlo:
       este es el único tema donde el acento de la interfaz y el de la marca son
       exactamente el mismo color. */
    --accent:       #F59E0B;
    --accent-hover: #FCD34D;
    --accent-deep:  #B45309;

    --success: #4ADE80; --success-bg: rgba(74,222,128,.12);
    --warning: #FBBF24; --warning-bg: rgba(251,191,36,.12);
    --error:   #F87171; --error-bg:   rgba(248,113,113,.12);
    --info:    #9CA3AF; --info-bg:    rgba(255,255,255,.06);

    --class-confidential: #FCD34D;
    --gate-aside-bg: #0A101E;

    /* La barra lateral comparte color con el lienzo, así que se separa por una
       línea y no por un tono: sobre fondo oscuro una sombra no se ve y sí
       ensucia el borde. */
    --rail-bg:   #030712;
    --rail-line: rgba(255,255,255,.10);

    --shadow:    0 1px 2px rgba(0,0,0,.40);
    --shadow-2:  0 1px 2px rgba(0,0,0,.40), 0 8px 26px -18px rgba(0,0,0,.70);
    --shadow-lg: 0 14px 46px -16px rgba(0,0,0,.72);
  }
}

:root[data-theme="dark"] {
  --bg:            #030712;
  --surface:       #0B1220;
  --surface-2:     #111A2B;
  --surface-3:     #1B2436;
  --border:        rgba(255,255,255,.08);
  --border-strong: rgba(255,255,255,.16);
  --text:          #F9FAFB;
  --text-2:        #D1D5DB;
  --text-muted:    #9CA3AF;
  --disabled:      #4B5563;

  --accent:       #F59E0B;
  --accent-hover: #FCD34D;
  --accent-deep:  #B45309;

  --success: #4ADE80; --success-bg: rgba(74,222,128,.12);
  --warning: #FBBF24; --warning-bg: rgba(251,191,36,.12);
  --error:   #F87171; --error-bg:   rgba(248,113,113,.12);
  --info:    #9CA3AF; --info-bg:    rgba(255,255,255,.06);

  --class-confidential: #FCD34D;
  --gate-aside-bg: #0A101E;

  --rail-bg:   #030712;
  --rail-line: rgba(255,255,255,.10);

  --shadow:    0 1px 2px rgba(0,0,0,.40);
  --shadow-2:  0 1px 2px rgba(0,0,0,.40), 0 8px 26px -18px rgba(0,0,0,.70);
  --shadow-lg: 0 14px 46px -16px rgba(0,0,0,.72);
}

/* ── Base ──────────────────────────────────────────────────────────────────── */

* { box-sizing: border-box; }
html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 13.5px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-variant-numeric: tabular-nums;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r1);
}
[hidden] { display: none !important; }

h1, h2, h3 { margin: 0; }
h1 { font-size: 22px; font-weight: 650; letter-spacing: -.022em; line-height: 1.25; }
h2 { font-size: 14px; font-weight: 620; letter-spacing: -.008em; }
h3 { font-size: 13px; font-weight: 620; }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }

::selection { background: color-mix(in srgb, var(--accent) 24%, transparent); }

/* Una sola declaración de movimiento reducido, al final de la base: quien pide
   no ver animaciones no quiere excepciones repartidas por la hoja. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--surface); color: var(--text);
  padding: var(--s2) var(--s4);
  border: 1px solid var(--border); border-radius: 0 0 var(--r3) 0;
}
.skip:focus { left: 0; }

/* ── Utilidades ────────────────────────────────────────────────────────────── */

.mono { font-family: var(--mono); font-size: .94em; }
.xs   { font-size: 11.5px; }
.t2   { color: var(--text-2); }
.t3   { color: var(--text-muted); }
.right  { text-align: right; }
.center { text-align: center; }
.spacer { margin-left: auto; }
.block  { width: 100%; }
.num {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  text-align: right; white-space: nowrap; font-size: .95em;
}
.stack   { display: flex; flex-direction: column; gap: var(--s3); }
.rowline { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* ── Marca ─────────────────────────────────────────────────────────────────── */

.brand { display: flex; align-items: center; gap: var(--s3); min-width: 0; }

/* El isotipo va en SVG y no en PNG por dos razones, y la segunda es la que manda:
   a 28 px un raster se ve blando, y el perímetro tiene que cambiar de color con
   el tema. El SVG hereda currentColor en el trazo y deja el núcleo en ámbar de
   marca, que es lo que el manual exige que no cambie nunca.

   El hexágono es más alto que ancho (razón 0,83), así que la caja lo es también:
   forzarlo a un cuadrado lo dejaría flotando en un carril de aire a los lados. */
.mark {
  width: 26px; height: 31px; flex-shrink: 0;
  color: var(--rail-text-hi);
  font-size: 0;
}
.mark svg { display: block; width: 100%; height: 100%; }

.wm {
  font-size: 16px; font-weight: 700; letter-spacing: -.02em; line-height: 1.1;
  color: var(--rail-text-hi); white-space: nowrap;
}
/* Wordmark en una sola tinta. El manual es explícito: los modelos se nombran en
   tipografía, no se señalan recoloreando la marca; partir «Valdra» en dos
   colores sería justo eso. */
.tag {
  font-size: 10px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--rail-muted); margin-top: 2px; white-space: nowrap;
}
.brand-lg .mark { width: 32px; height: 38px; color: var(--text); }
.brand-lg .wm   { font-size: 20px; color: var(--text); }
.brand-lg .tag  { color: var(--text-muted); font-size: 11px; }

/* ── Puerta de acceso ──────────────────────────────────────────────────────────
   Una lámina apoyada sobre el fondo, y dentro dos mitades: identidad a la
   izquierda, formulario a la derecha. El patrón es el de una consola corporativa
   y no el de una aplicación de consumo, y esa diferencia es deliberada: quien
   entra aquí administra dinero ajeno.

   Las dos mitades siguen al tema. La versión anterior dejaba el panel de marca
   en canvas oscuro siempre; se cambió porque en tema claro el resultado era una
   pantalla partida por la mitad en dos temas distintos, y porque el manual
   permite ámbar profundo sobre superficie clara justamente para esto.

   Lo que NO hay en esta pantalla, y es una decisión y no un olvido: no hay
   «¿olvidaste tu contraseña?» porque la plataforma no tiene recuperación por
   autoservicio —el alta y la reposición las hace el propietario de la cuenta de
   la organización—, y no hay botones de SSO ni de Microsoft porque no hay
   proveedor de identidad federada conectado. Un botón que no lleva a ninguna
   parte en una pantalla de acceso no es un adorno: es una llamada al soporte.  */

.gate {
  position: fixed; inset: 0; overflow: auto;
  background: var(--bg);
  display: grid; place-items: center;
  padding: var(--s6);
}

/* Reanudación de sesión: theme.js marca el raíz con data-session antes de que
   exista esta hoja. Mientras dure, la puerta no se pinta ni un fotograma y se
   enseña la marca en espera. app.js retira la marca al entrar o al caducar. */
html[data-session] .gate { display: none !important; }
.boot {
  position: fixed; inset: 0; z-index: 5;
  display: none; place-items: center;
  background: var(--bg); color: var(--text-muted);
}
html[data-session] .boot { display: grid; }
.boot-mark { width: 44px; height: 52px; color: var(--accent); }
.boot-mark svg { width: 100%; height: 100%; display: block; }
.boot-inner { display: grid; justify-items: center; gap: var(--s3); }
.boot-word { font: 500 12px/1 var(--mono); letter-spacing: .15em; text-transform: uppercase; }
@media (prefers-reduced-motion: no-preference) {
  .boot-mark { animation: boot-breathe 3s ease-in-out infinite; }
  @keyframes boot-breathe { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
}

/* ── La puerta se compromete al oscuro, como la de la consola ──────────────
   DESIGN.md reserva claro/oscuro/sistema para las superficies de jornada. Una
   puerta se cruza en quince segundos: no es una jornada. Hasta hoy la de admin
   seguía el tema del sistema y traía su propio conmutador, y así el mismo
   producto tenía dos puertas con dos identidades. Los tokens se declaran sobre
   la puerta y todo lo que cuelga hereda; #B45309 queda fuera porque el manual
   lo prohíbe sobre el canvas oscuro. El conmutador vive dentro, donde actúa. */
.gate {
  background: #030712;
  color-scheme: dark;
  --bg:            #030712;
  --surface:       #0B1220;
  --surface-2:     #111A2B;
  --surface-3:     #1B2436;
  --text:          #F9FAFB;
  --text-2:        #D1D5DB;
  --text-muted:    #9CA3AF;
  --accent:        #F59E0B;
  --border:        rgba(255,255,255,.08);
}

/* La lámina. Se le pone un ancho máximo y no se deja crecer: un formulario de
   acceso a 2560 px de ancho separa tanto la etiqueta del campo que deja de
   leerse como una pareja. */
.gate-shell {
  width: 100%; max-width: 76rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r5);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.gate-split {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

/* ── Mitad de marca ───────────────────────────────────────────────────────── */

.gate-aside {
  padding: var(--s8) var(--s7);
  display: flex; flex-direction: column; gap: var(--s5);
  position: relative; overflow: hidden;
  border-right: 1px solid var(--border);
  background: var(--gate-aside-bg, #FDFCFB);
}
/* Dos manchas de ámbar muy diluido. El manual admite «vidrio sobre una mancha»
   como recurso de profundidad y prohíbe el resplandor; la diferencia práctica es
   que la mancha se queda quieta detrás del contenido y el resplandor persigue a
   la marca. Ninguna toca el logotipo. */
.gate-aside::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(42rem 24rem at 88% 6%, rgba(245,158,11,.10), transparent 62%),
    radial-gradient(34rem 22rem at 4% 96%, rgba(180,83,9,.07), transparent 64%);
}
.gate-aside > * { position: relative; z-index: 1; }

/* flex: none es obligatorio, no cosmético: el panel es una columna flex y sin él
   el navegador encoge la caja del logotipo hasta cero para hacer sitio al resto.
   El síntoma es un panel correcto y sin marca, que es peor que un panel roto
   porque parece intencionado.

   La razón de aspecto sale del archivo real (640×207). Dársela redonda dejaría
   el logotipo nadando en una caja vacía, y ese aire de más se leería como parte
   del espacio de respeto de la marca, que es otra cosa y mide otra cosa. */
.gate-logo {
  flex: none;
  width: 11.5rem; aspect-ratio: 640 / 207;
  background: url("/assets/logo.png") left center / contain no-repeat;
}
/* En oscuro el logotipo cambia de archivo y no de filtro. Un invert() sobre el
   original convertiría el ámbar en azul, que es exactamente el color del que la
   marca huye. */
:root[data-theme="dark"] .gate-logo { background-image: url("/assets/logo-dark.png"); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gate-logo { background-image: url("/assets/logo-dark.png"); }
}

/* Filete corto sobre el titular: la misma pieza que el logotipo lleva a los
   lados del descriptor. Marca dónde empieza el mensaje. */
.gate-rule {
  width: 2.25rem; height: 3px; border-radius: 2px;
  background: var(--accent); flex: none;
}

/* El descriptor de marca, y en inglés a propósito: «Sovereign Private AI» es el
   descriptor, no el mensaje. El mensaje —«Tu modelo. Tus muros.»— sí se traduce,
   y vive debajo, en el diccionario. Traducir el descriptor lo convertiría en una
   frase distinta en cada mercado, que es lo contrario de un descriptor. */
.gate-claim {
  margin: 0; max-width: 11ch;
  font-size: clamp(1.9rem, 3vw, 2.55rem); line-height: 1.06;
  letter-spacing: -.035em; font-weight: 800; color: var(--text);
  text-wrap: balance;
}
.gate-claim em {
  display: block; font-style: normal; color: var(--accent);
}
.gate-sell {
  margin: 0; max-width: 36ch; font-size: .97rem; line-height: 1.55;
  color: var(--text-2); text-wrap: pretty;
}

/* La ilustración carga el peso visual del panel y por eso se le deja consumir el
   espacio sobrante en lugar de fijarle una altura: entre 900 px y 1400 px de
   ventana el panel crece bastante, y un dibujo de altura fija dejaría un hueco
   creciente encima de las garantías. */
.gate-art {
  flex: 1 1 auto; min-height: 8rem;
  display: grid; place-items: center;
  margin: var(--s2) 0;
}
.gate-art img { width: 100%; max-width: 24rem; height: 100%; object-fit: contain; }

/* Las tres garantías, en fila. Son el resumen de lo que se promete y por eso van
   pegadas al pie del panel: es lo último que se lee antes de mirar al
   formulario. */
.gate-points {
  list-style: none; margin: 0; padding: var(--s5) 0 0; border-top: 1px solid var(--border);
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s4);
}
.gate-points li { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.gate-points .pt-ico {
  width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  border: 1px solid var(--border); background: var(--surface);
  color: var(--accent); flex: none;
}
.gate-points .pt-ico svg { width: 15px; height: 15px; }
.gate-points strong { font-size: .82rem; font-weight: 620; color: var(--text); }
.gate-points span { font-size: .78rem; line-height: 1.4; color: var(--text-muted); text-wrap: pretty; }

.gate-legal {
  margin: 0; font-family: var(--mono); font-size: .68rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-muted);
}

/* ── Mitad de formulario ──────────────────────────────────────────────────── */

.gate-main {
  display: flex; flex-direction: column;
  padding: var(--s6) var(--s7) var(--s7);
  background: var(--bg);
}
/* Los mandos de idioma y tema, arriba y a la derecha, antes del formulario. Van
   aquí y no debajo por orden de uso: quien abre esto de noche o no lee español
   necesita arreglar eso ANTES de escribir su contraseña, no después de fallar al
   escribirla. */
.gate-bar {
  display: flex; justify-content: flex-end; gap: var(--s2);
  margin-bottom: auto; flex-wrap: wrap;
}

/* La tarjeta lleva superficie y borde propios. Sin ellos los campos flotaban
   directamente sobre el panel, y el formulario se leía como un montón de cajas
   sueltas en vez de como una unidad: no había nada que dijera dónde empieza y
   dónde acaba lo que hay que rellenar. */
.gate-card {
  width: 100%; max-width: 24rem; margin: var(--s6) auto auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r5);
  box-shadow: var(--shadow-2);
  padding: var(--s7) var(--s6) var(--s6);
  display: flex; flex-direction: column; gap: var(--s4);
}

/* El candado. Es el único icono decorativo de la pantalla y se gana el sitio:
   dice de qué va esto antes de que nadie lea el titular. aria-hidden en el
   marcado — para un lector de pantalla, «candado» delante de «Entrar a tu
   consola» no añade nada. */
.gate-badge {
  width: 46px; height: 46px; border-radius: 50%; margin: 0 auto;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent);
}
.gate-badge svg { width: 20px; height: 20px; }

.gate-card h1 {
  margin: 0; font-size: 1.5rem; letter-spacing: -.028em; font-weight: 700;
  text-wrap: balance; color: var(--text); text-align: center;
}
.gate-sub {
  margin: 0; color: var(--text-2); font-size: .92rem; text-align: center;
  text-wrap: pretty;
}
.gate-form { display: flex; flex-direction: column; gap: var(--s4); }
.gate-form .field { margin-bottom: 0; }

/* Campo con icono a la izquierda y, en la contraseña, botón a la derecha. El
   relleno lateral del input se amplía en la misma medida que ocupa el adorno:
   si se superpusiera sin reservar sitio, el texto pasaría por debajo del icono
   en cuanto alguien escribiera un correo largo. */
.gate-field { position: relative; display: flex; align-items: center; }
.gate-field > svg {
  position: absolute; left: 11px; width: 16px; height: 16px;
  color: var(--text-muted); pointer-events: none;
}
.gate-field input { padding: 9px 11px 9px 34px; }
.gate-field.has-toggle input { padding-right: 38px; }
.gate-field:focus-within > svg { color: var(--accent); }

/* Mostrar la contraseña. Existe porque la alternativa real no es escribirla bien
   a ciegas: es escribirla en el campo de correo para verla, y eso la manda al
   servidor en claro dentro del usuario y la deja en el historial del navegador. */
.gate-reveal {
  position: absolute; right: 6px;
  display: grid; place-items: center; width: 28px; height: 28px;
  border: 0; border-radius: var(--r2); background: none; cursor: pointer;
  color: var(--text-muted);
  transition: color var(--mo-fast), background var(--mo-fast);
}
.gate-reveal:hover { color: var(--text); background: var(--surface-2); }
.gate-reveal svg { width: 16px; height: 16px; }

.gate-submit { padding: 10px var(--s4); font-size: 14px; }
.gate-submit svg { width: 16px; height: 16px; }

/* Sin tono es un error —así lo llama app.js cuando el acceso falla— y con .info
   es una explicación. El borde lateral hace el trabajo que el color por sí solo
   no puede hacer para quien no distingue rojo de gris. */
.gate-msg {
  margin: 0; padding: var(--s3) var(--s4);
  border-radius: var(--r2); border-left: 3px solid var(--error);
  background: var(--error-bg); color: var(--error);
  font-size: .9rem; text-wrap: pretty;
}
.gate-msg.info {
  border-left-color: var(--border-strong);
  background: var(--surface-2); color: var(--text-2);
}
.gate-foot {
  margin: 0; font-size: .85rem; color: var(--text-muted);
  text-align: center; text-wrap: pretty;
}

/* Un <button> que se lee como enlace. Es un botón y no un <a> porque no navega
   a ninguna parte: cambia de formulario dentro de la misma pantalla, y un enlace
   sin destino es una promesa que el teclado no cumple. La clase existía en el
   marcado de la puerta desde el principio pero no estaba definida en ninguna
   hoja, así que estos botones salían con el estilo nativo del navegador — un
   rectángulo gris en mitad de un párrafo. */
.linkish {
  border: 0; background: none; padding: 0;
  font: inherit; color: var(--accent); font-weight: 550;
  cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.linkish:hover { color: var(--accent-hover); }

/* ── Pie de la lámina ─────────────────────────────────────────────────────── */

.gate-footbar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  padding: var(--s4) var(--s7);
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  font-size: .78rem; color: var(--text-muted);
}
.gate-footbar p { margin: 0; }
.gate-footbar .mark { width: 18px; height: 21px; color: var(--accent); }
/* Aviso de «hace falta JavaScript». Reutiliza .gate y .gate-card pero sin la
   lámina de dos mitades: no hay formulario que enmarcar, solo una frase que
   explica por qué la pantalla está vacía. El margen automático de la tarjeta,
   que en la puerta la empuja hacia arriba, aquí la descentraría. */
noscript .gate-card { margin: 0 auto; max-width: 30rem; text-align: center; }

/* ── Adaptación ───────────────────────────────────────────────────────────── */

/* Por debajo de 62rem las dos mitades se apilan: mantenerlas en columnas dejaría
   el formulario en una franja donde no cabe escribir. Lo que sobrevive es el
   logotipo y el mensaje; la ilustración y las garantías se retiran, porque en un
   móvil son un obstáculo entre el usuario y el formulario. */
@media (max-width: 62rem) {
  .gate { padding: 0; place-items: stretch; }
  .gate-shell { max-width: none; border: 0; border-radius: 0; box-shadow: none; min-height: 100%; }
  .gate-split { grid-template-columns: 1fr; }
  .gate-aside {
    padding: var(--s5) var(--s5) var(--s6);
    gap: var(--s4);
    border-right: 0; border-bottom: 1px solid var(--border);
  }
  .gate-art, .gate-points { display: none; }
  .gate-claim { font-size: 1.75rem; max-width: none; }
  .gate-claim em { display: inline; }
  .gate-sell { display: none; }
  .gate-logo { width: 8.5rem; }
  .gate-main { padding: var(--s5) var(--s4) var(--s7); background: var(--surface); }
  .gate-card {
    margin-top: var(--s4); padding: 0;
    background: none; border: 0; box-shadow: none;
  }
  .gate-footbar { padding: var(--s4) var(--s5); }
}

/* ── Armazón ───────────────────────────────────────────────────────────────── */

.app { display: grid; grid-template-columns: var(--rail-w) minmax(0, 1fr); min-height: 100vh; }
@media (max-width: 960px) { .app { grid-template-columns: 1fr; } }

.rail {
  background: var(--rail-bg);
  border-right: 1px solid var(--rail-line);
  display: flex; flex-direction: column;
  padding: var(--s4) var(--s3) var(--s3);
  gap: var(--s4);
  position: sticky; top: 0; height: 100vh; min-height: 0;
}
@media (max-width: 960px) { .rail { position: static; height: auto; } }

/* ── Navegación ────────────────────────────────────────────────────────────── */

.nav {
  display: flex; flex-direction: column; gap: var(--s5);
  overflow-y: auto; min-height: 0; flex: 1;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,.16) transparent;
}
.nav::-webkit-scrollbar { width: 6px; }
.nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,.16); border-radius: 3px; }

.nav-group { display: flex; flex-direction: column; gap: 1px; }
/* Los grupos se separan con una línea, no con más aire: doce entradas sueltas
   son una lista; cuatro grupos rotulados son un mapa de la plataforma. */
.nav-group + .nav-group { border-top: 1px solid var(--rail-line); padding-top: var(--s4); }
.nav-title {
  font-size: 10.5px; font-weight: 650; letter-spacing: .10em; text-transform: uppercase;
  color: var(--rail-muted); padding: 0 var(--s2); margin: 0 0 var(--s2);
}

.nav button {
  position: relative; display: flex; align-items: center; gap: var(--s2);
  width: 100%; padding: 6px var(--s2); border: 0; border-radius: var(--r2);
  background: none; color: var(--rail-text); font: inherit; font-size: 13px;
  cursor: pointer; text-align: left;
  transition: background var(--mo-fast), color var(--mo-fast);
}
.nav button:hover { background: var(--rail-hover); color: var(--rail-text-hi); }
.nav button[aria-current="page"] {
  background: var(--rail-active); color: var(--rail-text-hi); font-weight: 600;
}
.nav button[aria-current="page"]::before {
  content: ""; position: absolute; left: 0; top: 6px; bottom: 6px;
  width: 2px; border-radius: 0 2px 2px 0; background: var(--rail-accent);
}
.nav .ico {
  width: 16px; height: 16px; flex-shrink: 0; opacity: .72;
  transition: opacity var(--mo-fast);
}
.nav button:hover .ico,
.nav button[aria-current="page"] .ico { opacity: 1; }
.nav button[aria-current="page"] .ico { color: var(--rail-accent); }
.nav .label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Punto de aviso: la ruta existe en el menú pero su script no se registró. */
.nav .dot {
  width: 5px; height: 5px; border-radius: 50%; background: var(--warning);
  margin-left: auto; flex-shrink: 0;
}

/* ── Pie de la barra lateral ───────────────────────────────────────────────── */

.rail-foot {
  display: flex; flex-direction: column; gap: var(--s2);
  border-top: 1px solid var(--rail-line); padding-top: var(--s3);
}
.who { font-size: 11.5px; color: var(--rail-muted); line-height: 1.45; min-width: 0; }
.who b {
  color: var(--rail-text-hi); font-weight: 600; font-size: 12.5px;
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.who .mail {
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.who .role {
  display: inline-block; margin-top: var(--s1); padding: 1px 6px;
  border-radius: var(--r1); border: 1px solid color-mix(in srgb, var(--accent-soft) 55%, transparent);
  color: var(--accent-soft); font-size: 10.5px; font-weight: 600;
  font-family: var(--mono); letter-spacing: -.01em;
}

/* Selector de idioma: nombres en su propia lengua, nunca banderas — una bandera
   es un país y no una lengua, y en portugués de Brasil eso se nota. */
.lang { position: relative; display: block; }
.lang > svg {
  position: absolute; left: 8px; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px; color: var(--rail-muted); pointer-events: none;
}
.lang::after {
  content: ""; position: absolute; right: 10px; top: 50%;
  width: 6px; height: 6px; margin-top: -4px; pointer-events: none;
  border-right: 1.5px solid var(--rail-muted); border-bottom: 1.5px solid var(--rail-muted);
  transform: rotate(45deg);
}
.lang select {
  appearance: none; -webkit-appearance: none;
  width: 100%; padding: 6px 24px 6px 27px;
  background: rgba(255,255,255,.05); border: 1px solid var(--rail-line);
  border-radius: var(--r2); color: var(--rail-text);
  font-family: var(--sans); font-size: 12.5px; cursor: pointer;
  transition: background var(--mo-fast), border-color var(--mo-fast);
}
.lang select:hover { background: rgba(255,255,255,.09); color: var(--rail-text-hi); }
.lang select option { background: var(--rail-bg); color: var(--rail-text-hi); }

.rail-foot .btn.ghost {
  background: rgba(255,255,255,.05); border-color: var(--rail-line); color: var(--rail-text);
}
.rail-foot .btn.ghost:hover {
  background: rgba(255,255,255,.10); border-color: rgba(255,255,255,.2); color: var(--rail-text-hi);
}
.rail-link {
  color: var(--rail-muted); font-size: 12px; text-decoration: none;
  text-align: center; padding: var(--s1) 0;
  transition: color var(--mo-fast);
}
.rail-link:hover { color: var(--rail-text-hi); text-decoration: none; }

/* ── Zona principal ────────────────────────────────────────────────────────── */

.main { min-width: 0; display: flex; flex-direction: column; }

.top {
  height: 48px; padding: 0 var(--s6); display: flex; align-items: center; gap: var(--s3);
  background: var(--surface); border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 5;
}
@media (max-width: 960px) { .top { padding: 0 var(--s4); } }
.crumb {
  font-size: 12.5px; color: var(--text-muted); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.crumb b { color: var(--text); font-weight: 600; }
.actions { display: flex; gap: var(--s2); align-items: center; flex-shrink: 0; }

/* El ancho se usa hasta 1600 px: cortar en 1180 sobre un monitor de 1568 deja
   un quinto de la pantalla en blanco y las tablas flotando en el medio. */
.canvas {
  width: 100%; max-width: var(--canvas-max); margin: 0 auto;
  padding: var(--s5) var(--s6) var(--s9);
}
@media (max-width: 960px) { .canvas { padding: var(--s4) var(--s4) var(--s8); } }

.canvas > h1 { margin-bottom: var(--s1); }
.sub {
  color: var(--text-2); font-size: 13px; margin: 0 0 var(--s5);
  max-width: 84ch;
}
#view { outline: none; }

/* ── Tarjetas ──────────────────────────────────────────────────────────────── */

.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r4); box-shadow: var(--shadow-2);
  margin-bottom: var(--s4);
}
.card .hd {
  padding: var(--s3) var(--s4); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
  background: var(--surface);
}
.card .hd h2 { font-size: 13px; font-weight: 620; }
.card .hd .n {
  font-family: var(--mono); font-size: 11px; color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--border);
  padding: 1px 6px; border-radius: var(--r1);
}
.card .bd { padding: var(--s4); }
/* El recorte va en el cuerpo pegado a los bordes —el que contiene una tabla— y
   no en la tarjeta entera: recortar la tarjeta también recortaría cualquier
   desplegable que una vista abra dentro de ella, y ese fallo aparecería lejos
   de aquí y sin explicación. */
.card .bd.tight { padding: 0; overflow: hidden; border-radius: 0 0 var(--r4) var(--r4); }
.card .hd:first-child { border-radius: var(--r4) var(--r4) 0 0; }

.panel {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r4);
  padding: var(--s7) var(--s6); text-align: center; box-shadow: var(--shadow);
}
.panel h2 { font-size: 15px; margin-bottom: var(--s2); }
.panel p { color: var(--text-2); font-size: 13px; margin: 0 auto; max-width: 68ch; }
.panel .btn { margin-top: var(--s4); }
.panel.deny {
  border-color: color-mix(in srgb, var(--warning) 38%, transparent);
  background: var(--warning-bg);
}
.panel.broken {
  border-color: color-mix(in srgb, var(--error) 38%, transparent);
  background: var(--error-bg);
}

.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--s3); }

/* ── Indicadores ───────────────────────────────────────────────────────────── */

/* Rejilla de verdad: número fijo de columnas por tramo, así todas las tarjetas
   miden lo mismo y el salto de línea es previsible. Con `auto-fit` la última
   fila se estira y aparece el defecto que había: cinco arriba, dos abajo y
   anchos distintos. */
.kpis {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s3); margin-bottom: var(--s5);
}
@media (max-width: 1400px) { .kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 1040px) { .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px)  { .kpis { grid-template-columns: 1fr; } }

/* Las tarjetas de indicador no llevan sombra: son una franja de lectura, no
   objetos flotantes. La elevación se reserva para la tarjeta que contiene el
   gráfico o la tabla, que es lo que de verdad está por encima del lienzo. */
.kpi {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r3); padding: var(--s3) var(--s4); min-width: 0;
}
.kpi .l {
  font-size: 12px; font-weight: 500; color: var(--text-2); margin: 0 0 var(--s1);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kpi .v {
  font-size: 22px; font-weight: 650; letter-spacing: -.028em; line-height: 1.15;
  font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis;
}
.kpi .d { font-size: 12px; margin-top: var(--s1); font-variant-numeric: tabular-nums; }
.kpi .d.up   { color: var(--success); }
.kpi .d.down { color: var(--error); }
.kpi .d.flat { color: var(--text-muted); }
.kpi .h { font-size: 11.5px; color: var(--text-muted); margin-top: var(--s1); line-height: 1.45; }
.kpi.ok    .v { color: var(--success); }
.kpi.warn  .v { color: var(--warning); }
.kpi.error .v { color: var(--error); }

/* ── Botones ───────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 7px var(--s3); border-radius: var(--r2);
  border: 1px solid var(--border); background: var(--surface); color: var(--text);
  font-family: inherit; font-size: 13px; font-weight: 550; line-height: 1.3;
  cursor: pointer; white-space: nowrap;
  transition: background var(--mo-fast), border-color var(--mo-fast), color var(--mo-fast);
}
.btn:hover { background: var(--surface-2); border-color: var(--border-strong); }
.btn:active { background: var(--surface-3); }
.btn.primary {
  background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600;
}
.btn.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn.danger {
  background: var(--error); border-color: var(--error); color: #fff; font-weight: 600;
}
.btn.danger:hover { background: color-mix(in srgb, var(--error) 88%, #000); }
.btn.ghost { background: transparent; }
.btn.ghost:hover { background: var(--surface-2); }
.btn.sm { padding: 4px var(--s2); font-size: 12.5px; }
.btn.block { width: 100%; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn svg { width: 14px; height: 14px; }

.iconbtn {
  background: none; border: 0; color: var(--text-muted); font-size: 17px; line-height: 1;
  cursor: pointer; padding: 2px 5px; margin-left: auto; border-radius: var(--r1);
  transition: color var(--mo-fast), background var(--mo-fast);
}
.iconbtn:hover { color: var(--text); background: var(--surface-2); }

/* ── Distintivos ───────────────────────────────────────────────────────────── */

/* Sin mayúsculas forzadas y en tipografía de texto: un estado es una palabra,
   no un código de sistema, y "ACTIVE" en monoespaciada es ruido de consola. */
.pill {
  display: inline-flex; align-items: center; gap: var(--s1);
  font-size: 11.5px; font-weight: 600; letter-spacing: .005em;
  padding: 2px 7px; border-radius: var(--r1); border: 1px solid;
  white-space: nowrap; line-height: 1.5;
}
.pill.mono { font-family: var(--mono); font-size: 11px; }
.p-ok    { color: var(--success); border-color: color-mix(in srgb, var(--success) 38%, transparent); background: var(--success-bg); }
.p-warn  { color: var(--warning); border-color: color-mix(in srgb, var(--warning) 38%, transparent); background: var(--warning-bg); }
.p-error { color: var(--error);   border-color: color-mix(in srgb, var(--error) 38%, transparent);   background: var(--error-bg); }
.p-info  { color: var(--info);    border-color: color-mix(in srgb, var(--info) 38%, transparent);    background: var(--info-bg); }
.p-muted { color: var(--text-2);  border-color: var(--border); background: var(--surface-2); }

.chip {
  display: inline-flex; align-items: center; gap: var(--s1);
  font-family: var(--mono); font-size: 11.5px; color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--border);
  padding: 1px 6px; border-radius: var(--r1); white-space: nowrap;
}

/* ── Formularios ───────────────────────────────────────────────────────────── */

.field { margin-bottom: var(--s3); }
.field.full { grid-column: 1 / -1; }
label {
  display: block; font-size: 12px; font-weight: 550; color: var(--text-2);
  margin-bottom: var(--s1); letter-spacing: 0;
}
input, select, textarea {
  width: 100%; padding: 7px 10px;
  border: 1px solid var(--border); border-radius: var(--r2);
  background: var(--surface); color: var(--text);
  font-family: var(--sans); font-size: 13px; line-height: 1.4;
  transition: border-color var(--mo-fast), box-shadow var(--mo-fast);
}
input.mono, textarea.mono, select.mono { font-family: var(--mono); font-size: 12.5px; }
textarea { min-height: 96px; line-height: 1.55; resize: vertical; }
input:hover, select:hover, textarea:hover { border-color: var(--border-strong); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: var(--ring);
}
input:disabled, select:disabled, textarea:disabled {
  background: var(--surface-2); color: var(--text-muted); cursor: not-allowed;
}
select { appearance: auto; }

.check { display: flex; align-items: flex-start; gap: var(--s2); }
.check input { width: auto; margin-top: 3px; }
.check label {
  font-size: 13px; font-weight: 500; color: var(--text); margin: 0;
}
.hint { font-size: 12px; color: var(--text-muted); margin: var(--s1) 0 0; line-height: 1.45; }
.hint code, .hint .mono { font-family: var(--mono); font-size: 11.5px; }

.uf-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 0 var(--s4); }
.uf-err {
  margin: var(--s3) 0 0; padding: var(--s3); border-radius: var(--r2); font-size: 13px;
  border: 1px solid color-mix(in srgb, var(--error) 32%, transparent);
  background: var(--error-bg); color: var(--text-2);
}
.uf-foot { display: flex; gap: var(--s2); align-items: center; margin-top: var(--s4); flex-wrap: wrap; }

/* Barra de filtros sobre una tabla: la misma altura y el mismo hueco en todas
   las vistas, para que doce pantallas parezcan un producto y no doce. */
.toolbar {
  display: flex; align-items: flex-end; gap: var(--s3); flex-wrap: wrap;
  padding: var(--s3) var(--s4); border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.toolbar .field { margin: 0; min-width: 160px; }
.toolbar .grow { flex: 1; min-width: 200px; }

/* ── Tablas ────────────────────────────────────────────────────────────────── */

.tw { overflow-x: auto; }
table.t { width: 100%; border-collapse: collapse; font-size: 13px; }
table.t caption {
  caption-side: top; text-align: left; font-size: 12px; color: var(--text-muted);
  padding: var(--s3) var(--s4) var(--s2);
}
table.t th {
  text-align: left; font-size: 12px; font-weight: 600; color: var(--text-2);
  padding: var(--s2) var(--s4); white-space: nowrap;
  background: var(--surface-2); border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 1;
}
table.t th.right { text-align: right; }
table.t td {
  padding: 7px var(--s4); border-bottom: 1px solid var(--border); vertical-align: middle;
}
table.t td.right { text-align: right; }
table.t td.mono { font-family: var(--mono); font-size: 12px; }
table.t tbody tr { transition: background var(--mo-fast); }
table.t tbody tr:hover { background: var(--surface-2); }
table.t tbody tr:last-child td { border-bottom: 0; }
table.t tbody tr.clickable { cursor: pointer; }
table.t tbody tr.clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* La fila vacía no se realza: no hay nada que señalar y el subrayado al pasar
   por encima haría creer que se puede pulsar. */
table.t tbody tr.is-empty:hover { background: transparent; }

th .sortbtn {
  display: inline-flex; align-items: center; gap: var(--s1);
  background: none; border: 0; padding: 0; font: inherit; color: inherit;
  cursor: pointer; transition: color var(--mo-fast);
}
th .sortbtn:hover { color: var(--text); }
th .arrow { font-size: 8px; opacity: .3; }
th[aria-sort] .arrow { opacity: 1; color: var(--accent); }
th[aria-sort] { color: var(--text); }

/* ── Paginación ────────────────────────────────────────────────────────────── */

.pager {
  display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
  padding: var(--s2) var(--s4); border-top: 1px solid var(--border);
  background: var(--surface-2); font-size: 12.5px; color: var(--text-2);
}
.pager .range { font-variant-numeric: tabular-nums; }
.pager .grow { flex: 1; }
.pager select { width: auto; padding: 3px var(--s2); font-size: 12.5px; }

/* ── Estados vacíos ────────────────────────────────────────────────────────── */

.empty { padding: var(--s7) var(--s5); text-align: center; }
.empty > svg {
  width: 28px; height: 28px; color: var(--text-muted); opacity: .7;
  margin: 0 auto var(--s3); display: block;
}
.empty .et { font-size: 13.5px; font-weight: 600; margin: 0 0 var(--s1); color: var(--text); }
.empty .eh { font-size: 12.5px; color: var(--text-2); margin: 0 auto; max-width: 62ch; line-height: 1.5; }
.empty .btn { margin-top: var(--s4); }

.skel {
  display: block; height: 11px; border-radius: var(--r1); background: var(--surface-2);
  animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }

/* ── Gráficos ──────────────────────────────────────────────────────────────── */

/* El hueco que se mide para dibujar el gráfico a su ancho real. Sin ancho
   declarado aquí, el observador de tamaño no tendría nada que observar. */
.chart-host { width: 100%; min-width: 0; }
.chart { width: 100%; height: auto; display: block; overflow: visible; }
.chart .ax-line { stroke: var(--border); stroke-width: 1; }
.chart .ax-base { stroke: var(--border-strong); stroke-width: 1; }
.chart .ax-text { fill: var(--text-muted); font-family: var(--mono); font-size: 10px; }
.chart .ax-text.mid { text-anchor: middle; }
.chart .ax-text.end { text-anchor: end; }
.chart .guide { stroke: var(--border-strong); stroke-width: 1; stroke-dasharray: 3 3; }
.chart .serie { fill: none; stroke-width: 1.75; stroke-linejoin: round; stroke-linecap: round; }
/* El área bajo la línea da volumen sin competir con ella: a más del 10 % de
   opacidad la serie deja de leerse y el gráfico se vuelve decorativo. */
.chart .area { stroke: none; fill-opacity: .08; }
.chart .dot { stroke: var(--surface); stroke-width: 2; }
.chart .marker { stroke: var(--surface); stroke-width: 1.5; }
.chart .bar { transition: opacity var(--mo-fast); }
.chart .bar:hover { opacity: .78; }
.chart .tip { pointer-events: none; }
.chart .tip-bg { fill: var(--surface); stroke: var(--border-strong); stroke-width: 1; }
.chart .tip-t { fill: var(--text); font-family: var(--mono); font-size: 10.5px; }
.chart .tip-t.mute { fill: var(--text-muted); }

/* Estado vacío del gráfico: antes se dibujaba una rejilla de 350 px sin una
   sola marca, que es lo primero que ve el operador y no comunica nada. */
.chart-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--s2); min-height: 148px; padding: var(--s6) var(--s5); text-align: center;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r3);
}
.chart-empty svg { width: 26px; height: 26px; color: var(--text-muted); opacity: .7; }
.chart-empty .et { font-size: 13px; font-weight: 600; margin: 0; color: var(--text); }
.chart-empty .eh { font-size: 12.5px; color: var(--text-2); margin: 0; max-width: 56ch; line-height: 1.5; }

.chart-legend {
  display: flex; gap: var(--s4); flex-wrap: wrap; margin-top: var(--s2);
  font-size: 12px; color: var(--text-2);
}
.chart-legend span.sw {
  display: inline-block; width: 10px; height: 3px; border-radius: 2px;
  vertical-align: middle; margin-right: 6px;
}

/* ── Avisos ────────────────────────────────────────────────────────────────── */

.toasts {
  position: fixed; top: var(--s3); right: var(--s3);
  display: flex; flex-direction: column; gap: var(--s2);
  z-index: 60; max-width: min(400px, calc(100vw - var(--s6)));
}
.toast {
  background: var(--surface); border: 1px solid var(--border); border-left-width: 3px;
  border-radius: var(--r3); box-shadow: var(--shadow-lg);
  padding: var(--s3); font-size: 13px; color: var(--text-2);
  display: flex; gap: var(--s2); align-items: flex-start;
}
.toast b { color: var(--text); font-weight: 600; }
.toast.ok    { border-left-color: var(--success); }
.toast.warn  { border-left-color: var(--warning); }
.toast.error { border-left-color: var(--error); }
.toast.info  { border-left-color: var(--accent); }
.toast .x {
  background: none; border: 0; color: var(--text-muted); cursor: pointer;
  font-size: 15px; line-height: 1; padding: 0; margin-left: auto;
}
.toast .x:hover { color: var(--text); }

.notice {
  border-radius: var(--r3); padding: var(--s3) var(--s4); font-size: 13px;
  color: var(--text-2); margin-bottom: var(--s4);
  border: 1px solid var(--border); background: var(--surface-2);
}
.notice b { color: var(--text); }
.notice.warn  { border-color: color-mix(in srgb, var(--warning) 32%, transparent); background: var(--warning-bg); }
.notice.error { border-color: color-mix(in srgb, var(--error) 32%, transparent);   background: var(--error-bg); }
.notice.info  { border-color: color-mix(in srgb, var(--info) 32%, transparent);    background: var(--info-bg); }

/* ── Capas: modal y cajón ──────────────────────────────────────────────────── */

/* La capa aparecía de golpe, y aparecer de golpe se lee como un fallo del
   navegador: era literalmente la queja —«se ve que hay error»—. Con un velo que
   entra en 140 ms y un panel que sube 8 px en 180 ms, el ojo entiende que algo
   se ha abierto encima y no que la pantalla ha parpadeado.

   Los tiempos son cortos a propósito: es un formulario que un operador abre
   veinte veces al día, y por encima de 200 ms una animación deja de informar y
   empieza a estorbar. El bloque de movimiento reducido del principio de la hoja
   ya las desactiva para quien las haya pedido desactivadas. */
@keyframes scrim-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-in {
  from { opacity: 0; transform: translateY(8px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
@keyframes drawer-in {
  from { opacity: 0; transform: translateX(28px); }
  to   { opacity: 1; transform: none; }
}

.scrim {
  position: fixed; inset: 0; background: rgba(3,20,47,.42);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  z-index: 40; display: grid; place-items: center; padding: var(--s5);
  animation: scrim-in .14s ease-out both;
}
.modal {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r5);
  /* Al relieve se le suma un filo de un píxel: sobre fondo oscuro el borde solo
     no separa el panel del velo, y el diálogo parecía flotar sin contorno. */
  box-shadow: var(--shadow-lg), 0 0 0 1px color-mix(in srgb, var(--border) 55%, transparent);
  width: 100%; max-width: 540px; max-height: 86vh;
  display: flex; flex-direction: column; overflow: hidden;
  animation: modal-in .18s cubic-bezier(.16, 1, .3, 1) both;
}
.modal .hd, .drawer .hd {
  padding: var(--s4) var(--s5); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: var(--s3);
}
.modal .hd h2, .drawer .hd h2 { font-size: 14px; }
.modal .bd {
  padding: var(--s5); overflow-y: auto; color: var(--text-2); font-size: 13px;
}
.modal .bd .subject { color: var(--text); font-weight: 600; }
/* El pie se asienta sobre el tono secundario: separa la zona de decisión del
   contenido sin necesidad de una segunda línea divisoria. */
.modal .ft {
  padding: var(--s4) var(--s5); border-top: 1px solid var(--border);
  background: var(--surface-2);
  display: flex; gap: var(--s3); justify-content: flex-end; flex-wrap: wrap;
}

/* `right` aquí significa «pegado al borde derecho», pero el mismo nombre existe
   como utilidad de texto —`.right { text-align: right; }`— y esa declaración se
   heredaba a todo el cajón: etiquetas, ayudas y párrafos salían alineados a la
   derecha. Se devuelve la alineación al valor natural del documento; el nombre
   de la clase se deja como está para no tocar el marcado de todas las vistas. */
.scrim.right { place-items: stretch; justify-content: flex-end; padding: 0; text-align: initial; }
.drawer {
  background: var(--surface); border-left: 1px solid var(--border);
  width: min(620px, 100vw); height: 100vh; display: flex; flex-direction: column;
  box-shadow: var(--shadow-lg);
  animation: drawer-in .2s cubic-bezier(.16, 1, .3, 1) both;
}
.drawer .bd { padding: var(--s5); overflow-y: auto; flex: 1; }

/* ── Lista de comprobaciones ───────────────────────────────────────────────── */

.checks { display: flex; flex-direction: column; }
.chk {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--s3);
  padding: var(--s3) var(--s4); border-bottom: 1px solid var(--border); align-items: start;
  transition: background var(--mo-fast);
}
.chk:hover { background: var(--surface-2); }
.chk:last-child { border-bottom: 0; }
.chk .ct { font-size: 13px; font-weight: 600; margin: 0; }
.chk .cd { font-size: 12.5px; color: var(--text-2); margin: 2px 0 0; }
.chk details { margin-top: var(--s2); }
.chk summary { font-size: 12px; color: var(--accent); cursor: pointer; }
.chk pre {
  font-family: var(--mono); font-size: 11.5px; color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r2);
  padding: var(--s2) var(--s3); margin: var(--s2) 0 0;
  white-space: pre-wrap; word-break: break-word; overflow-x: auto;
}

/* ── Definiciones clave/valor ──────────────────────────────────────────────── */

.kv {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--s3) var(--s5); margin: 0;
}
.kv div { min-width: 0; }
.kv dt { font-size: 12px; font-weight: 500; color: var(--text-2); }
.kv dd { margin: 2px 0 0; font-size: 13px; word-break: break-word; }
.kv dd .mono { font-family: var(--mono); font-size: 12.5px; }

/* ── Medidor (cuota, ocupación) ────────────────────────────────────────────── */

.meter {
  height: 6px; border-radius: 3px; background: var(--surface-3);
  overflow: hidden; margin-top: var(--s1);
}
.meter > i { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
.meter.warn  > i { background: var(--warning); }
.meter.error > i { background: var(--error); }

/* ══════════════════════════════════════════════════════════════════════════════
   PUERTA DE ACCESO · las cinco capas del manual

   La lámina era una superficie sólida sobre un fondo sólido, y por eso se leía
   plana: el manual describe el canvas por capas —casi negro, rejilla ámbar al
   3 %, un blob que respira, vidrio, ruido al 1,5 %— y advierte que el vidrio
   sobre oscuro plano se ve muerto. Faltaba el blob, así que faltaba todo.

   El tratamiento es distinto en claro y en oscuro, y no por gusto: el vidrio es
   blanco sobre blanco cuando el fondo ya es claro, de modo que ahí el mismo
   papel lo hace un halo tenue y una sombra bien puesta. La marca vive en el
   canvas oscuro; en claro se comporta.
   ══════════════════════════════════════════════════════════════════════════════ */

.gate { position: fixed; isolation: isolate; }

/* Capa 2 · rejilla de 60 px, enmascarada hacia el centro para que no empape los
   bordes de la pantalla. */
.gate::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    linear-gradient(rgba(245,158,11,.05) 1px, transparent 1px) 0 0 / 100% 60px,
    linear-gradient(90deg, rgba(245,158,11,.05) 1px, transparent 1px) 0 0 / 60px 100%;
  mask-image: radial-gradient(90% 70% at 50% 0%, #000 0%, #000 45%, transparent 100%);
}

/* Capa 3 · el blob. Respira en 9 s, que es el vocabulario de movimiento de la
   marca: lento, ambiental, deliberado. */
.gate::after {
  content: ""; position: absolute; z-index: 0; pointer-events: none;
  width: 70vw; height: 70vw; min-width: 560px; min-height: 560px;
  top: -30vw; left: -12vw;
  background: radial-gradient(circle at 50% 50%,
    rgba(245,158,11,.16) 0%, rgba(245,158,11,.06) 40%, transparent 70%);
  filter: blur(46px);
}
:root[data-theme="light"] .gate::after {
  background: radial-gradient(circle at 50% 50%,
    rgba(245,158,11,.14) 0%, rgba(245,158,11,.05) 42%, transparent 72%);
}

.gate-shell, .gate-bar, .gate-card { position: relative; z-index: 1; }

/* Capa 4 · vidrio. Fondo blanco al 3 %, desenfoque de 20 px, borde al 6 %: las
   cifras del manual, no una aproximación. */
:root[data-theme="dark"] .gate-shell {
  background: rgba(255,255,255,.03);
  backdrop-filter: blur(20px);
  border-color: rgba(255,255,255,.06);
  box-shadow: 0 40px 80px -40px rgba(0,0,0,.9);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gate-shell {
    background: rgba(255,255,255,.03);
    backdrop-filter: blur(20px);
    border-color: rgba(255,255,255,.06);
    box-shadow: 0 40px 80px -40px rgba(0,0,0,.9);
  }
}

/* La tarjeta del formulario es la superficie ACTIVA de la pantalla: es donde se
   escribe. Lleva el filete superior en degradado, que es firma de marca. */
.gate-card::before {
  content: ""; position: absolute; top: -1px; left: 22px; right: 22px; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(245,158,11,.6), transparent);
}
:root[data-theme="dark"] .gate-card {
  background: rgba(255,255,255,.05);
  backdrop-filter: blur(12px);
  border-color: rgba(255,255,255,.08);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gate-card {
    background: rgba(255,255,255,.05);
    backdrop-filter: blur(12px);
    border-color: rgba(255,255,255,.08);
  }
}

/* El titular de la tarjeta a la escala de la marca: Inter 700 con tracking
   cerrado. A 1,5 rem competía con la reclamación de la izquierda en vez de
   mandar sobre su propia mitad. */
.gate-card h1 { font-size: 1.7rem; letter-spacing: -.03em; }

/* La reclamación de marca, a la escala de sección del manual. */
.gate-claim { letter-spacing: -.028em; }

/* Capa 5 · ruido. Sin él, el degradado del blob se bandea en pantallas de 8 bits
   y se ven aros concéntricos donde debería haber una transición limpia. */
.gate-noise {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  opacity: .015;
}
:root[data-theme="light"] .gate-noise { opacity: .01; }

@media (prefers-reduced-motion: no-preference) {
  .gate::after { animation: gate-breathe 9s ease-in-out infinite; }
  @keyframes gate-breathe {
    0%, 100% { transform: scale(1); opacity: .85; }
    50%      { transform: scale(1.09) translate(2%, -2%); opacity: 1; }
  }
  /* Entrada de la lámina: una sola, deliberada, con salida exponencial. */
  .gate-shell { animation: gate-in .8s cubic-bezier(.16,1,.3,1) both; }
  @keyframes gate-in {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: none; }
  }
}

/* ── Lockup de la puerta ─────────────────────────────────────────────────────
   Sustituye al PNG. Un raster de 640×207 servido a 184 px dejaba el descriptor
   incrustado en seis píxeles de altura: el manual lo prohíbe expresamente —por
   debajo del umbral se cambia de variante, nunca se escala la pieza— y en
   pantalla se leía como una mancha. Compuesto, cada parte tiene su tamaño y su
   peso, y es nítido en cualquier densidad. */
.gate-logo {
  flex: none; width: auto; aspect-ratio: auto;
  background: none;
  display: flex; align-items: center; gap: 13px;
}
.gate-mark { width: 40px; flex: none; color: var(--text); }
.gate-mark svg { display: block; width: 100%; height: auto; }
.gate-word { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.gate-word b {
  font-size: 1.55rem; font-weight: 700; letter-spacing: -.03em;
  line-height: 1; color: var(--text);
}
/* Mono en el descriptor: es una etiqueta, que es uno de los tres trabajos que
   el manual le reserva. */
.gate-word i {
  font-family: var(--mono); font-style: normal;
  font-size: .625rem; font-weight: 500; letter-spacing: .15em;
  text-transform: uppercase; color: var(--text-muted);
}
:root[data-theme="dark"] .gate-logo { background-image: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gate-logo { background-image: none; }
}

/* El filete superior de la tarjeta se leía como un borde más. Se le da cuerpo
   y se le acorta el recorrido para que sea lo que es: una firma, no un marco. */
.gate-card::before {
  top: -1px; left: 30%; right: 30%; height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  opacity: .85;
}

/* La lámina no cabía en pantallas bajas y se comía el pie. Con el alto mínimo
   liberado, el contenedor desplaza en lugar de recortar: una pantalla de acceso
   que esconde el aviso legal por debajo del borde es una pantalla incompleta. */
.gate { place-items: start center; padding-block: var(--s6); }
.gate-shell { margin-block: auto; }


/* ══════════════════════════════════════════════════════════════════════════════
   LA PUERTA, A SANGRE
   ══════════════════════════════════════════════════════════════════════════════
   Era una tarjeta con vidrio flotando en el centro de un rectángulo: la forma
   por defecto de un formulario de acceso, y se leía como tal — un producto
   metido dentro de otra pantalla. La consola resolvió esto hace tiempo y su
   criterio vale igual aquí, porque es el mismo manual y la misma marca: el
   canvas ocupa el viewport, la mitad de marca sangra por el borde izquierdo y
   el formulario se apoya directamente sobre las capas, sin contenedor que lo
   envuelva.

   ASIMÉTRICO Y NO PARTIDO POR LA MITAD. Un 50/50 es la retícula por defecto y
   se lee como tal. El peso cae del lado de la marca, que es lo que esta
   pantalla tiene que decir primero: quien llega aquí ya sabe escribir una
   contraseña.

   LAS CAPAS DEL MANUAL SIGUEN AHÍ y no se duplican: canvas casi negro, rejilla
   al 3 %, blob que respira y ruido — ya declaradas más arriba sobre .gate. Lo
   que este bloque hace es quitar el contenedor de en medio.
   ══════════════════════════════════════════════════════════════════════════════ */

.gate {
  padding: 0;
  place-items: stretch;
}

/* Desmontaje de la lámina. Se repiten los selectores por tema porque igualan
   especificidad con los originales; al ir después en el archivo, ganan. */
:root[data-theme="dark"] .gate-shell,
:root:not([data-theme="light"]) .gate-shell,
:root[data-theme="light"] .gate-shell,
.gate-shell {
  width: 100%; max-width: none; min-height: 100%;
  margin: 0; padding: 0;
  border: 0; border-radius: 0; box-shadow: none;
  background: none; backdrop-filter: none;
  display: flex; flex-direction: column;
  overflow: visible;
}

.gate-split {
  position: relative;
  flex: 1 1 auto; min-height: 0;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
}

/* ── Mitad de marca ───────────────────────────────────────────────────────── */

.gate-aside {
  padding: clamp(2rem, 4.4vw, 4.75rem);
  display: flex; flex-direction: column; gap: clamp(1.2rem, 2.2vw, 2rem);
  position: relative; overflow: hidden;
  border-right: 1px solid rgba(255,255,255,.06);
  background: none;
}
/* La ilustración de la marca, la MISMA que usa la consola. El enclave suelto que
   había aquí era un SVG pequeño dentro de una caja grande: por mucho que se
   estirara seguía leyéndose como una figura flotando en un hueco, y su contorno
   cruzaba la línea de texto de una de las garantías. Esta va de fondo, recortada
   por el panel, y es la pieza que la marca ya tiene resuelta.

   El encuadre al 88 % horizontal no es capricho: el cubo vive en el tercio
   derecho del archivo, y con cover sobre un panel más alto que ancho, centrarlo
   lo dejaría fuera del recorte. El filtro le quita el azul —el color del que
   esta marca huye— sin apagar el ámbar del cubo, que es lo único que conservar.

   La imagen ya está en el disco y la sirve la misma máquina: no añade petición a
   ningún tercero, que en una pantalla de acceso al plano de control importa. */
.gate-aside::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: url("/assets/gate-bg.webp") 88% 40% / cover no-repeat;
  filter: saturate(.44) sepia(.44) brightness(.9) contrast(1.06);
}

/* Velo de legibilidad, y hace falta. El archivo trae un resplandor ámbar claro
   arriba a la izquierda, justo donde caen el logotipo y el titular; sin velo,
   «Sovereign» se leería sobre su propio color de acento. Opaco donde hay texto,
   casi transparente sobre el cubo. Las manchas de ámbar que pedía el manual se
   suman en esta misma capa: una capa menos que mantener sincronizada. */
.gate-aside::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background:
    linear-gradient(to top,
      rgba(3,7,18,.94) 0%, rgba(3,7,18,.76) 15%,
      rgba(3,7,18,.32) 27%, transparent 40%),
    radial-gradient(34rem 24rem at 74% 44%, rgba(245,158,11,.20), transparent 66%),
    linear-gradient(107deg,
      rgba(3,7,18,.95) 0%, rgba(3,7,18,.86) 30%,
      rgba(3,7,18,.52) 56%, rgba(3,7,18,.24) 78%);
}
.gate-aside > * { position: relative; z-index: 1; }

.gate-claim {
  max-width: 13ch;
  font-size: clamp(2.2rem, 4.2vw, 3.6rem);
  line-height: 1.04; letter-spacing: -.038em;
  text-align: left; text-wrap: balance;
}
.gate-sell { max-width: 44ch; font-size: clamp(.95rem, 1.05vw, 1.02rem); text-align: left; }

/* El enclave suelto se retira: su trabajo lo hace ahora el fondo del panel. */
.gate-art { display: none; }

/* Los puntos quedan abajo por su cuenta: al sacar la ilustración del flujo se
   perdió el elemento elástico que los empujaba. */
.gate-points { margin-top: auto; }
.gate-points li { text-align: left; }

/* ── Mitad del formulario ─────────────────────────────────────────────────── */

.gate-main {
  position: relative;
  display: flex; flex-direction: column;
  padding: clamp(2rem, 4.4vw, 4.75rem);
  /* El blob que exige el manual, detrás de donde se escribe: el vidrio sobre
     oscuro plano se ve muerto, y aquí ya no hay vidrio que lo disimule. */
  background:
    radial-gradient(44rem 32rem at 58% 44%, oklch(78% .155 70 / .07), transparent 68%),
    radial-gradient(28rem 28rem at 92% 88%, oklch(62% .13 55 / .05), transparent 70%);
}

.gate-bar { display: flex; align-items: center; margin-bottom: auto; }
.gate-bar #gateLangSlot { margin-left: auto; }

/* Sin tarjeta: el formulario se apoya sobre las capas. */
:root[data-theme="dark"] .gate-card,
:root:not([data-theme="light"]) .gate-card,
:root[data-theme="light"] .gate-card,
.gate-card {
  width: 100%; max-width: 25.5rem;
  margin: auto 0; padding: 0;
  background: none; border: 0; border-radius: 0;
  box-shadow: none; backdrop-filter: none;
}
/* El filete superior en degradado es firma de marca sobre una SUPERFICIE. Sin
   superficie no hay dónde ponerlo, y dejarlo flotando sería un adorno. */
.gate-card::before { display: none; }

/* Todo el formulario se alinea a la izquierda, como la mitad de marca y como la
   consola. Estaba centrado porque vivía dentro de una tarjeta estrecha, donde el
   centrado se sostiene; sobre el fondo abierto, un titular centrado encima de
   unas etiquetas alineadas a la izquierda deja el eje de lectura roto. */
.gate-card h1 {
  font-size: clamp(1.7rem, 2.3vw, 2.1rem); letter-spacing: -.03em;
  text-align: left;
}
.gate-sub { text-align: left; max-width: 40ch; }
.gate-foot { text-align: left; max-width: 34ch; }
.gate-badge { margin: 0; }

/* En pantalla estrecha se apila y la mitad de marca se recorta a lo esencial:
   el logotipo y la reclamación. La ilustración y las garantías se van porque
   entre ellas y el formulario, en un móvil, gana el formulario. */
@media (max-width: 900px) {
  .gate-split { grid-template-columns: 1fr; }
  .gate-aside {
    border-right: 0; border-bottom: 1px solid rgba(255,255,255,.06);
    padding: var(--s6) var(--s5); gap: var(--s3);
  }
  .gate-art, .gate-points { display: none; }
  .gate-claim { font-size: clamp(1.9rem, 7vw, 2.4rem); max-width: none; }
  .gate-main { padding: var(--s6) var(--s5); }
  .gate-card { max-width: none; margin: 0; }
}
