/* ============================================================================
   SERPIENTE DE ORO · Hoja de estilos principal

   Contiene la ARQUITECTURA: tokens, armazón, acceso, transición, componentes
   y responsive. El CSS del dominio (conversión de archivos) va al final.

   Reglas heredadas del kit base — ver 00-docs/arquitectura-base.md:
     13.2 · TODO el CSS vive aquí. Nada se inyecta desde JS.
     13.1 · prefijos por módulo: sh- (shell) · lg- · tr- · mk- (marca) ·
            cs- (isotipo del cliente) · gp- (firma de GEN+) ·
            lst- · mdl- · cv- (convertir) · mo- (componentes compartidos)
     13.3 · los colores críticos se anclan al componente, no a la página.

   El prefijo --mo-* y los objetos MO_* se conservan del kit a propósito: la
   arquitectura pide sustituir los VALORES de marca y conservar los NOMBRES,
   para que 05-core/ siga copiándose tal cual a la siguiente plataforma.
   ==========================================================================*/

/* ---------------------------------------------------------------------------
   1. TOKENS

   La paleta NO se inventó: se midió sobre las dos referencias que fija el
   cliente —genplusdesign.com y aecode.ai— y se tomó lo que ambas hacen igual.
   Extraído de sus hojas de estilo reales, no a ojo:

     concepto        GEN+                 AECODE               aquí
     ───────────────────────────────────────────────────────────────────
     tinta           #040f20 #06142a      #0e1121 #0c0f29      #0a1020
     primario        #2165ff #1854e8      #4465ee #6756e3      #2f57e6
     gris frío       #8e9aad #b3bec8      #a2b4cb #8c97dc      #98a7bc
     texto 2º        #5b6c87              #3a4065              #55637d
     línea           #e2e6ee #d0d8f0      #eef3f8              #e2e8f1
     lienzo          #f6f8fc #f5f7ff      #eef3f8 #edebf9      #f4f7fb
     acento verde    #6dcdbb              #65d78e #95e3b1      #0f7a5a

   Las dos coinciden en lo esencial: un casi-negro con matiz azul marino
   (ninguna usa negro puro), un azul saturado como primario, neutros grises
   fríos y un blanco con velo azul. La diferencia —GEN+ tira a azul puro,
   AECODE a índigo— se resuelve en el punto medio.

   Los valores de contraste anotados están MEDIDOS con 03-tools/contraste.js,
   no estimados. Mínimos: 4.5:1 en texto, 3:1 en el borde de un control.
   -------------------------------------------------------------------------*/
:root{
  /* --- MARCA · lo único que cambia por cliente -------------------------- */
  --mo-ink:        #0a1020;   /* tinta de titulares — 18.96:1 sobre blanco */
  --mo-steel:      #2f57e6;   /* PRIMARIO — foco, barras, iconos, bordes */
  --mo-steel-d:    #2145c8;   /* primario oscuro — 7.64:1 sobre blanco */
  --mo-steel-xd:   #16307f;
  --mo-steel-l:    #e9edfd;   /* primario tenue — fondos de selección */
  --mo-marino:     #0e2a6b;   /* MARINO PROFUNDO — el azul oscuro de GEN+ */
  --mo-marino-2:   #040f20;   /* el más oscuro de las dos webs */
  --mo-slate:      var(--mo-marino);   /* avatar */
  --mo-slate-2:    #1b3a80;
  --mo-sand:       #dde5f0;   /* separadores y bordes de panel */
  --mo-sand-2:     #c6d2e4;
  --mo-paper:      #eef3f8;   /* lienzo del área de trabajo — literal AECODE */
  --mo-paper-2:    #f7f9fc;
  --mo-line:       #848c9e;   /* BORDE DE CONTROL — 3.37:1 sobre blanco */
  --mo-line-2:     #eef2f7;   /* línea muy tenue: separador de filas */
  --mo-mute:       #98a7bc;   /* gris frío decorativo */
  --mo-mute-2:     #55637d;   /* gris de texto — 6.06:1 sobre blanco */
  --mo-menta:      #0f7a5a;   /* acento puntual — el verde de ambas webs */

  /* --- SUPERFICIES ------------------------------------------------------ */
  --sf-app:        var(--mo-paper);
  --sf-card:       #ffffff;
  --sf-side:       #ffffff;
  --sf-side-2:     var(--mo-paper);

  /* --- ACCIÓN ------------------------------------------------------------
     Superficie sólida de TODA acción del producto: los botones de la
     plataforma y el «Entrar» del acceso. Un único valor — dos negros
     distintos en el mismo producto se notan aunque no se sepa por qué.

     No es negro puro: #000 sobre blanco da 19.3:1, un contraste durísimo que
     se percibe barato. Este carbón azulado queda en 17.87:1 y lleva el matiz
     marino que comparten las dos referencias.

     Se guarda además como `--claro-*`: un ancla que el tema oscuro NO toca.
     La plataforma se invierte con el tema, pero el acceso y la transición van
     siempre en claro y necesitan estos valores tal cual. Un solo literal para
     los dos sitios, de modo que no puedan desincronizarse (§6.3).          */
  --claro-fuerte:   #2a4fd8;   /* 6.55:1 con blanco */
  --claro-fuerte-2: #1f3cae;   /* hover: OSCURECE — 9.07:1 */
  --claro-sobre:    #ffffff;
  --claro-azul-d:   #2145c8;   /* ancla del primario: lo usa el acceso */
  --claro-marca-ic: #2145c8;   /* ancla del isotipo */

  /* Degradado de la acción. Las dos referencias lo usan en sus botones
     —GEN+ va de #2165ff a #4d84ff, AECODE de #6756e3 a #9655ea—, y es lo que
     más distingue su lenguaje del de un botón plano. Se mide contra la parada
     MÁS CLARA, que es el peor caso: blanco sobre #3b62ea da 5.10:1.
     Va aparte de --sf-fuerte, que sigue siendo un color sólido: un degradado
     no vale como `border-color` ni dentro de `color-mix()`. */
  --claro-grad:    linear-gradient(180deg, #3b62ea 0%, #2447c9 100%);
  --claro-grad-2:  linear-gradient(180deg, #2a4fd8 0%, #1c37a2 100%);
  --grad-accion:   var(--claro-grad);
  --grad-accion-2: var(--claro-grad-2);

  --sf-fuerte:     var(--claro-fuerte);
  --sf-fuerte-2:   var(--claro-fuerte-2);
  --tx-fuerte:     var(--claro-sobre);
  /* Borde de la superficie de acción. En claro es del color del propio fondo
     —no se ve en reposo y aparece al aclararse en hover—. En oscuro el botón
     deja de ser una superficie invertida y pasa a ser un gris de la escala,
     así que necesita contorno propio o deja de leerse como control (§6.4). */
  --bd-fuerte:     var(--claro-fuerte);

  /* Acento con texto encima. El primario a secas (#2f57e6) da 5.42:1 con
     blanco y cumple; se usa igualmente su variante oscura como fondo de
     texto, y el claro se reserva para bordes, iconos y barras. */
  --sf-acento:     #2145c8;   /* 7.64:1 con blanco */
  --tx-acento:     #ffffff;

  /* --- TINTA ------------------------------------------------------------ */
  --tx-1:          var(--mo-ink);
  --tx-2:          var(--mo-mute-2);
  --tx-3:          #626e7d;   /* 5.19:1 sobre blanco · 4.65:1 sobre lienzo */
  --tx-side:       var(--mo-mute-2);
  --tx-side-on:    var(--mo-ink);

  /* --- ESTADO · reservados ----------------------------------------------
     Nunca se reutilizan como color de serie ni decorativo, y siempre van
     acompañados de etiqueta de texto (nunca color solo).                  */
  --st-ok-fg:      #0f6b48;  --st-ok-bg:  #e3f3ea;  --st-ok-bd:  #bfdfd0;
  --st-warn-fg:    #8a5a06;  --st-warn-bg:#fbf1df;  --st-warn-bd:#f0dfbe;
  --claro-crit-bg: #fdeae8;  --claro-crit-bd:#f7d2ce;   /* ancla: acceso */
  --st-crit-fg:    #b3261e;  --st-crit-bg:var(--claro-crit-bg);
                             --st-crit-bd:var(--claro-crit-bd);
  --st-neut-fg:    #55637d;  --st-neut-bg:#eef1f6;  --st-neut-bd:#dee4ed;
  --st-info-fg:    #2145c8;  --st-info-bg:#e9edfd;  --st-info-bd:#d3ddfa;

  /* --- FORMA -------------------------------------------------------------
     Radios en la escala de 8 px que usa GEN+ (18 de sus 25 declaraciones de
     border-radius son 8px; el resto, píldoras y círculos).                */
  --r-sm: 5px;  --r-md: 8px;  --r-lg: 12px;
  --side-w: 232px;
  --side-w-min: 68px;
  --side-pad: 18px;
  /* SEPARACIÓN · regla del sistema, no un ajuste suelto. Ningún panel toca
     un borde de la ventana, y entre dos paneles siempre hay aire. Este valor
     gobierna las dos cosas, así que la distancia es siempre la misma.     */
  --hueco: 11px;
  --hueco-sup: 8px;
  --top-h: 58px;

  /* --- TIPOS DE CAMPO DEL EDITOR DE MAPAS -------------------------------
     Paleta CATEGÓRICA, no de estado. Los tokens --st-* están reservados y no
     se reutilizan como serie: en deuteranopía el rojo y el ámbar de estado
     quedan indistinguibles, y además dejarían de avisar.

     El color aquí es una pista SECUNDARIA: cada campo dibujado lleva su
     nombre encima y el panel dice el tipo con todas las letras. Quien no
     distingue colores trabaja igual. */
  --mp-texto:   #4d84ff;
  --mp-multi:   #17a2b8;
  --mp-numero:  #c47f16;
  --mp-radio:   #8b5cf6;
  --mp-casilla: #14926a;
  --mp-firma:   #d6467f;

  --sh-1: 0 1px 2px rgba(10,16,32,.05);
  --sh-2: 0 2px 10px rgba(10,16,32,.08);
  --sh-3: 0 18px 60px rgba(10,16,32,.22);
  /* Tarjeta: dos capas, como la cajetilla del acceso. La cercana da
     contacto; la amplia, separación del fondo. */
  --sh-card: 0 1px 2px rgba(10,16,32,.05), 0 12px 34px rgba(10,16,32,.07);

  --tema-transicion: background-color .2s ease, border-color .2s ease, color .2s ease;
}

/* ---------------------------------------------------------------------------
   1 bis. TEMA OSCURO

   No es el claro invertido: en oscuro mandan otras reglas (§6.2). Se destilan
   midiendo Notion y WhatsApp y quedándose con lo que AMBAS hacen igual:

   1. ESCALÓN CORTO ABAJO, LARGO ARRIBA. Lienzo y panel se separan apenas; lo
      elevado —hover, fila activa— salta el doble o el triple. Medido en
      luminancia x1000:
         Notion    #191919 -> #202020 -> #2c2c2c   pasos  4.7 y 10.7
         WhatsApp  #0b141a -> #111b21 -> #202c33   pasos  3.7 y 13.3
         aquí      #15171c -> #1c1f26 -> #282c36   pasos  5.1 y 11.5
      Repartir por igual deja el hover indistinguible del panel, que es justo
      donde hace falta saber qué está señalado.

   2. NI BLANCO PURO NI NEGRO PURO. El texto principal es un blanco roto: el
      nuestro está al 83 % del blanco, dentro del 66–84 % de las referencias.

   3. LA JERARQUÍA LA DA EL FONDO, NO LA SOMBRA. En oscuro la sombra no se ve
      contra el fondo: se anula casi por completo y se separa por color. La
      excepción es el modal, que sí necesita despegarse.

   4. LOS SEPARADORES SE INSINÚAN. Excepto el borde que DELIMITA un control,
      que necesita 3:1 contra el panel adyacente (WCAG 1.4.11).

   5. EL COLOR CON SIGNIFICADO VA DESATURADO Y OSCURO DE FONDO, con la tinta
      encima. Nunca el color saturado como relleno.

   6. NO HAY BOTONES DE FONDO CLARO. La acción es un escalón más de la misma
      escala de grises y su hover SUBE. Un bloque blanco sobre pantalla oscura
      pesa como un foco.

   ⚠️ ESTE NO ES EL TEMA POR DEFECTO. Se entra en CLARO —§6.1: el claro es el
   modo de trabajo de una plataforma de obra, que se consulta a pleno sol y se
   imprime— y el oscuro queda en el conmutador de la barra superior, para
   quien trabaje de noche. Las tres pantallas arrancan en claro, así que ya no
   hay cambio de idioma al terminar la bienvenida.

   Matiz: NO es gris neutro. Es EL MARINO DE LA MARCA (#040f20 -> #0e2a6b) con
   el mismo degradado azul en los botones. Un gris neutro dejaba la plataforma
   sin el color que la identifica —fue la primera versión, y se leía como
   cualquier panel de administración—, y una segunda paleta distinta de la del
   acceso obligaba a cambiar de idioma a mitad del recorrido.
   -------------------------------------------------------------------------*/
:root[data-tema="oscuro"]{
  /* SUPERFICIES · escalón corto abajo, largo arriba (regla 1).
     ES LA MISMA FAMILIA DEL ACCESO: el marino de GEN+ (#040f20 -> #0e2a6b).
     Así la plataforma continúa la pantalla por la que se acaba de entrar en
     vez de cambiar de idioma a mitad de camino.
       lienzo #040f20 -> panel #0a1a38 -> elevado #14315f
       pasos de luminancia x1000:  6.2 y 20.8  (3.35x)
       (Notion 4.7 y 10.7 = 2.3x · WhatsApp 3.7 y 13.3 = 3.6x) */
  --sf-app:        #040f20;   /* lienzo — el pie del degradado del acceso */
  --sf-card:       #0a1a38;   /* panel y tarjeta — apenas por encima */
  --sf-side:       #0a1a38;
  --sf-side-2:     #14315f;   /* elevado: hover, fila activa — salto largo */

  /* ACCIÓN · EL MISMO DEGRADADO AZUL DEL BOTÓN «ENTRAR».
     No se apaga a relleno plano: es la pieza que da identidad y la que se
     reconoce de la pantalla anterior. Sobre el marino no deslumbra —es azul
     sobre azul, no un bloque claro sobre gris— así que la regla 6 se cumple
     igual. Mismos literales que en claro, de modo que el botón de entrar y
     los de dentro no pueden desincronizarse. */
  --sf-fuerte:     #2f57e6;   /* sólido: bordes y color-mix — 5.79:1 */
  --sf-fuerte-2:   #4569ec;   /* hover: SUBE — 4.68:1 */
  --tx-fuerte:     #ffffff;
  --bd-fuerte:     #5b729f;   /* 3.57:1 contra el panel */
  --grad-accion:   var(--claro-grad);     /* #3b62ea -> #2447c9 */
  --grad-accion-2: linear-gradient(180deg, #4569ec 0%, #2c50d4 100%);
  /* El acento se aclara, así que la tinta encima pasa a ser oscura */
  --sf-acento:     #7ba5ff;   /* 7.12:1 con la tinta oscura */
  --tx-acento:     #040f20;

  /* TINTA · blanco roto con velo azul, nunca blanco puro (regla 2) */
  --tx-1:          #e6ecf7;   /* 14.54:1 sobre el panel */
  --tx-2:          #a2b4cb;   /* 8.15:1 — el mismo del pie del acceso */
  --tx-3:          #8ea0bb;   /* 6.48:1 */
  --tx-side:       #a2b4cb;
  --tx-side-on:    #e6ecf7;

  /* LÍNEAS · insinuadas, salvo las que delimitan un control (regla 4) */
  --mo-ink:        #e6ecf7;   /* el «máximo contraste» se invierte */
  --mo-sand:       #1b2f52;   /* separadores y bordes de panel */
  --mo-sand-2:     #27406b;
  --mo-line:       #5b729f;   /* 3.57:1 — borde de campo */
  --mo-line-2:     #142744;
  --mo-paper:      #14315f;   /* hover: el escalón largo */
  --mo-paper-2:    #071630;
  --mo-mute:       #8ea0bb;

  /* PRIMARIO · el azul claro del isotipo del acceso (#4d84ff de GEN+),
     aclarado lo justo para cumplir sobre el panel. */
  --mo-steel:      #7ba5ff;
  --mo-steel-d:    #9cbcff;
  --mo-steel-xd:   #c2d5ff;
  --mo-steel-l:    #102a5c;   /* fondo tenue de selección */
  --mo-marino:     #0e2a6b;
  --mo-marino-2:   #040f20;
  --mo-slate:      #2447c9;   /* avatar */
  --mo-slate-2:    #3b62ea;
  --mo-menta:      #6dcdbb;   /* el verde azulado de GEN+ */

  /* ESTADOS · fondo desaturado y oscuro, tinta encima (regla 5) */
  --st-ok-fg:      #6dcdbb;  --st-ok-bg:  #0d3330;  --st-ok-bd:  #174a45;
  --st-warn-fg:    #e0b878;  --st-warn-bg:#372c12;  --st-warn-bd:#514224;
  --st-crit-fg:    #f08b86;  --st-crit-bg:#3b1f24;  --st-crit-bd:#562f36;
  --st-neut-fg:    #a2b4cb;  --st-neut-bg:#18294a;  --st-neut-bd:#27406b;
  --st-info-fg:    #7ba5ff;  --st-info-bg:#102a5c;  --st-info-bd:#1b3f7d;

  /* Sombras casi anuladas (regla 3): contra un fondo oscuro no se ven y
     mantenerlas solo ensucia el borde. La tarjeta se levanta por su color. */
  --sh-1: 0 1px 2px rgba(0,0,0,.28);
  --sh-2: 0 2px 8px rgba(0,0,0,.34);
  --sh-3: 0 16px 48px rgba(0,0,0,.5);   /* el modal sí necesita despegarse */
  --sh-card: 0 1px 2px rgba(0,0,0,.2);

  /* El acceso y la transición NO llevan tema: van siempre en claro. Sus
     variables --lg-* no se redefinen aquí a propósito. Ver el bloque
     `.lg-pantalla, .tr-pantalla` más abajo. */

  color-scheme: dark;         /* barras de scroll y controles del sistema */
}

/* ---------------------------------------------------------------------------
   1 ter. MARCA  (prefijo mk-)

   EL LOGOTIPO ES EL ARCHIVO DEL CLIENTE, no un dibujo nuestro. Antes se
   reconstruía en SVG —isotipo y nombre— porque no había original; ahora lo
   hay y se usa tal cual. Solo se le recortó el margen en blanco sobrante y se
   redujo de 2171 px a 654: ni un color, ni una proporción, ni un trazo se han
   tocado (5.4491 de razón original frente a 5.4500 de la copia).

   Vive en 04-cliente/img/, no en 02-fuentes/: lo segundo es material del
   cliente que NO se publica, y el navegador necesita poder pedirlo.

   ⚠️  VA SOBRE UNA PLACA BLANCA, siempre. El archivo trae fondo blanco, así
   que sobre el marino del acceso o sobre el tema oscuro aparecería un rectángulo
   blanco recortado contra el panel. La placa lo convierte en lo que ya es
   —una etiqueta— y lo deja legible en cualquier fondo sin retocar la imagen.
   Sobre el panel blanco del menú la placa no se ve, que es lo que se quiere.

   La OBRA («Serpiente de Oro») va debajo y en el primario: es el proyecto, no
   la empresa, y no forma parte del logotipo del cliente.
   -------------------------------------------------------------------------*/
/* Firma de quien desarrolla (prefijo gp-). Se toma del ancla `--claro-fuerte`,
   la misma superficie de acción de toda la plataforma, para que no puedan
   desincronizarse. Es un ancla que el tema oscuro NO redefine, y eso es justo
   lo que hace falta: un logotipo no se recolorea con el tema. */
:root{
  --gp-fondo: var(--claro-fuerte);
  --gp-tinta: var(--claro-sobre);
}

.mk{
  display:flex; flex-direction:column; align-items:center;
  gap:6px; min-width:0; width:100%; text-decoration:none;
}
/* El logotipo es muy apaisado —5.45 de razón—, así que se dimensiona POR
   ANCHO y no por alto: fijarle 26 px de alto lo dejaba en 142 px de ancho y
   el nombre de la empresa no se leía. Ocupando el ancho del panel gana casi
   el triple de superficie sin deformarse. */
.mk-img{
  display:block; width:100%; max-width:196px; height:auto;
  background:#fff;                 /* la placa: el propio fondo del archivo */
  padding:5px 8px; border-radius:var(--r-sm);
  object-fit:contain;
}
.mk-obra{
  font-size:10px; font-weight:600; line-height:1;
  letter-spacing:.14em; text-transform:uppercase;
  color:var(--mo-steel-d);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%;
}

/* Versión grande: acceso y transición */
.mk-xl{ gap:10px; }
.mk-xl .mk-img{ max-width:330px; padding:9px 14px; border-radius:var(--r-md); }
.mk-xl .mk-obra{ font-size:11.5px; letter-spacing:.18em; }

/* Menú contraído: no cabe el nombre, así que se enseña solo el distintivo.
   Se recorta del MISMO archivo con object-fit, sin una segunda imagen que
   pudiera quedar desincronizada. */
body.sh-mini .mk-img{
  width:38px; height:38px; padding:3px;
  object-fit:cover; object-position:left center;
}
body.sh-mini .mk-obra{ display:none; }

/* ---------------------------------------------------------------------------
   1 ter bis. FIRMA DEL DESARROLLADOR  (prefijo gp-)

   «Desarrollado por GEN+», al pie del menú lateral y de las dos pantallas de
   entrada. No sale de 04-cliente/marca.js: el cliente cambia en cada
   plataforma, quien la desarrolla no.

   El distintivo es el logotipo de GEN+ dibujado con tipografía, igual que el
   resto de la marca: un recuadro marino con el nombre en blanco. Si no carga
   Plus Jakarta Sans cae a la del sistema y sigue leyéndose, que es lo que
   pasaría también con una imagen que no llegara.
   -------------------------------------------------------------------------*/
.gp-cred{
  display:inline-flex; align-items:center; gap:7px;
  font-size:10.5px; line-height:1;
}
.gp-txt{ color:var(--tx-3); letter-spacing:.01em; white-space:nowrap; }
/* Sin contorno: el azul se despega solo del panel en los dos temas. El marino
   casi negro sí lo necesitaba en oscuro, porque se fundía con él. */
.gp-logo{
  display:inline-flex; align-items:center;
  padding:4px 7px 5px;
  background:var(--gp-fondo); color:var(--gp-tinta);
  border-radius:4px;
  font-size:11px; font-weight:800; line-height:1;
  letter-spacing:.03em;
}
/* El signo va PEGADO a la N: en el logotipo es parte de la palabra, no algo
   sumado detrás. El tracking de la caja lo separaba y se leía «GEN  +». */
.gp-logo i{ font-style:normal; letter-spacing:0; margin-left:-.5px; }

/* ---------------------------------------------------------------------------
   1 quater. PANTALLA DE ACCESO  (prefijo lg-)

   Estructura tomada de un referente profesional —cajetilla centrada, campos
   con etiqueta encima, una sola acción a ancho completo—; color y geometría,
   de las dos webs del cliente. Es el método del estándar: la ESTRUCTURA de un
   referente, la IDENTIDAD de la marca.

   Los radios siguen la escala de iOS: generosos y proporcionales al tamaño
   del elemento. Una cajetilla grande pide más radio que un campo.
   -------------------------------------------------------------------------*/
:root{
  /* EL FONDO ES CLARO. Antes iba sobre marino profundo, con la marca en
     blanco encima; ahora las tres pantallas arrancan en claro y el acceso es
     la primera de las tres, así que abre en el mismo idioma en el que se
     sigue trabajando.

     El marino NO desaparece: se queda donde pesa —el degradado del botón, el
     primario del foco y el velo azul del propio lienzo— en vez de ocupar la
     pantalla entera. Los dos valores son el lienzo de la plataforma con un
     grado más de velo azul hacia abajo, para que la cajetilla blanca se
     recorte contra el fondo en lugar de fundirse con él. */
  --lg-fondo:   #f7f9fd;   /* casi blanco, arriba */
  --lg-fondo-2: #e8eef8;   /* velo azul, abajo */

  --lg-caja:    #ffffff;   /* la cajetilla es blanca: es donde se lee */
  --lg-borde:   #dfe6f2;   /* su contorno — sobre lienzo claro la sombra sola
                              no basta para separarla */
  --lg-tx:      #0a1020;
  --lg-tx-2:    #55637d;   /* etiquetas — 6.06:1 sobre blanco */
  --lg-tx-3:    #626e7d;   /* auxiliar — 5.19:1 sobre blanco */
  --lg-line:    #848c9e;   /* borde de campo — 3.37:1, cumple 1.4.11 */
  --lg-focus:   #2145c8;   /* foco: el primario de la marca */
  --lg-error:   #b3261e;

  /* Tinta SOBRE el lienzo — fuera de la cajetilla. Medidos contra el punto
     más OSCURO del degradado (#e8eef8), que aquí es el peor caso. */
  --lg-sobre:   #0a1020;   /* 17.05:1 — nombre de la marca */
  --lg-sobre-2: #55637d;   /* 5.19:1  — segunda línea del nombre */
  --lg-sobre-3: #55637d;   /* 5.19:1  — pie y texto de estado.
                              #626e7d, el auxiliar sobre blanco, se queda en
                              4.45:1 contra este fondo: no llega al 4.5 */
  --lg-ico:     #2145c8;   /* 7.64:1 — barra de avance y detalles de marca */
  --lg-velo:    rgba(10,16,32,.10);   /* canal de la barra de avance */

  --lg-r-caja:  22px;
  --lg-r-campo: 12px;
}

/* EL ACCESO NO SIGUE EL TEMA. Siempre en claro, en las dos pantallas.
   -------------------------------------------------------------------------
   El interruptor de tema es una preferencia de trabajo dentro de la
   plataforma; quien aún no ha entrado no la ha elegido. Además la entrada es
   la primera impresión de la marca y conviene que sea siempre la misma.

   Aquí se reponen las variables de PLATAFORMA que el acceso toma prestadas
   —isotipo, botón, aviso de error y la tinta general—, que sí se invierten
   con el tema y arrastraban a estas pantallas con él. Se reponen desde el
   ancla --claro-*, nunca escribiendo el color otra vez, para que el botón de
   entrar y los de dentro no puedan desincronizarse.                        */
.lg-pantalla,
.tr-pantalla{
  --sf-fuerte:   var(--claro-fuerte);     /* botón «Entrar» */
  --sf-fuerte-2: var(--claro-fuerte-2);
  --tx-fuerte:   var(--claro-sobre);
  --bd-fuerte:   var(--claro-fuerte);     /* contorno invisible, como en claro */
  --mo-steel-d:  var(--claro-azul-d);     /* isotipo de la marca */
  --grad-accion:   var(--claro-grad);     /* el degradado del botón «Entrar» */
  --grad-accion-2: var(--claro-grad-2);
  --st-crit-bg:  var(--claro-crit-bg);    /* aviso de credenciales */
  --st-crit-bd:  var(--claro-crit-bd);

  /* La tinta general también se hereda de la raíz: en oscuro es un blanco
     roto y dejaría texto blanco sobre la cajetilla blanca. Se repone a la del
     acceso, y se fija `color` para cortar la herencia de quien no lo declare. */
  --tx-1: var(--lg-tx);
  --tx-2: var(--lg-tx-2);
  --tx-3: var(--lg-tx-3);
  color: var(--lg-tx);

  color-scheme: light;   /* campos, casilla y barras del sistema, en claro */
}

/* El velo superior es lo único de color en el lienzo: un halo del primario
   muy tenue detrás de la marca, que da profundidad sin quitarle el sitio al
   claro. Va antes del degradado en la lista: la primera capa es la de arriba. */
.lg-pantalla{
  position:fixed; inset:0; z-index:200;
  display:flex; align-items:center; justify-content:center;
  padding:40px 24px;
  background:
    radial-gradient(120% 82% at 50% -12%, rgba(47,87,230,.11) 0%, rgba(47,87,230,0) 62%),
    linear-gradient(180deg, var(--lg-fondo) 0%, var(--lg-fondo-2) 100%);
  overflow-y:auto;                 /* si no cabe, se desplaza; nunca se corta */
}
.lg-pantalla[hidden]{ display:none; }

.lg-centro{ width:100%; max-width:392px; margin:auto; }

/* --- Marca, sobre la cajetilla ---
   Va sobre el lienzo, no dentro de la cajetilla. El contenedor repone los
   TOKENS de tinta para todos sus descendientes, en vez de pintar cada pieza
   por su cuenta: `.mk` declara `color:var(--tx-1)`, así que heredar el color
   no basta — hay que reponer la variable. */
.lg-marca{
  display:flex; justify-content:center; margin-bottom:28px;
  --tx-1: var(--lg-sobre);
  --tx-2: var(--lg-sobre-2);
  color: var(--lg-sobre);
}

/* --- Cajetilla --- */
.lg-caja{
  background:var(--lg-caja);
  border:1px solid var(--lg-borde);
  border-radius:var(--lg-r-caja);
  padding:32px 30px 30px;
  /* sombra en dos capas: contacto cercano + difusión amplia. Sobre lienzo
     claro va más suave que sobre el marino de antes —ahí la separación la
     daba el contraste; aquí la da el contorno— o se lee como una mancha. */
  box-shadow:0 1px 2px rgba(10,16,32,.04), 0 14px 34px rgba(10,16,32,.07);
}

.lg-titulo{
  font-size:19px; font-weight:600; letter-spacing:-.01em;
  color:var(--lg-tx); text-align:center; margin-bottom:6px;
}
.lg-sub{
  font-size:13px; color:var(--lg-tx-3);
  text-align:center; margin-bottom:26px;
}

.lg-campo{ margin-bottom:16px; }
/* Etiquetas en caja normal: en versalitas apretadas se leen peor y endurecen
   una pantalla que debe resultar acogedora. */
.lg-campo label{
  display:block; font-size:13px; font-weight:500;
  color:var(--lg-tx-2); margin-bottom:7px;
}

/* etiqueta a la izquierda · enlace de recuperación a la derecha */
.lg-fila-label{
  display:flex; align-items:baseline; justify-content:space-between; gap:10px;
}
.lg-fila-label label{ margin-bottom:7px; }
.lg-olvido{
  background:none; border:0; padding:0; cursor:pointer;
  font:inherit; font-size:12.5px; color:var(--lg-tx-2);
  transition:color .15s;
}
/* el subrayado aparece al interactuar: en reposo sería ruido */
.lg-olvido:hover{ color:var(--lg-tx); text-decoration:underline; text-underline-offset:2px; }
.lg-olvido:focus-visible{ outline:2px solid var(--lg-focus); outline-offset:3px; border-radius:3px; }

.lg-campo input{
  width:100%; height:44px; padding:0 13px;
  font:inherit; font-size:14px; color:var(--lg-tx);
  background:var(--lg-caja); border:1px solid var(--lg-line);
  border-radius:var(--lg-r-campo);
  transition:border-color .15s, box-shadow .15s;
}
.lg-campo input::placeholder{ color:var(--lg-tx-3); opacity:.7; }
/* Foco claramente visible: un anillo tenue no cumple accesibilidad y deja
   perdido a quien navega con teclado. */
.lg-campo input:focus{
  outline:none; border-color:var(--lg-focus);
  box-shadow:0 0 0 3px rgba(33,69,200,.18);
}
/* El error se marca también en el campo, no solo en el mensaje */
.lg-campo input[aria-invalid="true"]{
  border-color:var(--lg-error);
  box-shadow:0 0 0 3px rgba(179,38,30,.12);
}

/* contraseña: el ojo no tapa el texto porque el campo reserva su hueco */
.lg-clave{ position:relative; }

/* ⚠️  FUERA EL OJO NATIVO DEL NAVEGADOR. Edge —y Chrome en Windows— añaden su
   propio botón de revelar dentro del campo en cuanto se escribe algo. Al
   convivir con el nuestro salían DOS ojos pegados, uno de ellos con el estilo
   del sistema operativo y no del producto. Se retira el del navegador y se
   queda el que sí sigue los tokens y anuncia su estado a un lector de
   pantalla. `::-ms-clear` va por lo mismo: la aspa de borrar del sistema. */
.lg-clave input::-ms-reveal,
.lg-clave input::-ms-clear{ display:none; width:0; height:0; }
.lg-clave input{ padding-right:44px; }
.lg-ojo{
  position:absolute; right:5px; top:50%; transform:translateY(-50%);
  width:34px; height:34px; display:flex; align-items:center; justify-content:center;
  background:transparent; border:0; border-radius:9px;
  color:var(--lg-tx-3); cursor:pointer; transition:color .15s, background .15s;
}
.lg-ojo svg{ width:18px; height:18px; }
.lg-ojo:hover{ color:var(--lg-tx); background:#eef2f7; }
.lg-ojo:focus-visible{ outline:2px solid var(--lg-focus); outline-offset:1px; }

.lg-recordar{
  display:flex; align-items:center; gap:9px;
  font-size:13px; color:var(--lg-tx-2); cursor:pointer;
  margin:4px 0 22px;
}
.lg-recordar input{
  width:16px; height:16px; border-radius:5px;
  accent-color:var(--lg-focus); cursor:pointer;
}

.lg-error{
  font-size:12.5px; color:var(--lg-error); font-weight:500;
  background:var(--st-crit-bg); border:1px solid var(--st-crit-bd);
  border-radius:var(--lg-r-campo);
  padding:10px 12px; margin-bottom:16px; line-height:1.5;
}
.lg-error[hidden]{ display:none; }

/* Mismo token que los botones de la plataforma: es la misma acción, del mismo
   producto. Solo cambia el tamaño, porque aquí es la única acción. */
.lg-entrar{
  width:100%; height:46px;
  background:var(--grad-accion); color:var(--tx-fuerte);
  border:0; border-radius:var(--lg-r-campo);
  font:inherit; font-size:14px; font-weight:600; letter-spacing:.02em;
  cursor:pointer; transition:background .15s, box-shadow .15s;
  box-shadow:0 1px 2px rgba(10,16,32,.14);
}
.lg-entrar:hover{ background:var(--grad-accion-2); box-shadow:0 4px 14px rgba(31,60,174,.32); }
.lg-entrar:active{ background:var(--grad-accion-2); box-shadow:none; }
/* El anillo va en el primario, no en la tinta: sobre lienzo claro un anillo
   oscuro pegado a un botón azul se lee como un borde del propio botón. */
.lg-entrar:focus-visible{ outline:2px solid var(--lg-focus); outline-offset:3px; }
.lg-entrar[aria-busy="true"]{ opacity:.7; cursor:progress; }

/* El pie va sobre el lienzo, no sobre la cajetilla */
.lg-pie{
  font-size:11.5px; color:var(--lg-sobre-3); text-align:center;
  margin-top:24px; line-height:1.7;
}

/* La firma de GEN+, debajo del pie y separada de él: son dos cosas distintas
   —de quién es la plataforma y quién la hace— y juntas se leen como una. */
.lg-centro .gp-cred{
  display:flex; justify-content:center;
  margin-top:14px;
}

/* --- Adaptación a cualquier pantalla ---
   Tres cortes: tableta, móvil y altura reducida (móvil apaisado). Los campos
   y el botón nunca bajan de 44 px de alto: es el mínimo para tocar con el
   dedo, con guante si hace falta.                                          */
@media (max-width:480px){
  .lg-pantalla{ padding:28px 16px; }
  .lg-marca{ margin-bottom:22px; }
  .mk-xl .mk-ico{ width:37px; height:37px; flex:0 0 37px; }
  .mk-xl .mk-n1, .mk-xl .mk-n2{ font-size:12.5px; letter-spacing:.08em; }
  .mk-xl .mk-obra{ font-size:10.5px; }
  .lg-caja{ padding:26px 20px 24px; border-radius:20px; }
  .lg-titulo{ font-size:18px; }
  .lg-sub{ font-size:12.5px; margin-bottom:22px; }
  .lg-olvido{ font-size:12px; }
  /* 16px evita que iOS haga zoom automático al enfocar el campo */
  .lg-campo input{ font-size:16px; }
  .lg-pie{ margin-top:20px; font-size:11px; }
}

/* Muy estrecho: la etiqueta y el enlace de recuperación se apilan */
@media (max-width:340px){
  .lg-fila-label{ flex-direction:column; gap:0; align-items:flex-start; }
  .lg-olvido{ margin-bottom:7px; }
}

/* Móvil apaisado o ventana baja: se recorta lo decorativo, nunca lo funcional */
@media (max-height:620px){
  .lg-pantalla{ padding:20px 16px; align-items:flex-start; }
  .lg-marca{ margin-bottom:16px; }
  .mk-xl .mk-ico{ width:32px; height:32px; flex:0 0 32px; }
  .mk-xl .mk-n1, .mk-xl .mk-n2{ font-size:11.5px; letter-spacing:.07em; }
  .mk-xl .mk-obra{ font-size:9.5px; margin-top:3px; }
  .lg-caja{ padding:22px 22px 20px; }
  .lg-sub{ display:none; }
  .lg-titulo{ margin-bottom:18px; }
  .lg-campo{ margin-bottom:12px; }
  .lg-recordar{ margin:2px 0 16px; }
  /* Se va el pie de la plataforma, se queda la firma: de las dos líneas, la
     que hay que ver siempre es de quién es el trabajo. */
  .lg-pie{ display:none; }
  .lg-centro .gp-cred{ margin-top:16px; }
  .tr-cred{ margin-top:22px; }
}

/* ---------------------------------------------------------------------------
   1 quinquies. TRANSICIÓN A LA PLATAFORMA  (prefijo tr-)

   Puente entre el acceso y el escritorio. Cumple tres funciones:
     · da continuidad — mismo fondo y misma marca que la pantalla anterior,
     · confirma quién ha entrado, antes de que la interfaz lo diga,
     · cubre el arranque real: preparar el motor de conversión.

   Dura poco a propósito: menos de 0,8 s parpadea y no se lee; más de 2 s
   estorba a quien entra todas las mañanas.
   -------------------------------------------------------------------------*/
.tr-pantalla{
  position:fixed; inset:0; z-index:205;
  display:flex; align-items:center; justify-content:center;
  padding:40px 24px;
  /* EL MISMO FONDO QUE EL ACCESO, capa por capa: es lo que hace que el paso
     de una pantalla a la otra se lea como continuidad y no como un salto. */
  background:
    radial-gradient(120% 82% at 50% -12%, rgba(47,87,230,.11) 0%, rgba(47,87,230,0) 62%),
    linear-gradient(180deg, var(--lg-fondo) 0%, var(--lg-fondo-2) 100%);
  animation:tr-entra .32s ease both;
}
.tr-pantalla[hidden]{ display:none; }
.tr-pantalla.is-saliendo{ animation:tr-sale .34s ease both; }

@keyframes tr-entra{ from{ opacity:0 } to{ opacity:1 } }
@keyframes tr-sale { from{ opacity:1 } to{ opacity:0; visibility:hidden } }

/* Da para el logotipo entero del cliente en su versión grande, que es más
   ancho que el nombre corto de antes. */
.tr-centro{ width:100%; max-width:360px; text-align:center; }
.tr-marca{
  display:flex; justify-content:center; margin-bottom:30px;
  --tx-1: var(--lg-sobre);
  --tx-2: var(--lg-sobre-2);
  color: var(--lg-sobre);
}

.tr-saludo{
  font-size:20px; font-weight:600; letter-spacing:-.01em;
  color:var(--lg-sobre); margin-bottom:22px;
}

/* Barra de avance: fina, sin porcentajes. Un número exacto obligaría a
   inventarlo, y un progreso falso se nota. */
/* El canal es tinta al 10 %, no blanco: sobre el lienzo claro un canal blanco
   no se ve, y la barra parecería empezar de la nada. */
.tr-barra{
  height:3px; border-radius:99px; overflow:hidden;
  background:var(--lg-velo);
}
.tr-avance{
  height:100%; width:0; border-radius:99px;
  background:var(--lg-ico);
  /* La transición ocupa casi todo el intervalo entre pasos: si fuera más
     corta, la barra llegaría y se quedaría parada, y eso se lee como que algo
     se ha atascado. */
  transition:width 1.05s cubic-bezier(.4,0,.2,1);
}

.tr-estado{
  font-size:12.5px; color:var(--lg-sobre-3);
  margin-top:14px; min-height:1.4em;      /* reserva el alto: no salta */
  transition:opacity .2s;
}
.tr-estado.is-cambiando{ opacity:0; }

/* La firma queda claramente por debajo del bloque de estado: durante la
   espera lo que se mira es la barra, y la firma no debe competir con ella. */
.tr-cred{ display:flex; justify-content:center; margin-top:34px; }

@media (max-width:480px){
  .tr-marca{ margin-bottom:26px; }
  .tr-saludo{ font-size:18px; }
  .tr-cred{ margin-top:28px; }
}

/* Quien pide menos movimiento no ve animaciones: solo el texto */
@media (prefers-reduced-motion:reduce){
  .tr-pantalla, .tr-pantalla.is-saliendo{ animation:none; }
  .tr-avance{ transition:none; }
  .tr-estado{ transition:none; }
  .cv-drop, .card, .btn{ transition:none; }
}

/* ---------------------------------------------------------------------------
   2. BASE
   -------------------------------------------------------------------------*/
*,*::before,*::after{ box-sizing:border-box; }
/* La PÁGINA no se desplaza nunca: el armazón ocupa la pantalla y quien se
   desplaza es el interior de cada panel. Sin esto, al ampliar el zoom la
   ventana entera se mueve y los paneles se salen de su sitio. */
html,body{ height:100%; overflow:hidden; }
body{
  margin:0;
  background:var(--sf-app);
  color:var(--tx-1);
  transition:var(--tema-transicion);
  font-family:"Plus Jakarta Sans",-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  font-size:14px;
  line-height:1.5;
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3,h4,p{ margin:0; }
button{ font:inherit; color:inherit; }
a{ color:inherit; }
::selection{ background:var(--sf-acento); color:var(--tx-acento); }

:focus-visible{ outline:2px solid var(--mo-steel); outline-offset:2px; border-radius:3px; }

/* Tamaño de partida de todo icono del sprite. Un <svg> sin alto ni ancho se
   dibuja a 300x150 px: sin esta red de seguridad, cualquier icono que no caiga
   bajo una regla más específica revienta la fila donde esté. */
.sh-ico{ width:18px; height:18px; flex:0 0 auto; }

/* Barra de scroll discreta. Solo aparece cuando el contenido no cabe: los
   contenedores usan overflow:auto, nunca scroll. */
*::-webkit-scrollbar{ width:10px; height:10px; }
*::-webkit-scrollbar-thumb{
  background:var(--mo-sand-2); border-radius:99px;
  border:3px solid transparent; background-clip:content-box;
}
*::-webkit-scrollbar-thumb:hover{
  background:var(--mo-mute);
  border:3px solid transparent; background-clip:content-box;
}
*::-webkit-scrollbar-track{ background:transparent; }
/* Firefox no tiene ::-webkit-scrollbar */
*{ scrollbar-width:thin; scrollbar-color:var(--mo-sand-2) transparent; }

/* ---------------------------------------------------------------------------
   3. ARMAZÓN — rejilla, menú lateral, barra superior

   LA PIEZA MÁS DIFÍCIL DE ACERTAR. Copiada tal cual del kit: costó varias
   sesiones y cuatro correcciones sobre la causa equivocada.

   Fórmula, repetida en cada nivel que deba contener un scroll:
     contenedor   -> flex column · min-height:0 · overflow:hidden
     el que rueda -> flex:1 1 0  · min-height:0 · overflow:auto

   EN ESTA CADENA NO SE ESCRIBE NI UN PORCENTAJE DE ALTURA:
     · `height:100%` se resuelve contra el contenedor CON su padding, desborda
       por abajo y se come el margen; y si el contenedor no tiene alto
       resuelto, se computa `auto` y el scroll desaparece.
     · `flex:1 1 auto` mide por el CONTENIDO: el panel crece y no rueda.
   -------------------------------------------------------------------------*/
/* Paneles independientes sobre el lienzo: el menú y la barra superior son dos
   piezas separadas, no un marco continuo. Cada una con su borde y su sombra,
   como las tarjetas del contenido.

   Altura fija de pantalla: el armazón NO crece con el contenido. Sin esto una
   sección larga estira el menú lateral y deja de estar siempre a la vista. */
.sh-app{
  display:grid;
  grid-template-columns:var(--side-w) minmax(0,1fr);
  grid-template-rows:minmax(0,1fr);   /* minmax(0,…) evita que la fila crezca */
  gap:var(--hueco);
  height:100vh;
  height:100dvh;              /* en móvil descuenta la barra del navegador */
  padding:var(--hueco-sup) var(--hueco) var(--hueco);
  background:var(--sf-app);
  overflow:hidden;
  transition:grid-template-columns .18s ease;
}
.sh-app[hidden]{ display:none; }
body.sh-mini .sh-app{ grid-template-columns:var(--side-w-min) minmax(0,1fr); }

/* --- Menú lateral --- */
.sh-side{
  background:var(--sf-side);
  color:var(--tx-side);
  display:flex;
  flex-direction:column;
  min-height:0;
  border:1px solid var(--mo-sand);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-card);
  overflow:hidden;
  transition:var(--tema-transicion);
}

/* El logotipo pasó de dos líneas a tres —cliente arriba, obra debajo—, así
   que ya no cabe en los 58 px de la barra superior. Se deja crecer con su
   contenido y se le da el aire con padding: el resto del armazón no depende
   de que este bloque mida exactamente `--top-h`. */
.sh-brand{
  flex:0 0 auto;
  display:flex; align-items:center; justify-content:center;
  padding:13px 12px;
  border-bottom:1px solid var(--mo-sand);
}
/* Contraído: el nombre no cabe en 68 px. Queda solo el distintivo. */
body.sh-mini .sh-brand{ padding:13px 0; }
body.sh-mini .sh-brand .mk-t{ display:none; }
body.sh-mini .sh-brand .mk{ gap:0; }

/* --- Pie del menú: quién desarrolla ---
   Al pie y no en la barra superior: es una firma, no un control. Y dentro del
   panel del menú, que es la pieza que está siempre a la vista. */
.sh-side-pie{
  flex:0 0 auto;
  display:flex; align-items:center; justify-content:center;
  padding:11px 12px 13px;
  border-top:1px solid var(--mo-sand);
}
/* Contraído: cabe el distintivo, no la frase */
body.sh-mini .sh-side-pie{ padding:11px 0 13px; }
body.sh-mini .sh-side-pie .gp-txt{ display:none; }

/* El menú lleva 8 px y cada ítem 10 px: suman los 18 px del margen del panel,
   así que el texto queda alineado con la marca.

   Rueda en vertical, nunca en horizontal: su ancho es fijo y el texto se
   ajusta dentro. Hay que declarar `overflow-x:hidden` A MANO — dejándolo en
   `visible` el navegador lo convierte en `auto` al ver el otro eje en `auto`,
   y aparece una barra horizontal en cuanto se amplía el zoom. */
.sh-nav{
  flex:1 1 0; min-height:0;
  overflow-y:auto; overflow-x:hidden;
  padding:14px 8px 20px;
}
.sh-nav-group{
  font-size:9.5px; letter-spacing:.18em; text-transform:uppercase;
  color:var(--mo-mute); padding:16px 10px 8px; font-weight:600;
}
.sh-nav-group:first-child{ padding-top:6px; }
/* Contraído: el título del grupo no cabe, pero la separación entre bloques sí
   importa. Se convierte en una línea corta y centrada. */
body.sh-mini .sh-nav-group{
  font-size:0; padding:0; margin:12px auto 12px;
  width:24px; height:1px; background:var(--mo-sand);
}
body.sh-mini .sh-nav-group:first-child{ display:none; }

/* Ítem editorial: sin píldora — regla fina a la izquierda, como las webs de
   referencia, que marcan el activo con un filete y no con un bloque. */
.sh-nav-item{
  display:flex; align-items:center; gap:11px;
  width:100%; padding:8px 10px; margin-bottom:1px;
  background:transparent; border:0; border-radius:0;
  text-align:left; cursor:pointer;
  color:var(--tx-side);
  position:relative;
  transition:background .13s ease,color .13s ease;
}
.sh-nav-item .sh-ico{ flex:0 0 18px; width:18px; height:18px; opacity:.85; }
/* `anywhere` para que una palabra larga parta antes que desbordar el menú:
   con el zoom alto, una etiqueta larga no cabe en el ancho de la barra. */
.sh-nav-label{ font-size:13px; min-width:0; overflow-wrap:anywhere; }
.sh-nav-label.l2{ line-height:1.22; }

/* Hover: nunca blanquea — se oscurece el fondo, no el texto. */
.sh-nav-item:hover{ background:var(--mo-paper); color:var(--tx-1); }
/* El módulo activo se marca con el AZUL TENUE de la marca, no con un gris:
   es el estado más repetido de la pantalla y donde el color de la empresa
   trabaja mejor. El filete de la izquierda va en el primario. */
.sh-nav-item.is-active{ background:var(--mo-steel-l); color:var(--tx-side-on); font-weight:500; }
.sh-nav-item.is-active .sh-ico{ opacity:1; color:var(--mo-steel-d); }
.sh-nav-item.is-active::before{
  content:""; position:absolute; left:-6px; top:0; bottom:0;
  width:2px; background:var(--mo-steel);
}
.sh-nav-count{
  margin-left:auto; font-size:10.5px; font-weight:600;
  padding:1px 6px; border-radius:99px;
  background:var(--mo-sand); color:var(--mo-mute-2);
}
.sh-nav-item.is-active .sh-nav-count{ background:var(--sf-fuerte); color:var(--tx-fuerte); }
/* Contraído: el ítem pasa de fila a botón cuadrado. La barrita lateral que
   marca el activo no sirve aquí —el panel la recortaría—, así que el estado
   se señala con el propio botón. */
body.sh-mini .sh-nav-item{
  justify-content:center;
  width:40px; height:40px; padding:0; margin:0 auto 4px;
  border-radius:var(--r-md);
}
body.sh-mini .sh-nav-label,
body.sh-mini .sh-nav-count{ display:none; }
body.sh-mini .sh-nav-item::before{ display:none; }
body.sh-mini .sh-nav-item.is-active{ background:var(--sf-fuerte); }
body.sh-mini .sh-nav-item.is-active .sh-ico{ color:var(--tx-fuerte); }

/* --- Columna principal ---
   MISMA FÓRMULA QUE .sh-side. Sin height:100% en ningún eslabón: como item
   de rejilla ya se estira al alto exacto. */
.sh-main{
  display:flex;
  flex-direction:column;
  gap:var(--hueco);
  min-width:0; min-height:0;
  overflow:hidden;            /* el scroll vive en la sección, no aquí */
}

/* Panel propio, separado del menú y del contenido */
.sh-top{
  height:var(--top-h); flex:0 0 auto;
  display:flex; align-items:center; gap:14px;
  padding:0 18px;
  background:var(--sf-card);
  border:1px solid var(--mo-sand);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-card);
  transition:var(--tema-transicion);
}
/* Área en la que se trabaja. En la barra superior, no en el menú: responde
   «dónde estoy» a la misma altura que el resto de controles globales. */
.sh-area{
  font-size:15px; font-weight:600; letter-spacing:-.01em;
  color:var(--tx-1); white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; min-width:0;
}
.sh-top-sp{ margin-left:auto; }

.sh-ico-btn{
  width:32px; height:32px; flex:0 0 32px;
  display:inline-flex; align-items:center; justify-content:center;
  background:transparent; border:0; border-radius:var(--r-md);
  color:var(--tx-2); cursor:pointer;
  transition:background .14s ease, color .14s ease;
}
.sh-ico-btn:hover{ background:var(--mo-paper); color:var(--tx-1); }
.sh-ico-btn .sh-ico{ width:18px; height:18px; }

/* Botón de usuario: lleva a Mi cuenta, que no está en el menú lateral.

   Sin cajetilla. Un recuadro permanente alrededor del nombre compite con los
   botones de acción de la barra y ensucia la esquina. El elemento con forma es
   el avatar; el resto es texto. */
.sh-user{
  display:flex; align-items:center; gap:9px;
  background:transparent; border:0; cursor:pointer;
  padding:4px 4px 4px 2px; border-radius:var(--r-md);
  text-align:left; transition:opacity .15s;
}
.sh-user:hover{ opacity:.72; }
.sh-user:hover .sh-user-av{ filter:brightness(.93); }

.sh-user-av{
  width:32px; height:32px; border-radius:50%; flex:0 0 32px;
  /* El mismo azul de la marca que lleva el recuadro de la firma: es un ancla
     que el tema oscuro no redefine, así que el avatar no cambia de color al
     cambiar de tema —igual que un logotipo—. Blanco encima da 6.55:1. */
  background:var(--gp-fondo) !important; color:var(--gp-tinta) !important;
  display:grid; place-items:center; font-size:11.5px; font-weight:600;
  letter-spacing:.02em;
}
/* Estar en Mi cuenta se señala en el nombre, no con un anillo alrededor del
   avatar: el anillo se lee como un foco que se quedó pegado. */
.sh-user.is-active .sh-user-t b{
  color:var(--tx-1); text-decoration:underline;
  text-decoration-thickness:1.5px; text-underline-offset:3px;
}
.sh-user-t{ line-height:1.3; min-width:0; }
.sh-user-t b{
  display:block; font-size:12.5px; font-weight:600; color:var(--tx-1);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.sh-user-t span{
  display:block; font-size:10.5px; color:var(--tx-3);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

/* --- Área de contenido / secciones ---
   MARCO FIJO. No se desplaza: acota al contenido, que se recorta contra sus
   bordes y por tanto nunca llega a tocar la barra superior ni el filo de la
   ventana.

   SIN PADDING VERTICAL PROPIO: la separación de arriba ya la da el `gap` de
   .sh-main con la barra, y la de abajo el padding de .sh-app contra la
   ventana —el mismo que tiene el menú lateral—. Con padding aquí, este panel
   terminaba 11 px más arriba que el menú y los pies quedaban desnivelados.

   El scroll vive un nivel más abajo, en la sección activa. */
.sh-content{
  flex:1 1 0;                 /* toma todo el alto que deja la barra superior */
  display:flex;
  flex-direction:column;
  min-height:0;
  overflow:hidden;
}
/* SIN ancho máximo: el área de trabajo aprovecha toda la pantalla. Un tope
   fijo deja una franja muerta a la derecha en monitores anchos. La medida de
   lectura la gobiernan las rejillas de dentro, que al ensanchar AÑADEN
   COLUMNAS en vez de estirar la línea de texto. */
.sh-sec{
  display:none;
  padding:0 var(--hueco) 40px;
}
.sh-sec.is-active{
  display:block;
  flex:1 1 0; min-height:0;   /* igual que .sh-nav en el panel izquierdo */
  /* Los DOS ejes en auto. En horizontal aparece la barra solo cuando el
     contenido no cabe —una tabla ancha—; con `hidden` se recorta sin manera
     de llegar a lo que queda fuera. */
  overflow:auto;
  overscroll-behavior:contain;
  /* Reserva el hueco de la barra aunque no haya: sin esto, al pasar de una
     sección larga a una corta el contenido salta a la derecha. */
  scrollbar-gutter:stable;
}

.sh-sec-head{ margin-bottom:18px; }
.sh-sec-head h1{ font-size:21px; font-weight:600; letter-spacing:-.01em; }
/* SIN tope de medida. Llevaba `max-width:76ch`, la medida de lectura clásica,
   y con eso la descripción de la sección partía en dos líneas a mitad de una
   pantalla que tenía sitio de sobra. Aquí no es un párrafo de lectura: es un
   rótulo de una frase debajo del título, y se lee de un golpe. Ocupa el ancho
   que haya y baja de línea solo cuando la pantalla ya no da más. */
.sh-sec-head p{ font-size:13px; color:var(--tx-2); margin-top:3px; }

/* --- Sub-pestañas (scopeadas por sección) --- */
.sh-tabs{
  display:flex; gap:4px; flex-wrap:wrap;
  border-bottom:1px solid var(--mo-sand);
  margin-bottom:18px;
}
.sh-tab{
  border:0; background:transparent; cursor:pointer;
  padding:9px 14px; margin-bottom:-1px;
  border-bottom:2px solid transparent;
  font-size:13px; color:var(--tx-2);
  min-height:38px; line-height:1.2;
  display:inline-flex; align-items:center; gap:7px;
  border-radius:var(--r-sm) var(--r-sm) 0 0;
}
.sh-tab:hover{ background:var(--mo-line-2); color:var(--tx-1); }
.sh-tab.is-on{
  color:var(--tx-1) !important; font-weight:500;
  border-bottom-color:var(--mo-steel) !important;
}
.sh-tab .n{
  font-size:10.5px; font-weight:600; padding:1px 6px; border-radius:99px;
  background:var(--mo-sand); color:var(--mo-mute-2);
}
.sh-tab.is-on .n{ background:var(--mo-steel-l) !important; color:var(--st-info-fg) !important; }
.sh-pane{ display:none; }
.sh-pane.is-on{ display:block; }

/* ---------------------------------------------------------------------------
   4. BOTONES

   ESCALA · solo dos tamaños, y cada uno con su sitio:
     .btn      32 px  acciones de página: barras de sección y formularios
     .btn-sm   28 px  dentro de modales y de controles anidados
   Nunca se mezclan en el mismo bloque: dos alturas juntas se leen como un
   descuido, no como jerarquía.

   Todos sólidos: fondo de máximo contraste y texto encima. Un solo
   tratamiento evita el «oscuro junto a claro», que se lee como dos cosas
   distintas en lugar de como principal y secundario.

   El contorno no se ve en reposo —es del color del fondo—. Al pasar por
   encima el fondo se aclara y el contorno queda por debajo: aparece sin haber
   dibujado nada nuevo.
   -------------------------------------------------------------------------*/
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:7px;
  height:32px; padding:0 13px;
  border:1px solid var(--bd-fuerte); border-radius:var(--r-md);
  background:var(--grad-accion); color:var(--tx-fuerte);
  font-size:12.5px; font-weight:500; cursor:pointer; white-space:nowrap;
  box-shadow:var(--sh-1);
  transition:background .14s ease, box-shadow .14s ease;
}
/* El hover jamás blanquea: aquí OSCURECE el degradado y crece la sombra */
.btn:hover{ background:var(--grad-accion-2); box-shadow:var(--sh-2); }
.btn:active{ background:var(--grad-accion-2); box-shadow:var(--sh-1); }
.btn[disabled]{ opacity:.45; cursor:not-allowed; box-shadow:none; }
.btn:focus-visible{ outline:2px solid var(--mo-steel); outline-offset:2px; }

/* Acción principal: mismo cuerpo, texto con más peso. La diferencia es de
   énfasis, no de color: dos colores distintos vuelven a confundir. */
.btn-pri{ font-weight:600 !important; }
/* Rojo SÓLIDO y solo para lo que destruye datos. Junto a botones sólidos uno
   pálido parecería deshabilitado en vez de peligroso. Cerrar sesión, cancelar
   o quitar un archivo de la cola no destruyen nada: van en neutro. */
.btn-danger{
  background:var(--st-crit-fg) !important;
  color:#fff !important;
  border-color:var(--st-crit-fg) !important;
}
.btn-danger:hover{ filter:brightness(1.18); }
/* Fantasma: sin cuerpo. Para iconos sueltos de una barra, donde un botón con
   borde y sombra pesaría demasiado. */
.btn-ghost{
  background:transparent; border-color:transparent; color:var(--tx-2);
  box-shadow:none;
}
.btn-ghost:hover{
  background:var(--mo-paper); border-color:transparent;
  box-shadow:none; color:var(--tx-1);
}
.btn-sm{ height:28px; padding:0 10px; font-size:12px; }
.btn-icon{ width:32px; padding:0; }
.btn-sm.btn-icon{ width:28px; }
.btn .sh-ico{ width:15px; height:15px; flex:0 0 15px; opacity:.85; }
.btn-sm .sh-ico{ width:14px; height:14px; flex:0 0 14px; }

/* Compuerta por rol: los controles de admin solo existen para admin. */
.only-admin{ display:none !important; }
body.is-admin .only-admin{ display:inline-flex !important; }
body.is-admin tr.only-admin,
body.is-admin .only-admin.blk{ display:block !important; }

/* ---------------------------------------------------------------------------
   5. BADGES DE ESTADO  (color + etiqueta, nunca color solo)
   -------------------------------------------------------------------------*/
.bdg{
  display:inline-flex; align-items:center; gap:5px;
  padding:2px 8px 2px 6px; border-radius:99px;
  font-size:11px; font-weight:500; line-height:1.55; white-space:nowrap;
  border:1px solid transparent;
}
.bdg::before{ content:""; width:5px; height:5px; border-radius:50%; background:currentColor; flex:0 0 5px; }
.bdg-ok  { color:var(--st-ok-fg)  !important; background:var(--st-ok-bg)  !important; border-color:var(--st-ok-bd)  !important; }
.bdg-warn{ color:var(--st-warn-fg)!important; background:var(--st-warn-bg)!important; border-color:var(--st-warn-bd)!important; }
.bdg-crit{ color:var(--st-crit-fg)!important; background:var(--st-crit-bg)!important; border-color:var(--st-crit-bd)!important; }
.bdg-neut{ color:var(--st-neut-fg)!important; background:var(--st-neut-bg)!important; border-color:var(--st-neut-bd)!important; }
.bdg-info{ color:var(--st-info-fg)!important; background:var(--st-info-bg)!important; border-color:var(--st-info-bd)!important; }
/* Etiqueta monoespaciada — no es un estado: una extensión, un código */
.bdg-code{
  font-family:ui-monospace,"SFMono-Regular",Consolas,monospace;
  font-size:11px; letter-spacing:.02em;
  padding:2px 7px; border-radius:var(--r-sm);
  background:var(--mo-sand) !important; color:var(--mo-mute-2) !important;
  border:1px solid var(--mo-sand-2) !important;
}
.bdg-code::before{ display:none; }

/* ---------------------------------------------------------------------------
   6. TARJETA · KPI
   -------------------------------------------------------------------------*/
.card{
  background:var(--sf-card);
  border:1px solid var(--mo-sand);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-card);
}
.card-h{
  display:flex; align-items:center; gap:10px;
  padding:13px 16px; border-bottom:1px solid var(--mo-sand);
}
.card-h h2{ font-size:13.5px; font-weight:600; }
.card-h p{ font-size:11.5px; color:var(--tx-3); }
.card-h-sp{ margin-left:auto; }
.card-b{ padding:16px; }

.kpi-row{
  display:grid; gap:14px; margin-bottom:18px;
  grid-template-columns:repeat(auto-fit,minmax(196px,1fr));
}
.kpi{ padding:15px 16px 14px; }
.kpi-l{
  font-size:10.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--tx-3); font-weight:600;
}
.kpi-v{
  font-size:30px; line-height:1.12; font-weight:600;
  letter-spacing:-.02em; color:var(--tx-1); margin-top:5px;
  font-variant-numeric:tabular-nums;
}
.kpi-d{ font-size:11.5px; color:var(--tx-2); margin-top:2px; }

/* ---------------------------------------------------------------------------
   7. LISTA-ÍNDICE  (patrón maestro: LISTA -> POP-UP)
   -------------------------------------------------------------------------*/
.lst-wrap{
  background:var(--sf-card);
  border:1px solid var(--mo-sand);
  border-radius:var(--r-lg);
  overflow:hidden;
  box-shadow:var(--sh-card);
}
.lst{ width:100%; border-collapse:collapse; table-layout:fixed; }
.lst th{
  text-align:left; font-size:10.5px; font-weight:600;
  letter-spacing:.09em; text-transform:uppercase; color:var(--tx-3);
  padding:10px 14px; background:var(--mo-paper-2);
  border-bottom:1px solid var(--mo-sand);
  white-space:nowrap;
}
.lst td{
  padding:11px 14px; font-size:13px;
  border-bottom:1px solid var(--mo-line-2);
  vertical-align:middle;
  /* El texto nunca se derrama de una celda de ancho fijo */
  white-space:normal; overflow-wrap:break-word; word-break:break-word; overflow:hidden;
}
.lst tr:last-child td{ border-bottom:0; }
.lst tbody tr{ cursor:pointer; }
/* Hover que nunca blanquea */
.lst tbody tr:hover td{ background:var(--mo-paper); }
.lst-t{ font-weight:500; }
.lst-s{ display:block; font-size:11.5px; color:var(--tx-3); margin-top:1px; }
.lst-num{ font-variant-numeric:tabular-nums; color:var(--tx-2); }
.lst-c{ text-align:center; }
.lst-r{ text-align:right; }

/* Fila que todavía no se puede abrir —se está leyendo, o falló—: deja de
   anunciarse como pulsable. Si el cursor dice «aquí se puede tocar» y no pasa
   nada, se lee como que la plataforma está rota. */
.lst tbody tr.es-inerte{ cursor:default; }

.lst-empty{ padding:46px 20px; text-align:center; }
.lst-empty h3{ font-size:14px; font-weight:600; margin-bottom:4px; }
.lst-empty p{ font-size:12.5px; color:var(--tx-2); margin-bottom:14px; }

/* Barra de filtros genérica de cualquier lista */
.pl-bar{ display:flex; align-items:center; gap:9px; flex-wrap:wrap; margin-bottom:14px; }
.pl-bar-sp{ flex:1 1 auto; }
.pl-hint{ font-size:11.5px; color:var(--tx-3); }
.pl-cuenta{ font-size:11.5px; color:var(--tx-3); margin-bottom:9px; }
.pl-vacio{
  padding:34px 20px; text-align:center;
  background:var(--sf-card); border:1px solid var(--mo-sand);
  border-radius:var(--r-lg); box-shadow:var(--sh-card);
}
.pl-vacio p{ font-size:13px; color:var(--tx-2); }
/* Nota al pie de una sección: el margen va arriba */
.sh-pie-nota{ margin:var(--hueco) 0 0; }

/* ---------------------------------------------------------------------------
   8. FORMULARIOS
   -------------------------------------------------------------------------*/
.form-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr)); gap:14px; }
.fld label{ display:block; font-size:11.5px; color:var(--tx-2); margin-bottom:5px; }
.fld input,.fld textarea{
  width:100%; height:34px; padding:0 11px;
  border:1px solid var(--mo-line); border-radius:var(--r-md);
  background:var(--mo-paper-2); font:inherit; font-size:13px; color:var(--tx-1);
  outline:none;
}
.fld textarea{ height:80px; padding:9px 11px; resize:vertical; }
.fld input:focus,.fld textarea:focus{ border-color:var(--mo-steel); background:var(--sf-card); }
.fld input[readonly]{ color:var(--tx-2); }

/* --- Mi cuenta --- */
.cta-card{ max-width:720px; }
/* Zona de sesión. Fondo distinto del de la tarjeta de datos: separa el bloque
   y, sobre todo, invierte la relación con el botón — antes era blanco sobre
   blanco y el botón desaparecía. */
.cta-salir{
  margin-top:var(--hueco); max-width:720px;
  background:var(--mo-paper);
  border-color:var(--mo-sand-2);
}
.cta-salir .card-b{
  display:flex; align-items:center; justify-content:space-between;
  gap:16px; flex-wrap:wrap;
}
.cta-salir-t{ flex:1 1 240px; }
.cta-salir-t b{ display:block; font-size:13.5px; font-weight:600; }
.cta-salir-t span{ display:block; font-size:12px; color:var(--tx-2); margin-top:2px; }

/* ---------------------------------------------------------------------------
   9. MÓDULO CONVERTIR  (prefijo cv-)

   El dominio de esta plataforma: entra una hoja de cálculo, sale otro
   formato. Tres piezas, en el orden en que se usan:
     · la zona de carga         .cv-drop
     · la cola de archivos      .cv-cola  (lista-índice; la fila abre el
                                           pop-up con la vista previa)
     · la barra de exportación  .cv-out
   -------------------------------------------------------------------------*/

/* --- Zona de carga -------------------------------------------------------
   Es una etiqueta, no un botón: envuelve un <input type="file">, así que el
   clic y el teclado funcionan sin JS. El arrastre lo añade el módulo encima. */
.cv-drop{
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:4px; padding:34px 24px; margin-bottom:var(--hueco);
  text-align:center; cursor:pointer;
  /* Velo azul muy tenue en vez de blanco plano: es la pieza principal de la
     pantalla y donde el color de la marca invita a soltar el archivo. */
  background:linear-gradient(180deg, var(--sf-card) 0%, var(--mo-steel-l) 100%);
  border:1.5px dashed var(--mo-sand-2);
  border-radius:var(--r-lg);
  transition:border-color .16s ease, background .16s ease;
}
.cv-drop:hover{ border-color:var(--mo-steel); }
.cv-drop:focus-within{ border-color:var(--mo-steel); box-shadow:0 0 0 3px var(--mo-steel-l); }
/* Arrastrando por encima: el estado se marca con el borde Y con el texto, no
   solo con color — quien no distingue colores necesita el mismo aviso. */
.cv-drop.es-encima{
  border-color:var(--mo-steel); border-style:solid;
  background:var(--mo-steel-l);
}
.cv-drop input[type="file"]{
  position:absolute; width:1px; height:1px; opacity:0; pointer-events:none;
}
.cv-drop-ico{
  width:30px; height:30px; color:var(--mo-steel-d); margin-bottom:6px;
}
.cv-drop b{ font-size:14px; font-weight:600; color:var(--tx-1); }
.cv-drop span{ font-size:12.5px; color:var(--tx-2); }
.cv-drop em{
  font-style:normal; font-size:11.5px; color:var(--tx-3); margin-top:5px;
}

/* --- Cola de archivos ---------------------------------------------------- */
.cv-nom{
  display:flex; align-items:center; gap:9px; min-width:0;
}
.cv-nom .sh-ico{ width:16px; height:16px; flex:0 0 16px; color:var(--tx-3); }
.cv-nom-t{ min-width:0; }
.cv-quitar{
  width:26px; height:26px; padding:0;
  display:inline-flex; align-items:center; justify-content:center;
  background:transparent; border:0; border-radius:var(--r-sm);
  color:var(--tx-3); cursor:pointer;
  transition:background .14s ease, color .14s ease;
}
.cv-quitar:hover{ background:var(--mo-paper); color:var(--st-crit-fg); }
.cv-quitar .sh-ico{ width:15px; height:15px; }

/* --- Barra de exportación ------------------------------------------------
   Va en tarjeta propia, debajo de la cola: es el paso siguiente, no un filtro
   de la lista. Los controles quedan en UNA sola línea mientras quepan. */
.cv-out{
  margin-top:var(--hueco);
  display:flex; align-items:center; gap:14px; flex-wrap:wrap;
}
.cv-out-l{
  font-size:10.5px; font-weight:600; letter-spacing:.1em;
  text-transform:uppercase; color:var(--tx-3);
}
.cv-out-sp{ flex:1 1 auto; }

/* Selector de formato · PÍLDORA, no botones.
   El contraste fuerte aquí NO es jerarquía, es ESTADO: dice cuál está
   seleccionado. Se le da forma de píldora justamente para que no se confunda
   con los botones de acción, que son rectangulares. */
.cv-fmt{
  display:inline-flex; align-items:center; gap:2px;
  padding:3px; border-radius:99px;
  background:var(--mo-paper); border:1px solid var(--mo-sand);
}
.cv-fmt button{
  height:26px; padding:0 13px; border:0; border-radius:99px;
  background:transparent; color:var(--tx-2);
  font-size:12px; font-weight:500; cursor:pointer; white-space:nowrap;
  transition:background .14s ease, color .14s ease;
}
.cv-fmt button:hover{ color:var(--tx-1); }
.cv-fmt button.es-on{
  background:var(--sf-fuerte) !important;
  color:var(--tx-fuerte) !important;
  font-weight:600;
}
.cv-fmt button:focus-visible{ outline:2px solid var(--mo-steel); outline-offset:1px; }

/* --- Vista previa dentro del pop-up --------------------------------------
   La hoja se muestra tal como llega. El contenedor rueda en los DOS ejes: una
   hoja ancha tiene que poder alcanzarse hasta el final, y ocultarla dejaría
   contenido inalcanzable. */
.cv-prev-bar{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  margin-bottom:12px;
}
.cv-prev-wrap{
  max-height:min(58vh, 520px);
  overflow:auto;
  border:1px solid var(--mo-sand);
  border-radius:var(--r-md);
  background:var(--sf-card);
}
.cv-hoja{
  border-collapse:collapse;
  font-size:12px;
  font-variant-numeric:tabular-nums;
}
.cv-hoja th,
.cv-hoja td{
  border:1px solid var(--mo-sand);
  padding:4px 8px;
  max-width:260px;
  /* El texto no se derrama, en ninguna celda */
  overflow:hidden; overflow-wrap:break-word; word-break:break-word;
  vertical-align:top;
}
/* Cabecera de columna (A, B, C…) y de fila (1, 2, 3…): la referencia de una
   hoja de cálculo. Pegadas, para no perderlas al rodar. */
.cv-hoja thead th{
  position:sticky; top:0; z-index:2;
  background:var(--mo-paper-2); color:var(--tx-3);
  font-size:10.5px; font-weight:600; letter-spacing:.06em;
  text-align:center; white-space:nowrap;
}
.cv-hoja tbody th{
  position:sticky; left:0; z-index:1;
  background:var(--mo-paper-2); color:var(--tx-3);
  font-size:10.5px; font-weight:600; text-align:right;
  white-space:nowrap; width:46px;
}
.cv-hoja thead th:first-child{ z-index:3; left:0; position:sticky; width:46px; }
.cv-hoja td{ color:var(--tx-1); background:var(--sf-card); }
/* La primera fila de datos se marca como encabezado cuando así se ha
   declarado: es lo que decide si sale como cabecera en el archivo exportado. */
.cv-hoja tr.es-cab td{ font-weight:600; background:var(--mo-paper); }
.cv-hoja td.es-num{ text-align:right; }
.cv-vacia{ color:var(--tx-3); }

.cv-meta{
  display:flex; gap:16px; flex-wrap:wrap;
  font-size:11.5px; color:var(--tx-2); margin-top:10px;
}
.cv-meta b{ color:var(--tx-1); font-weight:600; }

/* Aviso dentro del módulo (motor no disponible, archivo ilegible…) */
.cv-nota{
  display:flex; gap:9px; align-items:flex-start;
  padding:11px 13px; border-radius:var(--r-md);
  font-size:12.5px; margin-bottom:var(--hueco);
  border:1px solid transparent;
}
.cv-nota .sh-ico{ width:16px; height:16px; flex:0 0 16px; margin-top:1px; }
.cv-nota-info{ color:var(--st-info-fg) !important; background:var(--st-info-bg) !important; border-color:var(--st-info-bd) !important; }
.cv-nota-warn{ color:var(--st-warn-fg) !important; background:var(--st-warn-bg) !important; border-color:var(--st-warn-bd) !important; }
.cv-nota-crit{ color:var(--st-crit-fg) !important; background:var(--st-crit-bg) !important; border-color:var(--st-crit-bd) !important; }
.cv-nota b{ font-weight:600; }
/* `hidden` es del navegador y `display:flex` es de aquí: en la cascada gana
   el nuestro, así que un aviso oculto seguía ocupando su sitio — se veía una
   barra de color vacía debajo del botón. El atributo tiene que poder más. */
.cv-nota[hidden]{ display:none !important; }
/* Aviso al pie de una tarjeta: el margen va arriba, no abajo */
.cv-nota-pie{ margin:var(--hueco) 0 0; }

/* ---------------------------------------------------------------------------
   AVANCE DE LA CONVERSIÓN A PDF

   Anillo con el porcentaje dentro, y al lado el paso en el que va.

   DOS SEÑALES, Y CADA UNA DICE UNA COSA DISTINTA:

     · El NÚMERO es el avance real. Lo escribe el servidor al terminar cada
       paso del pipeline, así que puede quedarse quieto un rato — la
       exportación de Excel es un solo paso y es el más largo de todos.
     · El GIRO dice que sigue vivo. Es lo único que se mueve durante ese rato.

   Por qué no un contador que suba solo hasta el 99: porque se nota, y el día
   que de verdad se atasque ya nadie lo va a creer. Esto es lo mismo que llevó
   a que la barra de la pantalla de transición NO lleve porcentaje: allí no hay
   nada que medir, así que no se finge un número; aquí sí lo hay, así que se
   da el de verdad.
   -------------------------------------------------------------------------*/
.cv-prog{
  display:flex; align-items:center; gap:16px;
  margin:var(--hueco) 0 0;
  padding:16px 18px;
  background:var(--sf-card);
  border:1px solid var(--mo-sand);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-card);
}
.cv-prog[hidden]{ display:none; }

/* El margen deja sitio al halo del giro, que sobresale 6 px por cada lado */
.cv-prog-aro{
  position:relative; flex:0 0 58px; width:58px; height:58px; margin:6px;
}
.cv-prog-aro svg{
  width:100%; height:100%;
  /* -90° para que el trazo arranque arriba y no a las tres en punto */
  transform:rotate(-90deg);
}
.cv-prog-canal{ fill:none; stroke:var(--mo-sand); stroke-width:4; }
.cv-prog-linea{
  fill:none; stroke:var(--mo-steel); stroke-width:4; stroke-linecap:round;
  /* Acompaña al salto entre pasos en vez de aparecer de golpe. Solo el trazo:
     el número salta, porque un número interpolado enseña cifras por las que el
     proceso no ha pasado. */
  transition:stroke-dashoffset .45s cubic-bezier(.4,0,.2,1);
}

/* El giro va en el CONTENEDOR del anillo, no en el trazo: girar el trazo
   movería también su punto de arranque y el avance dejaría de leerse.

   ⚠️  Y va POR FUERA del anillo, fino y tenue, no encima. Compartiendo
   diámetro y grosor con el trazo del avance se leían como la misma señal: a
   0 % se veía un arco azul girando y parecía que ya iba por la cuarta parte.
   Separados —el avance grueso y dentro, el giro fino y fuera— cada uno dice
   lo suyo y no hay forma de confundirlos. */
.cv-prog-aro::after{
  content:''; position:absolute; inset:-6px;
  border-radius:50%;
  border:1.5px solid transparent;
  border-top-color:var(--mo-steel);
  opacity:.4;
  animation:cv-gira 1.1s linear infinite;
}
.cv-prog.is-fin .cv-prog-aro::after{ display:none; }
@keyframes cv-gira{ to{ transform:rotate(360deg); } }

.cv-prog-n{
  position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center;
  font-size:15px; font-weight:700; color:var(--tx-1);
  letter-spacing:-.02em;
  /* Cifras de ancho fijo: sin esto el número baila al pasar de 9 a 10 */
  font-variant-numeric:tabular-nums;
}
.cv-prog-n i{ font-style:normal; font-size:9.5px; font-weight:600; color:var(--tx-3); margin-left:1px; }

.cv-prog-t{ min-width:0; line-height:1.45; }
.cv-prog-t b{ display:block; font-size:13.5px; font-weight:600; color:var(--tx-1); }
/* El paso puede ser largo —lleva el nombre de la hoja— y no debe reventar la
   tarjeta ni hacerla crecer a cada cambio: se corta con puntos suspensivos. */
.cv-prog-t span{
  display:block; font-size:12.5px; color:var(--tx-2);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

/* Quien pide menos movimiento no ve el giro. El número sigue informando: es
   el que lleva el dato, el giro solo acompaña. */
@media (prefers-reduced-motion:reduce){
  .cv-prog-aro::after{ animation:none; opacity:.3; }
  .cv-prog-linea{ transition:none; }
}

/* La tarjeta de exportación va separada de la cola, como cualquier panel */
.cv-card{ margin-top:var(--hueco); }
.cv-recorte{ margin-top:8px; }

/* ---------------------------------------------------------------------------
   9 bis. EDITOR DE MAPAS  (prefijo mp-)

   Un lienzo con la página del formato y los campos encima. El color de cada
   campo dice su tipo, pero nunca solo: encima lleva su nombre y el panel lo
   escribe con letras.
   -------------------------------------------------------------------------*/
.mp-nota{ margin-bottom:var(--hueco); }
.mp-nota[hidden]{ display:none; }

.mp-barra{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  margin-bottom:var(--hueco);
}
/* La etiqueta ES el botón: envuelve el <input type="file">, así que el clic y
   el teclado funcionan sin una línea de JS. */
.mp-subir{ position:relative; overflow:hidden; cursor:pointer; }
.mp-subir input{
  position:absolute; inset:0; opacity:0; cursor:pointer;
  font-size:0;                      /* Safari le da alto propio si no */
}
.mp-estado{ font-size:11.5px; color:var(--tx-2); }
.mp-estado b{ color:var(--tx-3); font-weight:400; margin:0 2px; }

.mp-zoom{ display:inline-flex; align-items:center; gap:6px; }
.mp-zoom[hidden]{ display:none; }
.mp-zoom-v{
  font-size:11.5px; color:var(--tx-2); min-width:48px; text-align:center;
  font-variant-numeric:tabular-nums;
}

/* Lienzo a la izquierda, propiedades a la derecha */
.mp-cuerpo{
  display:grid; gap:var(--hueco);
  grid-template-columns:minmax(0,1fr) 340px;
  align-items:start;
}

/* El lienzo rueda dentro de su caja, no empuja la sección: es el mismo
   tratamiento que el documento fiel del kit. En los DOS ejes — una página
   ampliada no cabe a lo ancho y hay que poder llegar al borde derecho. */
.mp-lienzo-wrap{
  overflow:auto;
  max-height:calc(100dvh - 260px);
  background:var(--mo-paper-2);
  border:1px solid var(--mo-sand);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-card);
  padding:12px;
}
.mp-lienzo{
  position:relative;
  margin:0 auto;
  /* el fondo blanco es el del papel, no del tema: la página es una hoja */
  background:#fff;
  box-shadow:var(--sh-2);
  touch-action:none;              /* el arrastre lo gobierna el módulo */
  cursor:crosshair;
}
.mp-pagina{
  display:block; width:100%; height:100%;
  user-select:none; -webkit-user-drag:none;
}
.mp-capa{ position:absolute; inset:0; }

/* --- un campo sobre la página --- */
.mp-campo{
  position:absolute;
  border:1.5px solid var(--mp-c, var(--mp-texto));
  background:color-mix(in srgb, var(--mp-c, var(--mp-texto)) 16%, transparent);
  border-radius:2px;
  cursor:move;
  overflow:visible;
}
.mp-campo:hover{ background:color-mix(in srgb, var(--mp-c, var(--mp-texto)) 28%, transparent); }
.mp-campo.es-sel{
  border-width:2px;
  box-shadow:0 0 0 2px color-mix(in srgb, var(--mp-c, var(--mp-texto)) 35%, transparent);
  z-index:3;
}
/* Un campo con problema se marca con trazo discontinuo Y sale listado en la
   revisión con su motivo: el color no comunica solo. */
.mp-campo.es-malo{ border-style:dashed; border-color:var(--st-crit-fg); }
.mp-campo:focus-visible{ outline:2px solid var(--mo-steel); outline-offset:1px; }

.mp-campo-n{
  position:absolute; left:0; bottom:100%;
  font-size:9.5px; line-height:1.5; white-space:nowrap;
  padding:0 4px; border-radius:3px 3px 0 0;
  background:var(--mp-c, var(--mp-texto)); color:#fff;
  max-width:220px; overflow:hidden; text-overflow:ellipsis;
  pointer-events:none;
}

.mp-t-t{ --mp-c:var(--mp-texto); }
.mp-t-m{ --mp-c:var(--mp-multi); }
.mp-t-n{ --mp-c:var(--mp-numero); }
.mp-t-r{ --mp-c:var(--mp-radio); }
.mp-t-c{ --mp-c:var(--mp-casilla); }
.mp-t-f{ --mp-c:var(--mp-firma); }

/* Asas de redimensión — 12 px de caja para poder cogerlas con el dedo */
.mp-asa{
  position:absolute; width:12px; height:12px; z-index:4;
  background:var(--sf-card); border:2px solid var(--mp-c, var(--mp-texto));
  border-radius:50%;
}
.mp-asa-nw{ left:-6px; top:-6px;    cursor:nwse-resize; }
.mp-asa-ne{ right:-6px; top:-6px;   cursor:nesw-resize; }
.mp-asa-sw{ left:-6px; bottom:-6px; cursor:nesw-resize; }
.mp-asa-se{ right:-6px; bottom:-6px;cursor:nwse-resize; }

/* Lo que se está dibujando, antes de soltar */
.mp-fantasma{
  position:absolute; z-index:5; pointer-events:none;
  border:1.5px dashed var(--mo-steel);
  background:color-mix(in srgb, var(--mo-steel) 14%, transparent);
}

/* --- panel de propiedades --- */
.mp-panel{ display:flex; flex-direction:column; gap:var(--hueco); min-width:0; }
.mp-card .card-b{ padding:14px 16px; }
.mp-fld{ margin-bottom:11px; }
.mp-mono{ font-family:ui-monospace,"SFMono-Regular",Consolas,monospace; }

.mp-tipos{ display:flex; flex-wrap:wrap; gap:4px; }
.mp-tipo{
  height:28px; padding:0 10px;
  border:1px solid var(--mo-line); border-radius:99px;
  background:var(--sf-card); color:var(--tx-2);
  font-size:11.5px; cursor:pointer; white-space:nowrap;
  transition:background .14s ease, color .14s ease, border-color .14s ease;
}
.mp-tipo:hover{ color:var(--tx-1); border-color:var(--mo-steel); }
/* Píldora, como el selector de formato: aquí el contraste fuerte es ESTADO
   —cuál está elegido—, no jerarquía de acción. */
.mp-tipo.es-on{
  background:var(--sf-fuerte) !important; color:var(--tx-fuerte) !important;
  border-color:var(--bd-fuerte) !important; font-weight:600;
}

.mp-grupo{
  margin:12px 0; padding:12px;
  background:var(--mo-paper); border:1px solid var(--mo-sand);
  border-radius:var(--r-md);
}
.mp-ayuda{ font-size:11.5px; color:var(--tx-2); margin-top:8px; line-height:1.55; }

.mp-errores{ margin:0; padding-left:18px; font-size:12px; color:var(--tx-2); }
.mp-errores li{ margin-bottom:5px; cursor:pointer; line-height:1.5; }
.mp-errores li.es-grave{ color:var(--st-crit-fg); }
.mp-errores li:hover{ text-decoration:underline; text-underline-offset:2px; }

.mp-lista{ max-height:320px; overflow-y:auto; }
.mp-lista-i{
  display:flex; align-items:center; gap:9px; width:100%;
  padding:8px 16px; border:0; background:transparent; cursor:pointer;
  text-align:left; border-bottom:1px solid var(--mo-line-2);
}
.mp-lista-i:hover{ background:var(--mo-paper); }
.mp-lista-i.es-sel{ background:var(--mo-steel-l); }
.mp-pt{
  width:9px; height:9px; flex:0 0 9px; border-radius:2px;
  background:var(--mp-c, var(--mp-texto));
}
.mp-lista-n{
  flex:1 1 auto; min-width:0; font-size:12.5px; color:var(--tx-1);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.mp-lista-r{
  font-size:11px; color:var(--tx-3); flex:0 0 auto;
  font-family:ui-monospace,"SFMono-Regular",Consolas,monospace;
}

/* --- estado vacío con las instrucciones --- */
.mp-vacio{ text-align:left; max-width:70ch; margin:0 auto; }
.mp-vacio h3{ font-size:15px; font-weight:600; margin-bottom:8px; }
.mp-pasos{ margin:10px 0; padding-left:20px; font-size:13px; color:var(--tx-2); }
.mp-pasos li{ margin-bottom:7px; line-height:1.6; }
.mp-cmd{ font-size:12.5px; color:var(--tx-2); margin-top:12px; line-height:1.9; }
.mp-vacio code, .mp-cmd code{
  font-family:ui-monospace,"SFMono-Regular",Consolas,monospace;
  font-size:11.5px; padding:2px 6px; border-radius:var(--r-sm);
  background:var(--mo-paper); border:1px solid var(--mo-sand);
  overflow-wrap:anywhere;
}

@media (max-width:1100px){
  .mp-cuerpo{ grid-template-columns:minmax(0,1fr); }
  .mp-lienzo-wrap{ max-height:70vh; }
}

/* ---------------------------------------------------------------------------
   10. COMPONENTES COMPARTIDOS  (prefijo mo-)  ·  ver 01-estandares/ui.md
   -------------------------------------------------------------------------*/

/* --- Campo de búsqueda --- */
.mo-busca{
  display:flex; align-items:center; gap:7px;
  height:32px; padding:0 11px; min-width:200px; flex:1 1 240px; max-width:380px;
  background:var(--sf-card); border:1px solid var(--mo-line);
  border-radius:var(--r-md); color:var(--tx-3);
  transition:border-color .14s ease;
}
.mo-busca:focus-within{ border-color:var(--mo-steel); }
.mo-busca .sh-ico{ width:15px; height:15px; flex:0 0 auto; }
.mo-busca input{
  flex:1 1 auto; min-width:0; border:0; background:transparent;
  font:inherit; font-size:12.5px; color:var(--tx-1); outline:0;
}

/* --- Casilla · área táctil de 32 px aunque la caja mida 16 --- */
.mo-check{
  display:inline-flex; align-items:center; gap:8px; min-height:32px;
  font-size:12.5px; color:var(--tx-2); cursor:pointer;
}
.mo-check input{
  width:16px; height:16px; flex:0 0 auto;
  accent-color:var(--mo-steel-d); cursor:pointer;
}

/* --- Desplegable propio --------------------------------------------------
   El <select> nativo abre una lista que pinta el SISTEMA OPERATIVO: su
   tipografía, sus colores y su azul de selección. No admite estilo, y en tema
   oscuro sale clara. Dentro del producto se ve como una pieza prestada. */
.mo-sel{ position:relative; flex:0 1 auto; min-width:0; }
.mo-sel-b{
  display:flex; align-items:center; gap:8px;
  width:100%; height:32px; padding:0 9px 0 11px;
  background:var(--sf-card); border:1px solid var(--mo-line);
  border-radius:var(--r-md);
  font:inherit; font-size:12.5px; color:var(--tx-1);
  cursor:pointer; text-align:left;
  transition:border-color .14s ease, background .14s ease;
}
.mo-sel-b:hover{ border-color:var(--mo-steel); }
.mo-sel.es-abierto .mo-sel-b{ border-color:var(--mo-steel); }
.mo-sel-t{
  flex:1 1 auto; min-width:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.mo-sel-i{
  width:15px; height:15px; flex:0 0 auto; color:var(--tx-3);
  transition:transform .16s ease;
}
.mo-sel.es-abierto .mo-sel-i{ transform:rotate(180deg); }

.mo-sel-l{
  position:absolute; z-index:90; left:0; top:calc(100% + 5px);
  min-width:100%; max-width:min(340px, 78vw); max-height:290px; overflow-y:auto;
  list-style:none; margin:0; padding:5px;
  background:var(--sf-card); border:1px solid var(--mo-sand-2);
  border-radius:var(--r-md); box-shadow:var(--sh-3);
  animation:mo-sel-in .13s ease both;
}
.mo-sel.es-arriba .mo-sel-l{ top:auto; bottom:calc(100% + 5px); }
@keyframes mo-sel-in{ from{ opacity:0; transform:translateY(-4px) } }

.mo-sel-o{
  display:flex; align-items:center; gap:8px;
  padding:7px 9px; border-radius:var(--r-sm);
  font-size:12.5px; color:var(--tx-1); cursor:pointer;
}
.mo-sel-o span{ flex:1 1 auto; min-width:0; overflow-wrap:anywhere; }
.mo-sel-o.es-foco{ background:var(--mo-paper); }
.mo-sel-o.es-on{ font-weight:600; }
.mo-sel-ok{ width:15px; height:15px; flex:0 0 auto; opacity:0; color:var(--mo-steel-d); }
.mo-sel-o.es-on .mo-sel-ok{ opacity:1; }

/* --- Modal con velo de VIDRIO -------------------------------------------
   El estándar pide DIFUMINAR el fondo, no taparlo. Un velo oscuro plano en
   tema claro apaga toda la pantalla; aquí el velo toma el color del lienzo y
   el desenfoque hace el trabajo.

   La cabecera NO lleva botón de cierre: las acciones —incluida cancelar— van
   juntas en el pie. Un «Cancelar» arriba y otro abajo son dos caminos para lo
   mismo, y el de arriba compite con el título. */
.mo-mdl-ov{
  position:fixed; inset:0; z-index:210;
  display:flex; align-items:center; justify-content:center;
  padding:26px 18px; overflow-y:auto;
  background:color-mix(in srgb, var(--sf-app) 62%, transparent);
  -webkit-backdrop-filter:blur(16px) saturate(1.4);
  backdrop-filter:blur(16px) saturate(1.4);
  animation:mo-ov-in .16s ease both;
}
@keyframes mo-ov-in{ from{ opacity:0 } }

.mo-mdl{
  width:100%; max-width:520px; margin:auto;
  background:var(--sf-card);
  border:1px solid var(--mo-sand-2); border-radius:var(--r-lg);
  box-shadow:var(--sh-3);
  animation:mo-mdl-in .18s cubic-bezier(.2,.7,.3,1) both;
}
@keyframes mo-mdl-in{ from{ opacity:0; transform:translateY(10px) scale(.985) } }

.mo-mdl-h{ padding:16px 18px 0; }
.mo-mdl-h h2{ font-size:14.5px; font-weight:600; color:var(--tx-1); line-height:1.35;
  overflow-wrap:anywhere; }
.mo-mdl-h p{ font-size:12.5px; color:var(--tx-2); margin-top:3px; }
/* Párrafo de cuerpo de un modal — el texto de un aviso o una confirmación */
.mo-mdl-p{ font-size:13px; color:var(--tx-2); }
.mo-mdl-b{ padding:14px 18px 18px; }
.mo-mdl-f{
  display:flex; justify-content:flex-end; gap:8px; flex-wrap:wrap;
  padding:14px 18px; border-top:1px solid var(--mo-sand);
}

/* ---------------------------------------------------------------------------
   11. RESPONSIVE

   Ninguna vista se da por terminada sin comprobarla en móvil. Se comprueba a
   1440, 1024, 768 y 390 px de ancho, y en un caso apaisado (740x360).
   Al reducir se sacrifica lo DECORATIVO, nunca lo funcional.
   -------------------------------------------------------------------------*/

/* --- Escritorio estrecho y tableta apaisada --- */
@media (max-width:1100px){
  .sh-sec{ padding:0 var(--hueco) 44px; }
}

/* --- Tableta ------------------------------------------------------------
   El menú se contrae a iconos, pero eso YA NO SE DECIDE AQUÍ.

   ⚠️  Antes esta consulta encogía la columna del menú y dejaba el aspecto
   contraído colgando de `.sh-mini`, una clase que en esta franja NO está
   puesta. Resultado medido: panel de 66 px con 130 px de contenido dentro —
   el nombre de la marca y las etiquetas recortados contra el borde. Y para
   arreglarlo había que invertir el significado de la clase justo en este
   corte, lo que obligaba a escribir cada regla dos veces, con la condición
   al revés.

   Ahora manda una sola clase con un único significado —`.sh-mini` = el menú
   enseña solo iconos— y quien la pone o la quita es shell.js, que conoce el
   ancho y también lo que ha pulsado el usuario. La hoja de estilos define el
   aspecto una vez y no se contradice.                                      */
@media (max-width:860px){
  .sh-user-t span{ display:none; }        /* el cargo sobra en poco espacio */
  .cv-out{ gap:10px; }
}

/* --- Móvil: el menú pasa a panel deslizante ------------------------------
   Contraído a iconos ya no sirve: con 68 px de menú el contenido se queda sin
   ancho útil. Se saca de la rejilla y se desliza sobre el contenido.       */
@media (max-width:720px){
  /* El hueco se reduce, pero NO desaparece: la regla es que ningún panel
     toque un borde, también en móvil. Se cambia el valor, no la regla. */
  :root{ --hueco:8px; --hueco-sup:8px; }

  .sh-app,
  body.sh-mini .sh-app{ grid-template-columns:minmax(0,1fr); }

  .sh-side{
    position:fixed; top:0; bottom:0; left:0; z-index:120;
    width:min(84vw, var(--side-w));
    transform:translateX(-100%);
    transition:transform .24s ease;
    border-radius:0; border-width:0 1px 0 0;
    box-shadow:0 0 40px rgba(0,0,0,.28);
  }
  body.sh-menu-abierto .sh-side{ transform:translateX(0); }

  /* velo: deja claro que el menú está por encima y capta el toque de cierre */
  body.sh-menu-abierto .sh-main::before{
    content:''; position:fixed; inset:0; z-index:110;
    background:rgba(10,16,32,.34);
    -webkit-backdrop-filter:blur(2px);
    backdrop-filter:blur(2px);
  }

  /* Aquí no hace falta deshacer nada del aspecto contraído: por debajo de
     720 px el menú se superpone a ancho completo, y shell.js garantiza que
     `.sh-mini` no esté puesta. Una sola fuente de verdad. */

  .sh-top{ padding:0 12px; gap:8px; }
  .sh-sec{ padding:0 var(--hueco) 36px; }
  .sh-sec-head h1{ font-size:19px; }
  .cv-drop{ padding:26px 18px; }
}

/* --- Móvil pequeño --- */
@media (max-width:480px){
  .sh-sec-head h1{ font-size:18px; }
  .sh-sec-head p{ font-size:12.5px; }
  .kpi-row{ grid-template-columns:minmax(0,1fr); gap:10px; }
  .kpi-v{ font-size:26px; }
  .sh-user-t{ display:none; }                 /* solo el avatar */
  .sh-user{ padding:4px; }
  /* Los campos suben a 16 px: por debajo, iOS hace zoom al enfocar */
  .fld input,.fld textarea,.mo-busca input{ font-size:16px; }
  .pl-bar{ gap:6px; }
  .pl-bar .btn{ flex:1 1 auto; }
  .pl-hint{ display:none; }
  .cta-salir .card-b{ flex-direction:column; align-items:stretch; }
  /* las tablas de índice se desplazan dentro de su caja, no rompen la página */
  .lst-wrap{ overflow-x:auto; }
  .lst{ min-width:520px; }
  .cv-out{ flex-direction:column; align-items:stretch; }
  .cv-out .cv-fmt{ overflow-x:auto; }
  .cv-out-sp{ display:none; }
  /* el modal ocupa la pantalla: ceñirlo al contenido no tiene sentido aquí */
  .mo-mdl{ max-width:100%; }
  .mo-mdl-b{ padding:12px; }
  .mo-mdl-f .btn{ flex:1 1 auto; }
}

/* --- Móvil apaisado o ventana baja --- */
@media (max-height:560px) and (max-width:900px){
  .cv-drop{ padding:18px 16px; }
  .cv-drop em{ display:none; }        /* decorativo: se sacrifica primero */
}

/* --- Informe del PDF inteligente ------------------------------------------
   Sale en un modal después de generar. Enseña las nueve comprobaciones de
   Autodesk resueltas, más el error de ajuste, que es el número que delata una
   calibración mala antes de que nadie abra el archivo. */
.cv-informe{ list-style:none; margin:0; padding:0; }
.cv-informe > li{
  padding:12px 0; border-bottom:1px solid var(--mo-line-2);
}
.cv-informe > li:last-child{ border-bottom:0; }
.cv-informe > li > b{ margin-right:8px; overflow-wrap:anywhere; }
.cv-informe-l{
  font-size:11.5px; color:var(--tx-2); margin-top:5px; line-height:1.6;
}
.cv-informe-l b{ color:var(--tx-1); font-weight:600; }

/* --- Visor del PDF ya generado -------------------------------------------
   El lector es el del propio navegador dentro de un <iframe>: reimplantar uno
   saldría peor y no aporta nada. Alto en `vh` para que quepa en pantallas
   bajas sin desbordar el modal. */
.cv-visor{
  display:block; width:100%; height:min(66vh, 640px);
  border:1px solid var(--mo-sand); border-radius:var(--r-md);
  background:var(--mo-paper-2);
}

/* --- Zona de carga · estado CON archivos ---------------------------------
   La misma pieza enseña la invitación cuando está vacía y lo cargado cuando
   no. Eran dos bloques —una tabla encima y el recuadro debajo— para una sola
   cosa, y el recuadro seguía invitando a soltar algo que ya estaba puesto. */
.cv-drop-c{
  display:flex; flex-direction:column; align-items:center;
  width:100%; min-width:0;
}
.cv-drop.es-lleno{
  padding:14px; cursor:default;
  border-style:solid; border-color:var(--mo-sand);
  background:var(--sf-card);
  /* El cartel va centrado; una lista de nombres, no. Sin esto los archivos
     salían centrados y el ojo no encontraba dónde empieza cada línea. */
  text-align:left;
}
.cv-drop.es-lleno .cv-drop-c{ align-items:stretch; }

.cv-lista{ list-style:none; margin:0; padding:0; width:100%; }
.cv-item{
  display:flex; align-items:center; gap:11px;
  padding:9px 6px; min-width:0;
  border-bottom:1px solid var(--mo-line-2);
}
.cv-item:last-child{ border-bottom:0; }
.cv-item-ico{ color:var(--tx-3); flex:0 0 18px; }
.cv-item-t{ flex:1 1 auto; min-width:0; }
.cv-item-n{
  display:block; font-size:13px; font-weight:500; color:var(--tx-1);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.cv-item-e{ display:block; font-size:11.5px; color:var(--st-crit-fg); margin-top:1px; }

/* Cómo añadir más, sin repetir el cartel entero */
.cv-mas{
  display:block; text-align:center; font-size:11.5px; color:var(--tx-3);
  margin-top:10px; padding-top:10px; border-top:1px dashed var(--mo-sand-2);
  cursor:pointer;
}
