/* ===========================================================================
   TIPOGRAFÍA · IBM Plex, alojada en el propio servidor (28/07/2026)
   ---------------------------------------------------------------------------
   Antes el CSS pedia Roboto y Roboto Mono sin servirlas ni enlazarlas: solo
   se veian si el sistema operativo las tenia instaladas. En macOS y iOS no
   están, y en Windows tampoco de serie, así que buena parte del equipo veía
   Helvetica y Courier. Ahora van dentro del proyecto.

   Por qué Plex: es una superfamilia — Sans, Sans Condensed y Mono comparten
   esqueleto—, así que tres roles con un solo criterio tipográfico. La Mono
   tiene cifras de ancho fijo de verdad, que es lo que necesitan las columnas
   de importes. Licencia SIL Open Font, sin coste ni atribución en pantalla.

   Sans        400/500/600/700 · interfaz
   Sans Cond.  600             · cabeceras de tabla y antetítulos
   Mono        400/500/600     · cifras, códigos, fechas

   font-display:swap → el texto se ve desde el primer momento con la fuente del
   sistema y se recompone al llegar la Plex; nunca hay pantalla en blanco.
   El unicode-range hace que latin-ext solo se descargue si aparece un carácter
   que lo necesite: de arranque son 44 KB, no 418.
   ======================================================================== */
@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;
  src:url('fonts/plex-sans-400-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:400;font-display:swap;
  src:url('fonts/plex-sans-400-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;
  src:url('fonts/plex-sans-500-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:500;font-display:swap;
  src:url('fonts/plex-sans-500-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;
  src:url('fonts/plex-sans-600-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:600;font-display:swap;
  src:url('fonts/plex-sans-600-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:700;font-display:swap;
  src:url('fonts/plex-sans-700-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'IBM Plex Sans';font-style:normal;font-weight:700;font-display:swap;
  src:url('fonts/plex-sans-700-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'IBM Plex Sans Condensed';font-style:normal;font-weight:600;font-display:swap;
  src:url('fonts/plex-sans-condensed-600-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'IBM Plex Sans Condensed';font-style:normal;font-weight:600;font-display:swap;
  src:url('fonts/plex-sans-condensed-600-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url('fonts/plex-mono-400-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url('fonts/plex-mono-400-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;
  src:url('fonts/plex-mono-500-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;
  src:url('fonts/plex-mono-500-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;
  src:url('fonts/plex-mono-600-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;
  src:url('fonts/plex-mono-600-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ===========================================================================
   SISTEMA DE TOKENS (28/07/2026)
   ---------------------------------------------------------------------------
   Antes había 23 tamaños de letra en esta hoja y 21 más en los estilos en
   línea de las vistas: once escalones entre 9 y 14 px. Medio punto no crea
   jerarquía, crea ruido. Y once radios de esquina, de 3 a 12. Aquí se fija el
   sistema: ocho tamaños, tres radios, tres pesos, cuatro superficies.

   Los nombres antiguos NO desaparecen: 854 estilos en línea repartidos por las
   vistas los usan. Se redefinen abajo en función de los nuevos, así que una
   vista migrada y una sin migrar conviven en producción sin verse rotas —solo
   distintas—. Eso es lo que permite migrar de una en una y parar cuando se
   quiera, sin quedarse a medias de forma visible.
   ======================================================================== */
:root{
  /* --- anclas de marca: no se tocan (documento 60) --- */
  --azul:#3163B3; --navy:#1F3E70; --navy2:#193259;
  --chrome:#17304F;                      /* barra lateral: un punto bajo el navy */

  /* --- superficies: la separación la hace el tono, no la línea --- */
  --lienzo:#EEF1F7;                      /* fondo de página */
  --papel:#FFFFFF;                       /* tarjetas */
  --hundido:#E4E9F2;                     /* cabeceras de tabla, pozos, segmentados */

  /* --- tinta: cuatro pasos, con matiz azul para que pertenezca a la familia --- */
  --tinta:#0E1626;                       /* texto principal      18,1:1 sobre blanco */
  --t60:#4C5A70;                         /* texto secundario      7,0:1 */
  --t45:#67768F;                         /* apuntes y pies        4,6:1 */
  --t25:#AEB8C8;                         /* deshabilitado, guiones */
  --t12:#D7DEEA;                         /* filetes */
  --pizarra:#526884;                     /* «en trámite»: ni verde ni granate ni gris muerto */

  /* --- semántica: heredada, con los pares de texto ajustados a 4,5:1 --- */
  --verde:#63B331;   --verde-osc:#3A6B1D;   --verde-t:#E9F4E1;
  --granate:#B33163; --granate-osc:#6E1E3D; --granate-t:#F7E6ED;
  --amarillo:#F2C744; --mostaza:#80661F;    --ambar-t:#FCF3DA;

  /* --- escala tipográfica: ocho pasos --- */
  --t-micro:10px; --t-min:11px; --t-apunte:12px; --t-base:13px;
  --t-cuerpo:15px; --t-sec:18px; --t-tit:24px; --t-cifra:34px;

  /* --- pesos: tres. Plex llega a 700; pedir más da negrita sintética --- */
  --p-normal:400; --p-medio:500; --p-fuerte:600; --p-max:700;

  /* --- radios: tres --- */
  --r-ctrl:4px; --r-caja:10px; --r-pill:999px;

  /* --- elevación --- */
  --e1:0 1px 2px rgba(14,22,38,.05), 0 6px 18px -10px rgba(14,22,38,.16);
  --e2:0 2px 4px rgba(14,22,38,.06), 0 18px 40px -18px rgba(14,22,38,.28);

  /* =======================================================================
     Compatibilidad. Los nombres de abajo siguen vivos porque los usan los
     estilos en línea de las vistas aún sin migrar. Conforme una vista se
     migra, sus usos pasan a los nombres de arriba; cuando no quede ninguno,
     este bloque se retira entero.
     ==================================================================== */
  --panel:var(--lienzo);
  --tinte:#E5EBF5; --tinte2:#CBD8EC;
  --verde-claro:var(--verde-t); --granate-claro:var(--granate-t); --amarillo-claro:var(--ambar-t);
  --g60:var(--t60); --g40:var(--t45); --g20:#C0CAD9; --g15:var(--t12); --g08:#EAEEF5;
}
*{box-sizing:border-box;margin:0}
body{font-family:'IBM Plex Sans',system-ui,-apple-system,'Segoe UI',sans-serif;font-size:14px;color:var(--tinta);background:var(--panel);
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
/* Cifras de ancho fijo en todo lo que sea número: las columnas de importes
   alinean por sí solas y una cifra no baila al cambiar de valor. */
.mono,table.list td,table.list th,.kpi .val,.num{font-variant-numeric:tabular-nums}
h1,h2,h3{color:var(--navy);font-weight:700}
a{color:var(--azul);text-decoration:none}
button{font-family:'IBM Plex Sans';cursor:pointer}
.mono{font-family:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace}
/* 28/07/2026: cada pie explicativo empezaba con el carácter ℹ escrito en el
   texto —143 veces—. Cada sistema operativo lo dibuja distinto y en algunos
   sale a color. Ahora lo pone el CSS: un icono del mismo trazo que el resto,
   un solo sitio donde cambiarlo, y el texto queda limpio para copiarlo. */
.hint{font-size:var(--t-min);line-height:1.55;color:var(--t60);margin-top:4px}
.hint.pie{position:relative;padding-left:19px}
.hint.pie::before{content:"";position:absolute;left:0;top:2px;width:13px;height:13px;opacity:.65;
  background:no-repeat center/13px url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234C5A70' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 11v5.4M12 7.8v.1'/%3E%3C/svg%3E")}
/* 26/07/2026: el pie explicativo pasa de #868686 a #585857. Sobre blanco, el
   gris anterior daba 3,64:1, por debajo del 4,5:1 exigible a texto normal; el
   nuevo da 7,12:1. Es el elemento que más doctrina lleva del aplicativo —21
   pies en Facturación, 21 en CRM— y se leía a media luz. */
.spacer{flex:1}

/* ===========================================================================
   ACCESO (28/07/2026)
   ---------------------------------------------------------------------------
   Antes: degradado azul, un círculo blanco de relleno y una tarjeta centrada.
   Era lo más de plantilla que quedaba en el aplicativo.

   Ahora la pantalla se parte. A la izquierda, el navy del chrome —el mismo de
   la barra lateral, para que entrar no sea un salto de color— con el imagotipo
   DESPLEGADO: la marca es un cuadrado redondeado con otro encajado en su
   esquina inferior derecha, y aquí ocho escuadras comparten esa misma esquina
   y crecen hasta salirse del panel. La más pequeña es el cuadrado verde del
   logotipo; la mayor no cabe en pantalla. No es un adorno derivado de la
   marca: es la construcción del símbolo a escala de arquitectura.

   A la derecha, el formulario en tarjeta blanca sobre el lienzo, que es la
   superficie de todo el resto de la aplicación: entrar y estar dentro tienen
   que parecer el mismo sitio.
   ======================================================================== */
.acceso{display:grid;grid-template-columns:1.32fr 1fr;min-height:100vh}

/* ------------------------------------------------------ panel de la marca */
.acc-panel{position:relative;background:var(--chrome);color:#fff;overflow:hidden;
  display:flex;flex-direction:column;justify-content:space-between;padding:52px 56px 44px}
.acc-panel > *{position:relative;z-index:3}
/* Pautado del expediente, apenas perceptible. */
.acc-panel::before{content:"";position:absolute;inset:0;z-index:0;
  background-image:linear-gradient(rgba(255,255,255,.032) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(255,255,255,.032) 1px,transparent 1px);
  background-size:48px 48px}
/* Luz baja a la derecha, hacia donde converge el símbolo. */
.acc-panel::after{content:"";position:absolute;right:-18%;bottom:-34%;width:1100px;height:1100px;z-index:1;
  background:radial-gradient(circle,rgba(49,99,179,.42),rgba(49,99,179,.10) 42%,rgba(49,99,179,0) 68%)}

/* Escuadras, no cajas: con cajas completas los ocho bordes derechos y los ocho
   inferiores caían en la misma línea y se apilaban en un trazo casi blanco.
   Abiertas hacia la esquina no se superpone ninguno y el ojo cierra la figura.
   El grosor y el estilo van aquí; el COLOR lo pone cada escuadra, porque el
   atajo «border:1px solid» sin color fija currentColor —blanco en este panel—
   y gana por especificidad a las clases de abajo. */
.acc-marcos{position:absolute;z-index:2;right:23%;bottom:26%;width:0;height:0}
.acc-marcos span{position:absolute;right:0;bottom:0;display:block;
  border-width:1px 0 0 1px;border-style:solid;border-radius:28% 0 0 0}
.acc-k1{width:34px;height:34px;background:var(--verde);border:none;border-radius:9px}
.acc-k2{width:120px;height:120px;border-color:rgba(255,255,255,.34);background:rgba(255,255,255,.045)}
.acc-k3{width:232px;height:232px;border-color:rgba(255,255,255,.24)}
.acc-k4{width:392px;height:392px;border-color:rgba(255,255,255,.17);background:rgba(49,99,179,.14)}
.acc-k5{width:610px;height:610px;border-color:rgba(255,255,255,.125)}
.acc-k6{width:890px;height:890px;border-color:rgba(255,255,255,.09)}
.acc-k7{width:1240px;height:1240px;border-color:rgba(255,255,255,.05)}
.acc-k8{width:1660px;height:1660px;border-color:rgba(255,255,255,.035)}

.acc-panel .lockup .mark{width:48px;height:48px;border-radius:14px;background:#fff;position:relative}
.acc-panel .lockup .mark::after{content:"";position:absolute;right:8px;bottom:8px;width:15px;height:15px;
  border-radius:4px;background:var(--verde)}
.acc-panel .lockup{gap:15px}
.acc-panel .lockup .wordmark{font-size:40px;letter-spacing:-.032em;color:#fff}
.acc-rotulo{font-family:'IBM Plex Sans Condensed','IBM Plex Sans',sans-serif;font-size:var(--t-min);
  font-weight:var(--p-fuerte);letter-spacing:.22em;color:rgba(255,255,255,.58);margin-top:15px}
.acc-pie{display:flex;align-items:flex-end;justify-content:space-between;gap:28px}
.acc-pie .soc{font-family:'IBM Plex Mono',ui-monospace,monospace;font-size:var(--t-min);
  letter-spacing:.18em;color:rgba(255,255,255,.52)}
.acc-pie .nota{font-size:var(--t-min);color:rgba(255,255,255,.52);text-align:right;line-height:1.65}

/* ------------------------------------------------------------- formulario */
.acc-forma{display:flex;align-items:center;justify-content:center;padding:44px 40px}
.acc-caja{width:100%;max-width:396px;background:var(--papel);border-radius:var(--r-caja);
  box-shadow:0 2px 6px rgba(14,22,38,.07),0 28px 60px -26px rgba(14,22,38,.42);padding:38px 36px 30px}
.acc-caja h1{font-size:var(--t-tit);font-weight:var(--p-fuerte);letter-spacing:-.02em;
  color:var(--navy);line-height:1.15}
.acc-bajada{font-size:var(--t-base);color:var(--t60);margin-top:7px;margin-bottom:28px}
.acc-caja .field{margin-bottom:16px}
.acc-caja .field input{font-size:var(--t-cuerpo);padding:11px 13px}
.acc-caja .field input:focus{border-color:var(--azul);outline:none;box-shadow:0 0 0 3px rgba(49,99,179,.16)}
/* Aviso de bloqueo de mayúsculas: la causa más común de no poder entrar. */
.acc-mayus{display:none;align-items:center;gap:6px;margin-top:7px;font-size:var(--t-min);color:var(--mostaza)}
.acc-mayus.on{display:flex}
.acc-entrar{width:100%;margin-top:12px;border:none;border-radius:var(--r-ctrl);background:var(--azul);
  color:#fff;font-family:'IBM Plex Sans',system-ui,sans-serif;font-size:var(--t-cuerpo);
  font-weight:var(--p-fuerte);padding:12px 16px;cursor:pointer;transition:background .15s,box-shadow .15s}
.acc-entrar:hover{background:var(--navy);box-shadow:0 8px 20px -10px rgba(31,62,112,.7)}
.login-error{background:var(--granate-t);color:var(--granate-osc);border-left:3px solid var(--granate);
  border-radius:var(--r-ctrl);padding:10px 13px;font-size:var(--t-apunte);margin-bottom:20px;line-height:1.5}
.acc-pieF{margin-top:24px;padding-top:16px;border-top:1px solid var(--t12);
  font-size:var(--t-apunte);color:var(--t60);line-height:1.6}

@media(max-width:900px){
  .acceso{grid-template-columns:1fr}
  .acc-panel{padding:28px 26px 24px;min-height:auto}
  .acc-panel .acc-pie{display:none}
  .acc-marcos{right:-6%;bottom:-120%}
  .acc-panel .lockup .mark{width:34px;height:34px;border-radius:10px}
  .acc-panel .lockup .mark::after{right:6px;bottom:6px;width:10px;height:10px;border-radius:3px}
  .acc-panel .lockup .wordmark{font-size:28px}
  .acc-rotulo{margin-top:9px;font-size:var(--t-micro);letter-spacing:.18em}
  .acc-forma{align-items:flex-start;padding:26px 20px 40px}
  .acc-caja{max-width:none;padding:28px 24px 24px;box-shadow:var(--e1)}
}

/* shell */
#shell{display:grid;grid-template-columns:222px 1fr;min-height:100vh}
aside{background:var(--chrome);color:#fff;padding:20px 0;position:sticky;top:0;height:100vh;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.28) transparent}
.aside-brand{padding:0 20px 16px;border-bottom:1px solid rgba(255,255,255,.12);margin-bottom:12px}
.aside-brand .b{font-weight:700;font-size:var(--t-sec)}
.aside-brand .b .dot{color:var(--verde)}
.aside-brand .s{font-family:'IBM Plex Sans Condensed','IBM Plex Sans',sans-serif;font-size:var(--t-micro);
  font-weight:600;letter-spacing:.14em;color:rgba(255,255,255,.55);margin-top:4px}
/* 28/07/2026: el icono deja de ser un carácter dentro del texto y pasa a ser
   un SVG propio, así que la fila necesita su propia caja y su alineación. */
nav a{display:flex;align-items:center;gap:10px;padding:9px 20px;color:var(--tinte2);font-size:var(--t-base);font-weight:500}
nav a .ic{flex:none;opacity:.72;transition:opacity .15s}
nav a:hover .ic{opacity:1}
nav a.on .ic{opacity:1}
nav a:hover{background:rgba(255,255,255,.06);color:#fff}
nav a.on{background:rgba(255,255,255,.12);color:#fff;border-left:3px solid var(--verde);padding-left:17px;font-weight:600}
main{padding:0 28px 40px}
.topbar{display:flex;align-items:center;gap:14px;padding:18px 0 16px;border-bottom:none;
  margin-bottom:18px;background:var(--lienzo);position:sticky;top:0;z-index:5}
.topbar h1{font-size:var(--t-sec);font-weight:var(--p-fuerte);letter-spacing:-.015em;flex:1}
.provswitch{display:flex;border:none;border-radius:var(--r-ctrl);overflow:hidden;background:var(--hundido);padding:2px}
.provswitch a{padding:5px 12px;font-size:var(--t-apunte);font-weight:var(--p-medio);color:var(--t60);border-radius:var(--r-ctrl)}
.provswitch a.on{background:var(--papel);color:var(--navy);font-weight:var(--p-fuerte);box-shadow:0 1px 2px rgba(14,22,38,.10)}
.userchip{display:flex;align-items:center;gap:8px;font-size:var(--t-apunte);color:var(--g60)}
.card h3 img{border:1px solid var(--g15)}
.userchip .av{width:30px;height:30px;border-radius:50%;background:var(--tinte);color:var(--navy);
  font-weight:700;display:flex;align-items:center;justify-content:center;font-size:var(--t-apunte)}

/* componentes */
.grid{display:grid;gap:16px}
.g4{grid-template-columns:repeat(4,1fr)}.g3{grid-template-columns:repeat(3,1fr)}.g2{grid-template-columns:repeat(2,1fr)}
.gfit{grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:12px}
.kpi.sm{padding:12px 14px}
.kpi.sm .lab{font-size:var(--t-min)}
.kpi.sm .val{font-size:var(--t-tit);margin-top:2px}
.kpi.sm .sub{font-size:var(--t-micro);margin-top:2px}
/* 28/07/2026: la tarjeta deja de dibujarse con un filete de 1 px y pasa a
   separarse por superficie y elevación. Con veinte tarjetas en pantalla, el
   filete convertía la página en una retícula de cajas iguales. */
.card{background:var(--papel);border:none;border-radius:var(--r-caja);padding:18px 20px;box-shadow:var(--e1)}
.kpi .lab{font-size:var(--t-micro);font-weight:var(--p-fuerte);letter-spacing:.14em;text-transform:uppercase;color:var(--t45)}
.kpi .val{font-size:var(--t-tit);font-weight:var(--p-fuerte);letter-spacing:-.025em;color:var(--navy);margin-top:5px;line-height:1.12}
.kpi .val small{font-size:var(--t-base);font-weight:var(--p-normal);color:var(--t45)}
.kpi .sub{font-size:var(--t-min);color:var(--t60);margin-top:4px}
.kpi.warn .lab{color:var(--granate)}.kpi.warn .val{color:var(--granate-osc)}
.kpi.sm .lab{font-size:var(--t-min)}
/* El título de tarjeta sale de versalitas: eran nueve elementos distintos
   gritando a la vez y ninguno destacaba. Se queda la cabecera de tabla. */
.card h3{font-size:var(--t-apunte);font-weight:var(--p-fuerte);letter-spacing:.01em;text-transform:none;
  color:var(--navy);margin-bottom:14px;padding-bottom:0;border-bottom:none}
/* Barra de avance. Se usa en doce sitios para lo mismo: una parte sobre un
   todo. El fondo pasa a --hundido para que la parte vacía también se lea como
   dato —cuánto falta— y no como hueco. */
.bar{height:8px;background:var(--hundido);border-radius:var(--r-pill);overflow:hidden;margin:5px 0 2px}
.bar i{display:block;height:100%;background:var(--azul);border-radius:var(--r-pill);transition:width .3s ease}
.bar i.v{background:var(--verde)}
.bar i.g{background:var(--granate)}
.bar i.a{background:var(--amarillo)}
.brow{display:flex;justify-content:space-between;font-size:var(--t-apunte);color:var(--g60);margin-top:8px}
.brow b{color:var(--navy)}
table.list{width:100%;border-collapse:separate;border-spacing:0;font-size:var(--t-base)}
/* 28/07/2026: la cabecera llevaba white-space:nowrap y obligaba a la columna a
   ser al menos tan ancha como su rótulo. «Entregados válidos» o «Máx.
   facturable» son más largos que el dato que encabezan. Partiendo en dos
   líneas, la columna se ajusta al dato. Las flechas de orden no se separan del
   rótulo. */
table.list th{text-align:left;font-family:'IBM Plex Sans Condensed','IBM Plex Sans',sans-serif;
  font-size:var(--t-micro);font-weight:var(--p-fuerte);letter-spacing:.06em;text-transform:uppercase;
  color:var(--t60);padding:8px 11px;background:var(--hundido);border:none;
  white-space:normal;line-height:1.3;vertical-align:bottom}
table.list th .flechas{white-space:nowrap}
table.list thead th:first-child{border-radius:var(--r-ctrl) 0 0 var(--r-ctrl)}
table.list thead th:last-child{border-radius:0 var(--r-ctrl) var(--r-ctrl) 0}
table.list td{padding:10px 11px;border-bottom:1px solid var(--lienzo);vertical-align:middle}
table.list tbody tr:last-child td{border-bottom:none}
table.list tbody tr:hover td{background:#F8FAFD}
/* ===========================================================================
   DISTINTIVOS · dos familias, no cuatro
   ---------------------------------------------------------------------------
   .chip   → ESTADO de una fila: cobrada, pendiente, en riesgo, presentado…
   .fuente → PROCEDENCIA del dato: de dónde sale la cifra que estás leyendo.

   Son conceptos distintos y por eso siguen siendo dos familias, pero comparten
   geometría: misma altura, mismo radio de píldora, Condensed en versalitas y
   sin borde. Antes .src y .tag2 vivían en un <style> dentro de fact.php, con
   borde propio y radios de 12 y 20 px que no salían de ningún token.
   ======================================================================== */
.fuente,.src,.tag2{display:inline-flex;align-items:center;
  font-family:'IBM Plex Sans Condensed','IBM Plex Sans',sans-serif;
  font-size:var(--t-min);font-weight:var(--p-fuerte);letter-spacing:.06em;text-transform:uppercase;
  padding:2px 9px;border-radius:var(--r-pill);white-space:nowrap;border:none;vertical-align:middle}
.f-tal,.src-tal,.tag-tal{background:#E7EDF5;color:var(--navy)}
.f-hol,.src-hol,.tag-hol{background:var(--granate-t);color:var(--granate-osc)}
.f-mix,.src-mix,.tag-mix{background:var(--ambar-t);color:var(--mostaza)}
/* En las tarjetas, la procedencia va anclada arriba a la derecha. */
.card .src{position:absolute;top:12px;right:12px}
.card:has(> .src){position:relative}

/* ---------------------------------------------------------------------------
   TIPO de ausencia · familia propia (28/07/2026)
   ---------------------------------------------------------------------------
   El tipo se pintaba con .chip c-ok, o sea VERDE — el mismo verde que el estado
   «Aceptada» de la columna de al lado. Dos cosas distintas del mismo color, y
   además los diez tipos compartían uno solo, así que la columna no distinguía
   nada.

   Aquí el tipo deja de competir con el estado: fondo neutro y un punto de color
   que identifica la FAMILIA. El estado se queda con la semántica de siempre
   —verde aceptada, ámbar pendiente, granate denegada— y no hay dos verdes.

   Las familias no son arbitrarias, salen de lo que la ausencia significa:
     · descanso  planificado, consume cupo   → ámbar
     · salud     imprevisto, consume cupo    → azul
     · fuera     se trabaja en otro sitio,
                 NO consume cupo (computa=0) → verde
     · otros                                 → gris
   ------------------------------------------------------------------------- */
/* Ausencia sin fecha de fin: sigue en curso. Se marca en ambar porque es algo
   que hay que cerrar, no un estado estable. */
/* Bloque de entrega de la justificativa, bajo los costes indirectos. */
/* ===========================================================================
   Calendario visual · cuatro meses en una fila (28/07/2026)
   ---------------------------------------------------------------------------
   Cuatro meses caben holgados a lo ancho de la tarjeta. Por debajo de 1100 px
   pasan a dos y dos, y en movil a uno debajo de otro: nunca se encogen tanto
   que el numero deje de leerse.
   ======================================================================== */
.calmes-caja{min-width:0}
.calmes-tit{text-align:center;font-family:'IBM Plex Sans Condensed','IBM Plex Sans',sans-serif;
  font-size:var(--t-min);font-weight:var(--p-fuerte);letter-spacing:.10em;text-transform:uppercase;
  color:var(--t60);margin-bottom:8px}
.calfila{display:grid;grid-template-columns:repeat(4,1fr);gap:22px;align-items:start}
@media(max-width:1100px){.calfila{grid-template-columns:repeat(2,1fr);gap:18px}}
@media(max-width:560px){.calfila{grid-template-columns:1fr}}

/* Cola de campañas: los siete lotes del día como una tira de horas. Verde lo
   servido, azul lo que está saliendo, gris lo pendiente. Se lee de un vistazo
   por dónde va la jornada sin abrir nada. */
.lotes{display:flex;gap:8px;flex-wrap:wrap;margin:4px 0 14px}
.lote{flex:1 1 90px;min-width:90px;background:var(--hundido);border-radius:var(--r-ctrl);
  padding:8px 10px;border-left:3px solid var(--t60)}
.lote b{display:block;font-family:'IBM Plex Mono',ui-monospace,monospace;font-size:var(--t-cuerpo);color:var(--tinta)}
.lote span{display:block;font-family:'IBM Plex Mono',ui-monospace,monospace;
  font-size:var(--t-h3);font-weight:var(--p-fuerte);color:var(--navy);line-height:1.1}
.lote i{font-style:normal;font-size:var(--t-min);color:var(--t60)}
.lote.hecho{border-left-color:var(--verde);background:var(--verde-t)}
.lote.hecho span{color:var(--verde-osc)}
.lote.curso{border-left-color:var(--azul);background:var(--papel);box-shadow:inset 0 0 0 1px var(--hundido)}
tr.pausada td{opacity:.55}
.comp td.dch, .comp th.dch{text-align:right}

/* Composición exigida por plan (29/07/2026). Una sola unidad de información
   repetida en las cuatro columnas: etiqueta, lo que FALTA en grande a la
   derecha, y debajo la cuota y lo hecho en gris. Así se recorre la columna
   leyendo solo el déficit, con el detalle a mano sin estorbar. Se evitan los
   chips de color: sirven para estados, y aquí lo que hay son cifras. */
.comp td{vertical-align:top}
.comp .cli{font-weight:var(--p-fuerte);color:var(--tinta);line-height:1.3}
.comp .avance{margin-top:6px;font-size:var(--t-min);color:var(--t60)}
.comp .avance b{color:var(--tinta)}
.comp .barra{height:5px;border-radius:3px;background:var(--hundido);overflow:hidden;margin:6px 0 5px;max-width:150px}
.comp .barra i{display:block;height:100%;background:var(--verde)}
.comp .crit{color:var(--granate);font-weight:var(--p-fuerte)}

.cuota{display:grid;grid-template-columns:1fr auto;align-items:baseline;gap:3px 10px;
  padding:7px 0;border-bottom:1px dashed var(--hundido)}
.cuota:last-child{border-bottom:0}
.cuota .et{font-size:var(--t-apunte);color:var(--tinta);font-weight:var(--p-medio);line-height:1.25}
.cuota .ct{font-size:var(--t-min);color:var(--t60);font-family:'IBM Plex Mono',ui-monospace,monospace}
.cuota .ct.dch{text-align:right}
.cuota .fa{font-family:'IBM Plex Mono',ui-monospace,monospace;font-weight:var(--p-fuerte);
  font-size:var(--t-h3);color:var(--granate);text-align:right;line-height:1}
.cuota .fa.ok{color:var(--verde-osc)}
.cuota .mini2{grid-column:1/-1;font-size:var(--t-min);color:var(--t60);margin-top:2px;line-height:1.35}

/* Territorialidad en rejilla: once comunidades caben sin la mancha de once
   píldoras, ordenadas por lo que más falta. */
.terr{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 18px}
.terr > div{display:flex;justify-content:space-between;align-items:baseline;gap:8px;
  font-size:var(--t-min);padding:3px 0;border-bottom:1px dashed var(--hundido)}
.terr span{color:var(--t60);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.terr b{font-family:'IBM Plex Mono',ui-monospace,monospace;color:var(--granate);font-weight:var(--p-fuerte)}
/* «No consta» no es lo mismo que «no hay»: la primera es una laguna del espejo
   y la segunda una decisión del plan. Se distinguen para que nadie lea un hueco
   de datos como una ausencia de requisito. */
.sindato{display:inline-block;font-size:var(--t-min);color:var(--t60);font-style:italic;
  padding:2px 8px;background:var(--hundido);border-radius:var(--r-ctrl)}

/* Zonas admisibles sin cuota: misma rejilla, pero la cifra no es un déficit
   —es lo ya justificado allí— así que no va en granate. */
.terr.sincuota b{color:var(--t60);font-weight:var(--p-medio)}

.comp .nota{font-size:var(--t-min);color:var(--t60);margin-top:8px;line-height:1.4}

@media (max-width:1100px){ .terr{grid-template-columns:1fr} }

/* Solicitud de presupuesto en la ficha de proveedor. */
.sg-aviso{margin-top:10px;padding:9px 13px;background:var(--hundido);border-radius:var(--r-ctrl);color:var(--t60)}
#sg-cuerpo{font-family:'IBM Plex Mono',ui-monospace,monospace;font-size:var(--t-apunte);
  line-height:1.55;background:var(--papel);white-space:pre}
#sg-asunto{font-weight:var(--p-medio)}

.entrega{margin-top:16px;padding-top:14px;border-top:1px solid var(--lienzo);
  display:flex;flex-direction:column;gap:10px;align-items:flex-start}
.entrega-ok{display:flex;align-items:center;gap:10px;background:var(--verde-t);color:var(--verde-osc);
  border-radius:var(--r-ctrl);padding:10px 14px;width:100%}
.entrega-ok svg{flex:none}
.entrega-ok .mini{color:var(--verde-osc);opacity:.85}

.abierta{display:inline-flex;align-items:center;gap:5px;font-family:'IBM Plex Sans Condensed','IBM Plex Sans',sans-serif;
  font-size:var(--t-min);font-weight:var(--p-fuerte);letter-spacing:.05em;text-transform:uppercase;
  padding:1px 8px;border-radius:var(--r-pill);background:var(--ambar-t);color:var(--mostaza)}
.sinfin{display:inline-flex;align-items:center;gap:7px;font-size:var(--t-apunte);color:var(--t60);cursor:pointer}
.sinfin input{margin:0}

.tipo-aus{display:inline-flex;align-items:center;gap:6px;
  font-family:'IBM Plex Sans Condensed','IBM Plex Sans',sans-serif;
  font-size:var(--t-min);font-weight:var(--p-fuerte);letter-spacing:.05em;text-transform:uppercase;
  padding:2px 10px 2px 8px;border-radius:var(--r-pill);white-space:nowrap;border:none;
  background:var(--hundido);color:var(--t60)}
.tipo-aus::before{content:"";width:7px;height:7px;border-radius:50%;flex:none;background:var(--t25)}
.ta-descanso::before{background:var(--amarillo)}
.ta-salud::before{background:var(--azul)}
.ta-fuera::before{background:var(--verde)}
.ta-otros::before{background:var(--t25)}

.chip{display:inline-flex;align-items:center;gap:5px;font-family:'IBM Plex Sans Condensed','IBM Plex Sans',sans-serif;
  font-size:var(--t-min);font-weight:var(--p-fuerte);letter-spacing:.03em;text-transform:uppercase;
  padding:2px 9px;border-radius:var(--r-pill);white-space:nowrap;border:none}
.c-ok{background:var(--verde-t);color:var(--verde-osc)}
.c-warn{background:var(--ambar-t);color:var(--mostaza)}
.c-crit{background:var(--granate-t);color:var(--granate-osc)}
.c-mut{background:var(--hundido);color:var(--t60)}
.c-info{background:#E7EDF5;color:var(--pizarra)}

/* ===========================================================================
   CARRIL · cadena del dinero (28/07/2026)
   ---------------------------------------------------------------------------
   Sustituye a la fila de cuatro KPI idénticos allí donde las cifras no son
   cuatro magnitudes sueltas sino una sola repartida: emitido = cobrado +
   pendiente. Los anchos son proporcionales al dinero real, así que la
   proporción se lee antes que el número. No es adorno: es la única ecuación
   que la vista declara en su propia cabecera.

   Se usa SOLO cuando las partes suman el todo. Para magnitudes independientes
   siguen valiendo las tarjetas .kpi.
   ======================================================================== */
.carril{background:var(--papel);border-radius:var(--r-caja);box-shadow:var(--e1);padding:20px 22px 18px}
.carril .cab{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap}
.carril .rot{font-size:var(--t-micro);font-weight:var(--p-fuerte);letter-spacing:.14em;
  text-transform:uppercase;color:var(--t45)}
.carril .eq{font-family:'IBM Plex Mono',monospace;font-size:var(--t-min);color:var(--t45);margin-left:auto}
.carril .total{font-size:var(--t-cifra);font-weight:var(--p-fuerte);letter-spacing:-.03em;
  color:var(--navy);line-height:1.12;margin-top:2px;font-variant-numeric:tabular-nums}
.carril .total small{font-size:var(--t-cuerpo);font-weight:var(--p-normal);color:var(--t45);letter-spacing:0}

.carril .barra{display:flex;height:12px;border-radius:var(--r-pill);overflow:hidden;
  margin-top:16px;background:var(--hundido)}
.carril .barra i{display:block;height:100%;min-width:2px}
.carril .barra i.cob{background:var(--verde)}
.carril .barra i.pdt{background:var(--pizarra)}
.carril .barra i.ven{background:var(--granate)}

.carril .ley{display:flex;margin-top:16px;flex-wrap:wrap}
.carril .ley > div{flex:1;min-width:150px;padding-right:18px}
.carril .ley > div + div{padding-left:18px;border-left:1px solid var(--t12)}
.carril .ley .k{display:flex;align-items:center;gap:6px;font-size:var(--t-min);
  font-weight:var(--p-medio);color:var(--t60)}
.carril .ley .k::before{content:"";width:8px;height:8px;border-radius:2px;flex:none;background:var(--t25)}
.carril .ley .cob .k::before{background:var(--verde)}
.carril .ley .pdt .k::before{background:var(--pizarra)}
.carril .ley .ven .k::before{background:var(--granate)}
.carril .ley .v{font-size:var(--t-sec);font-weight:var(--p-fuerte);letter-spacing:-.02em;
  color:var(--tinta);margin-top:4px;font-variant-numeric:tabular-nums}
.carril .ley .ven .v{color:var(--granate-osc)}
.carril .ley .n{font-size:var(--t-min);color:var(--t45);margin-top:2px}
@media(max-width:760px){
  .carril .ley{flex-direction:column;gap:12px}
  .carril .ley > div + div{padding-left:0;border-left:none;border-top:1px solid var(--t12);padding-top:12px}
  .carril .eq{display:none}
}

/* ===========================================================================
   EMBUDO · caída entre hitos (28/07/2026)
   ---------------------------------------------------------------------------
   Antes el embudo era una tabla con una barra de 110 px por fila. La barra
   decía el tamaño de cada hito, pero lo que se decide mirando un embudo no es
   el tamaño de cada peldaño: es CUÁNTO SE PIERDE entre uno y el siguiente, y
   eso había que calcularlo de cabeza restando dos columnas.

   Aquí la caída es un elemento propio, entre peldaño y peldaño. Los anchos van
   en proporción al primer hito, así que la forma del embudo se lee de un
   vistazo y la fuga aparece señalada donde ocurre.
   ======================================================================== */
.embudo{margin:2px 0 0}
.embudo .paso{display:grid;grid-template-columns:1fr 210px;gap:14px;align-items:center}
.embudo .et{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin-bottom:5px}
.embudo .et .h{font-size:var(--t-base);font-weight:var(--p-medio);color:var(--tinta)}
.embudo .via{height:26px;border-radius:var(--r-ctrl);background:var(--hundido);overflow:hidden}
.embudo .via i{display:block;height:100%;background:var(--azul);border-radius:var(--r-ctrl);
  transition:width .3s ease}
.embudo .paso:nth-child(1) .via i{background:var(--navy)}
.embudo .paso .via i.v{background:var(--verde)}
.embudo .cifras{display:flex;align-items:baseline;justify-content:flex-end;gap:12px;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.embudo .cifras .n{font-family:'IBM Plex Mono',monospace;font-size:var(--t-sec);
  font-weight:var(--p-medio);color:var(--tinta);letter-spacing:-.02em}
.embudo .cifras .imp{font-family:'IBM Plex Mono',monospace;font-size:var(--t-base);color:var(--t60)}
.embudo .cifras .vacio{color:var(--t25)}

/* La caída: el dato que antes había que restar de cabeza. */
.embudo .caida{display:flex;align-items:center;gap:7px;padding:5px 0 5px 2px;
  font-size:var(--t-min);color:var(--t45)}
.embudo .caida::before{content:"";width:2px;height:16px;background:var(--t12);
  margin-left:9px;margin-right:6px;flex:none}
.embudo .caida b{font-weight:var(--p-fuerte);color:var(--granate-osc)}
.embudo .caida.nula b{color:var(--verde-osc)}
.embudo .caida .pc{font-family:'IBM Plex Mono',monospace}
@media(max-width:700px){
  .embudo .paso{grid-template-columns:1fr;gap:6px}
  .embudo .cifras{justify-content:flex-start}
}

/* --- Serie compacta: barras comparables dentro de una celda de tabla ------ */
.serie{display:flex;align-items:flex-end;gap:2px;height:22px}
.serie i{display:block;flex:1;min-width:3px;background:var(--tinte2);border-radius:1px}
.serie i.on{background:var(--azul)}
.serie i.alt{background:var(--verde)}

/* itinerario */
.iti{display:flex;align-items:center}
.iti .h{width:22px;height:22px;border-radius:50%;border:2px solid var(--g20);background:#fff;
  display:flex;align-items:center;justify-content:center;font-size:var(--t-micro);color:var(--g40);flex:none}
.iti .h.done{background:var(--verde);border-color:var(--verde);color:#fff}
.iti .h.now{border-color:var(--azul);color:var(--azul);box-shadow:0 0 0 3px var(--tinte)}
.iti .h.alert{background:var(--granate);border-color:var(--granate);color:#fff}
.iti .l{width:14px;height:2px;background:var(--g20);flex:none}
.iti .l.done{background:var(--verde)}

/* formularios */
.searchrow{display:flex;gap:10px;margin-bottom:14px;align-items:center;flex-wrap:wrap}

/* El espacio entre campos sale de aquí y solo de aquí: la rejilla no añade
   separación vertical propia, o dos campos en columna quedaban a 28 px y dos
   en fila a 16. */
.field{margin-bottom:14px}
.field label{display:block;font-size:var(--t-min);font-weight:var(--p-medio);letter-spacing:.01em;
  text-transform:none;color:var(--t60);margin-bottom:5px}
/* .field ya no redefine el control: solo le da el ancho de su columna. Todo lo
   demás —borde, radio, relleno, letra— viene de la regla global, para que un
   campo dentro de .field y otro suelto midan exactamente lo mismo. */
.field input,.field select,.field textarea{width:100%}

/* ===========================================================================
   CONTROLES DE FORMULARIO (28/07/2026)
   ---------------------------------------------------------------------------
   Hasta ahora solo se estilaban los que iban dentro de .field. Los que viven
   sueltos dentro de una tabla —la ficha de persona, los parámetros, media
   docena de sitios más— los pintaba el navegador con su estilo nativo: los
   input cuadrados, los select redondeados, alturas distintas y otra
   tipografía. Se estilan aquí todos, por elemento, para que no dependa de que
   alguien acordase envolverlos.

   Fuera de la regla: casillas, opciones, ficheros y ocultos, que tienen su
   propio dibujo y romperían al recibir borde y relleno.
   ======================================================================== */
/* 28/07/2026: esta regla usaba una cadena de :not() para excluir casillas y
   opciones, y eso le daba especificidad (0,5,1): ganaba a cualquier ajuste por
   clase —los campos del acceso salían a 34 px en vez de 44—. Ahora el estilo
   base va a peso de elemento (0,0,1) y las excepciones se devuelven a su
   dibujo nativo justo debajo. Así cualquier vista puede afinar su control con
   una sola clase. */
input, select, textarea{
  font-family:'IBM Plex Sans',system-ui,sans-serif;font-size:var(--t-base);color:var(--tinta);
  background:var(--papel);border:1px solid var(--g20);border-radius:var(--r-ctrl);
  padding:7px 10px;line-height:1.35;max-width:100%;
  appearance:none;-webkit-appearance:none;
}
/* Casillas, opciones, ficheros, deslizadores y ocultos: dibujo del navegador. */
input[type=checkbox],input[type=radio],input[type=file],input[type=range],input[type=hidden]{
  appearance:auto;-webkit-appearance:auto;border:none;border-radius:0;padding:0;
  background:none;font:inherit;max-width:none}
input[type=checkbox],input[type=radio]{width:auto;height:auto;accent-color:var(--azul)}
input[type=hidden]{display:none}

textarea{line-height:1.55;padding:9px 11px;resize:vertical}
/* La flecha del desplegable la dibuja el navegador y desaparece con appearance:none. */
select{padding-right:30px;
  background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%234C5A70' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6.4 4 4 4-4'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 9px center}
input[type=date],input[type=number]{font-family:'IBM Plex Mono',monospace;font-variant-numeric:tabular-nums}
input:focus,select:focus,textarea:focus{outline:2px solid var(--tinte2);outline-offset:0;border-color:var(--azul)}
input:disabled,select:disabled,textarea:disabled{background:var(--hundido);color:var(--t45)}
input::placeholder,textarea::placeholder{color:var(--t45)}
/* Dentro de una tabla el control compite con la fila: se ajusta al contenido. */
table.list td input:not([type=checkbox]):not([type=radio]),
table.list td select{max-width:100%}

/* ---------------------------------------------------------------- botones */
/* ===========================================================================
   BOTONES (28/07/2026)
   ---------------------------------------------------------------------------
   Había cinco definiciones repartidas por la hoja, .btn-verde declarado tres
   veces y, sobre todo, un fallo: «a.btn{background:var(--g08);color:var(--tinta)}»
   tiene especificidad (0,1,1) y ganaba a .btn-ghost (0,1,0). El resultado era
   que el MISMO .btn-ghost se veía gris si era un <a> y blanco con borde azul
   si era un <button> —«Editar» y «Desactivar» en Parámetros, uno al lado del
   otro—. Aquí el aspecto lo decide la variante, nunca la etiqueta HTML.

   Cinco intenciones y ninguna más:
     .btn-primary  azul macizo    · la acción principal, una por bloque
     .btn-ghost    borde azul     · secundaria
     .btn-verde    verde macizo   · confirmar y exportar
     .btn-danger   borde granate  · destructiva
     .btn-neutro   gris           · terciaria, salir de un paso
     .btn-ic       solo icono     · acción de fila
   ======================================================================== */
.btn{display:inline-block;border:1px solid transparent;border-radius:var(--r-ctrl);
  padding:9px 16px;font-family:'IBM Plex Sans',system-ui,sans-serif;
  font-weight:var(--p-fuerte);font-size:var(--t-base);line-height:1.35;cursor:pointer;
  text-decoration:none;transition:background .15s,border-color .15s,box-shadow .15s}
.btn:disabled,.btn[disabled]{opacity:.5;cursor:not-allowed}
/* Un botón con icono y texto necesita ser caja flexible para que el SVG
   quede alineado con la línea base óptica y no colgando. */
.btn:has(svg){display:inline-flex;align-items:center;gap:6px}
.btn svg{flex:none}
/* Botón de solo icono, para acciones de fila. Cuadrado, del alto de un chip,
   sin texto y con el título como única explicación. Antes era un botón de
   texto con el glifo del sobre dentro: se veía como un pegote y no compartía
   ni grosor de trazo ni color con el resto de la interfaz. */
.btn-ic{display:inline-flex;align-items:center;justify-content:center;width:26px;height:22px;
  padding:0;border:1px solid var(--t12);border-radius:var(--r-ctrl);background:var(--papel);
  color:var(--t60);cursor:pointer;vertical-align:middle;transition:all .15s}
.btn-ic:hover{border-color:var(--azul);color:var(--azul);background:#F4F7FC}
.btn-ic svg{display:block}

.btn-verde,a.btn-verde{background:var(--verde);color:#fff;border-color:var(--verde)}
.btn-verde:hover,a.btn-verde:hover{background:var(--verde-osc);border-color:var(--verde-osc);color:#fff}
/* .btn-ico era una sexta variante que solo cambiaba el relleno. Retirada:
   el tamaño de botón dentro de tabla ya lo fija table.list td .btn. */
.btn-ico{padding:7px 12px}
/* En una tabla el botón va a media escala: con el tamaño de formulario, dos
   acciones no caben en la celda y la fila crece al doble. */
table.list td .btn{padding:5px 11px;font-size:var(--t-apunte);vertical-align:middle}
table.list td .btn + .btn,
table.list td .btn + form,
table.list td form + form{margin-left:6px}
/* La celda de acciones no parte: sus botones van en una línea y la columna se
   ensancha lo que haga falta. Partiendo, dos acciones doblaban el alto de la
   fila y el bloque quedaba encaramado sobre la fila de al lado. */
table.list td:has(> .btn){white-space:nowrap}
table.list td:has(> .btn) > form{display:inline-block;vertical-align:middle}
.btn-primary,a.btn-primary{background:var(--azul);color:#fff;border-color:var(--azul)}
.btn-primary:hover,a.btn-primary:hover{background:var(--navy);border-color:var(--navy);color:#fff}
.btn-ghost,a.btn-ghost{background:var(--papel);color:var(--azul);border-color:var(--azul)}
.btn-ghost:hover,a.btn-ghost:hover{background:#F1F5FB;color:var(--navy);border-color:var(--navy)}
.btn-danger,a.btn-danger{background:var(--papel);color:var(--granate-osc);border-color:var(--granate)}
.btn-danger:hover,a.btn-danger:hover{background:var(--granate-t);color:var(--granate-osc)}
.btn-neutro,a.btn-neutro{background:var(--hundido);color:var(--t60);border-color:transparent}
.btn-neutro:hover,a.btn-neutro:hover{background:var(--t12);color:var(--tinta)}
.inlineform{background:var(--panel);border:1px dashed var(--g20);border-radius:var(--r-caja);padding:12px;margin-top:12px}
.inlineform .row{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap}
.inlineform .field{margin-bottom:0;flex:1;min-width:110px}
.note{background:#E7EDF5;border-left:3px solid var(--azul);border-radius:var(--r-ctrl);padding:10px 13px;
  font-size:var(--t-apunte);color:var(--navy2)}
.note.warn{background:var(--granate-claro);border-left-color:var(--granate);color:var(--granate-osc)}
.kv{display:grid;grid-template-columns:46% 54%;row-gap:7px;font-size:var(--t-base)}
.kv .k{color:var(--g60)}.kv .v{color:var(--tinta);font-weight:500}
.ficha-head{display:flex;align-items:flex-start;gap:18px;margin-bottom:18px;flex-wrap:wrap}
.ficha-head h2{font-size:var(--t-tit)}
.ficha-head .meta{font-size:var(--t-apunte);color:var(--g60);margin-top:4px}
.ficha-head .meta b{color:var(--navy)}
.secgrid{display:grid;grid-template-columns:1fr 1fr;gap:16px;align-items:start}
.crumb{font-size:var(--t-apunte);color:var(--g60);margin-bottom:4px}
.formgrid{display:grid;grid-template-columns:1fr 1fr;gap:0 18px}
.formgrid .full{grid-column:1/-1}
@media(max-width:960px){#shell{grid-template-columns:1fr}aside{position:static;height:auto}
 .g4,.g3,.secgrid,.formgrid{grid-template-columns:1fr}.g2{grid-template-columns:1fr}}

/* mockup v2 */
.msep{height:1px;background:rgba(255,255,255,.14);margin:9px 14px}
.otab2{display:none}

.tabs{display:flex;gap:2px;margin-bottom:16px;border-bottom:1px solid var(--t12);flex-wrap:wrap}
/* Las pestañas pasan de botón enmarcado a subrayado: no compiten con los
   botones de acción, que son lo único que debe parecer pulsable. */
.tabs a{padding:8px 14px 9px;border:none;border-bottom:2px solid transparent;border-radius:0;
  font-size:var(--t-base);font-weight:var(--p-medio);color:var(--t60);background:none;cursor:pointer;margin-bottom:-1px}
.tabs a.on{background:none;color:var(--navy);border-bottom-color:var(--azul);font-weight:var(--p-fuerte)}
.vista{display:none}.vista.on{display:block}
.sello{font-family:'IBM Plex Mono';font-size:var(--t-micro);color:var(--g40)}
.sem{display:inline-block;width:10px;height:10px;border-radius:50%;vertical-align:middle}
.chip.c-nav{background:var(--navy);color:#fff}.chip.c-req{background:#F08335;color:#fff}
.chip.c-bad{background:#F7E9ED;color:var(--granate);border:1px solid var(--granate)}
.sem.v{background:var(--verde)}.sem.a{background:var(--amarillo)}.sem.g{background:var(--granate)}
.mini{font-size:var(--t-min);color:var(--g60)}
.demo{position:fixed;bottom:10px;right:14px;background:var(--navy);color:#fff;font-family:'IBM Plex Mono';font-size:var(--t-micro);padding:4px 10px;border-radius:var(--r-ctrl);opacity:.85;z-index:50}
/* timeline */
.tl{position:relative;margin:6px 0 0 8px;padding-left:22px;border-left:2px solid var(--g15)}
.tl .ev{position:relative;padding:0 0 16px}
.tl .ev::before{content:"";position:absolute;left:-30px;top:2px;width:12px;height:12px;border-radius:50%;background:var(--verde);border:2px solid #fff;box-shadow:0 0 0 2px var(--verde)}
.tl .ev.prev::before{background:#fff;box-shadow:0 0 0 2px var(--g20)}
.tl .ev.prev{color:var(--g40)}
.tl .ev.venc::before{background:var(--granate);box-shadow:0 0 0 2px var(--granate)}
.tl .f{font-family:'IBM Plex Mono';font-size:var(--t-min);color:var(--g60)}
/* modal */
.velo{display:none;position:fixed;inset:0;background:rgba(10,18,32,.45);z-index:40;align-items:center;justify-content:center}
.velo.on{display:flex}
/* La definición de .modal que había aquí no llegaba a aplicarse nunca:
   dialog.modal, más abajo, tiene más especificidad y la pisaba entera —el
   ancho de 460 px incluido—. El sistema completo está en un solo sitio. */
.permgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:4px 12px;font-size:var(--t-apunte)}
.permgrid label{display:flex;gap:6px;align-items:center;font-weight:400}
.tachado{text-decoration:line-through;color:var(--g40)}
.bitac input{flex:3}
.clicable{cursor:pointer}

/* --- capa aplicación PHP (fase 3) --- */
.contenido{padding-top:16px}
.list .ent b{color:var(--navy)}
.list a{color:var(--azul);text-decoration:none}
.list a:hover{text-decoration:underline}
/* 28/07/2026: esta regla ponía display:block y, por especificidad, ganaba al
   nav a{display:flex} de arriba. Resultado: el gap entre icono y etiqueta no
   se aplicaba y el texto salía pegado al SVG. */
nav#menu a{cursor:pointer;text-decoration:none;display:flex;align-items:center;gap:10px}
/* --- entrega A --- */
/* Avisos: filete de color a la izquierda y fondo teñido, nunca borde completo.
   Un recuadro cerrado compite con las tarjetas; una barra lateral señala sin
   competir. Misma geometría para el flash, el error de acceso y la nota. */
.flash-ok{background:var(--verde-t);color:var(--verde-osc);border:none;border-left:3px solid var(--verde);
  border-radius:var(--r-ctrl);padding:10px 13px;font-size:var(--t-apunte);margin-bottom:14px;line-height:1.5}
.flash-err{background:var(--granate-t);color:var(--granate-osc);border:none;border-left:3px solid var(--granate);
  border-radius:var(--r-ctrl);padding:10px 13px;font-size:var(--t-apunte);margin-bottom:14px;line-height:1.5}

/* 28/07/2026: esta regla suelta iba después de la global y la pisaba: daba a
   TODOS los desplegables ancho completo y radio de tarjeta, así que en la
   ficha de persona los select salían anchos y redondeados al lado de unos
   input estrechos y cuadrados. El ancho completo lo da .field, que es donde
   tiene sentido; el resto se ajusta a su contenido. */
/* --- entrega B --- */
.field.full{grid-column:1/-1}

/* v13 fixes: searchrow compacto y modales de alta */
.searchrow select,.searchrow input{width:auto}
.searchrow input[type=checkbox]{width:auto;margin-right:4px}
.searchrow .spacer{flex:1}
/* ===========================================================================
   MODALES (28/07/2026)
   ---------------------------------------------------------------------------
   Sin borde: la separación la hace la elevación, como en las tarjetas. Un
   filete de 1 px sobre un velo oscuro no aporta y contradice al resto.
   El velo va en la tinta de la marca, no en un gris cualquiera.
   El botón de cerrar deja de flotar —float:right dentro de un <dialog> deja
   el título descolocado en cuanto ocupa dos líneas— y pasa a estar anclado.
   ======================================================================== */
dialog.modal{border:none;border-radius:var(--r-caja);padding:24px;max-width:720px;width:92%;
  background:var(--papel);color:var(--tinta);position:relative;
  box-shadow:0 4px 10px rgba(14,22,38,.10),0 32px 70px -20px rgba(14,22,38,.45)}
dialog.modal::backdrop{background:rgba(14,22,38,.52)}
dialog.modal h3{margin:0 34px 18px 0;font-size:var(--t-cuerpo);font-weight:var(--p-fuerte);
  color:var(--navy);letter-spacing:-.01em;line-height:1.3}
dialog.modal .cerrar{position:absolute;top:16px;right:16px;width:28px;height:28px;padding:0;
  display:flex;align-items:center;justify-content:center;cursor:pointer;border:none;
  border-radius:var(--r-ctrl);background:none;color:var(--t45);
  text-decoration:none;transition:background .15s,color .15s}
dialog.modal .cerrar:hover{background:var(--hundido);color:var(--tinta)}
dialog.modal .cerrar svg{display:block}
/* Una franja de acciones al pie, separada por el mismo filete que los pies. */
dialog.modal .acciones{display:flex;gap:8px;align-items:center;flex-wrap:wrap;
  margin-top:18px;padding-top:16px;border-top:1px solid var(--lienzo)}

/* D4: a.btn-primary pisado por a.btn; paginación y filtro de tablas */
.tblpag{margin-top:8px;font-size:var(--t-apunte);color:var(--g50);display:flex;gap:6px;align-items:center;flex-wrap:wrap}
.tblpag a{cursor:pointer;padding:2px 8px;border-radius:var(--r-ctrl);text-decoration:none;color:var(--g50)}
.tblpag a.on{background:var(--navy);color:#fff}
.tblfiltro{margin:0 0 8px;padding:7px 10px;border:1px solid var(--g20);border-radius:var(--r-ctrl);font-size:var(--t-base);width:220px}

/* D5: centrado de modales (el reset *{margin:0} anulaba el auto del dialog) y botón verde */
dialog.modal{margin:auto}
a
/* ============================================================
   R2 · Capa responsive (móvil ≤ 960 px)
   Menú off-canvas con ☰, cada tabla con su scroll horizontal
   (.tscroll, envuelto por JS del layout), topbar reordenada,
   objetivos táctiles e inputs sin zoom iOS. En escritorio solo
   cambia que las tablas anchas se deslizan dentro de su card.
   ============================================================ */
main{min-width:0}                                   /* la celda del grid nunca empuja la página */
/* 28/07/2026: sin el filete de la tarjeta, el corte de una tabla ancha no se
   leía como «sigue a la derecha», se leía como un fallo de maquetación. La
   sombra de borde aparece solo mientras haya contenido fuera y desaparece al
   llegar al final; es CSS puro, sin JavaScript. */
.tscroll{overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%;
  background:linear-gradient(90deg,var(--papel) 30%,rgba(255,255,255,0)),
             linear-gradient(90deg,rgba(255,255,255,0),var(--papel) 70%) 100% 0,
             radial-gradient(farthest-side at 0 50%,rgba(14,22,38,.12),rgba(14,22,38,0)),
             radial-gradient(farthest-side at 100% 50%,rgba(14,22,38,.12),rgba(14,22,38,0)) 100% 0;
  background-repeat:no-repeat;background-size:42px 100%,42px 100%,14px 100%,14px 100%;
  background-attachment:local,local,scroll,scroll}
/* Botón de menú en móvil: ya no lleva un glifo dentro, lleva un SVG, así que
   necesita centrarlo y no necesita cuerpo de letra. */
.menubtn{display:none;border:1px solid var(--g20);background:var(--papel);border-radius:var(--r-ctrl);
  width:38px;height:38px;color:var(--navy);cursor:pointer;align-items:center;justify-content:center;flex:none}
.menuvelo{display:none}

@media(max-width:960px){
  html,body{max-width:100vw;overflow-x:hidden}      /* la página nunca desborda en horizontal */

  /* — menú off-canvas — */
  aside{position:fixed;left:0;top:0;bottom:0;height:100vh;width:250px;max-width:82vw;z-index:60;
    transform:translateX(-105%);transition:transform .2s ease;overflow-y:auto;
    box-shadow:0 0 40px rgba(6,12,22,.35)}
  body.menu-abierto aside{transform:translateX(0)}
  body.menu-abierto .menuvelo{display:block;position:fixed;inset:0;background:rgba(10,18,32,.5);z-index:55}
  body.menu-abierto{overflow:hidden}
  .menubtn{display:flex}
  nav a{padding:13px 20px;font-size:var(--t-cuerpo)}
  nav a.on{padding-left:17px}

  /* — topbar: ☰ + título arriba; selector de entidad a ancho completo debajo — */
  main{padding:0 12px 30px}
  .topbar{flex-wrap:wrap;gap:8px 10px;padding:10px 0;margin-bottom:14px}
  .topbar h1{font-size:var(--t-sec);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .provswitch{order:5;width:100%}
  .provswitch a{flex:1;text-align:center;padding:9px 4px}
  .userchip span{max-width:96px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

  /* — tablas: el .tscroll desliza; la ancha conserva ancho mínimo legible — */
  table.list.t-ancha{min-width:640px}
  .card{padding:13px 14px}
  .tblfiltro{width:100%}

  /* — táctil y formularios — */
  .btn{padding:10px 16px}
  table.list td{padding:11px 10px}
  .contenido input,.contenido select,.contenido textarea{font-size:var(--t-sec)} /* evita el zoom iOS */
  dialog.modal{width:96vw;max-width:96vw;padding:16px 14px;max-height:92vh;overflow-y:auto}
  .ficha-head{gap:10px}
  .ficha-head h2{font-size:var(--t-sec)}
  .searchrow{gap:8px}
  .permgrid{grid-template-columns:1fr 1fr}

  /* — grids declarados inline en vistas (portada wiki, etc.) — */
  #wgrid{grid-template-columns:1fr!important}
}

/* ============================================================
   M1 · Lockup de marca (rediseño de Beatriz, lovemark)
   Pastilla redondeada + wordmark «talentus.» — sin imagen:
   HTML/CSS puro (.lockup > .mark + .wordmark). En el menú navy,
   pastilla y wordmark en blanco.
   ============================================================ */
.lockup{display:flex;align-items:center;gap:10px}
.lockup .mark{width:36px;height:36px;border-radius:var(--r-caja);background:var(--azul);flex:none}
/* La marca no entra en la escala de interfaz: es un logotipo y su tamaño es
   parte de la identidad. El barrido de tokens la infló; se fija aquí. */
.lockup .wordmark{font-weight:700;font-size:27px;color:var(--tinta);letter-spacing:-.025em;line-height:1}
.lockup .wordmark i{font-style:normal;color:var(--verde)}
.lockup .wordmark.wm-claro{color:#fff}
.aside-brand .lockup{gap:8px}
.aside-brand .lockup .mark{width:26px;height:26px;border-radius:8px;background:#fff;position:relative}
/* El cuadrado suelto no decía nada. El punto verde interior lo ata al punto
   del wordmark, que es lo que ya distingue la marca. */
.aside-brand .lockup .mark::after{content:"";position:absolute;right:5px;bottom:5px;
  width:8px;height:8px;border-radius:2px;background:var(--verde)}
.aside-brand .lockup .wordmark{font-size:20px}

/* ============================================================
   R3 · Ritmo vertical y responsive de escritorio (12/07/2026)
   1) Respiro entre bloques: margen automático entre .card/.grid/
      .note/.secgrid/.tscroll adyacentes. Solo actúa cuando son
      hermanos directos: donde la vista ya intercala un espaciador
      manual (div de 14 px) la regla no aplica y no se duplica.
   2) min-width:0 en los hijos de grid: una tabla ancha dentro de
      una tarjeta ya no empuja su columna fuera del contenedor
      (causa del corte «a media tabla» al estrechar la ventana).
   3) Breakpoints intermedios 1280/1200/1080 px: hasta ahora no
      había nada entre 960 px y pantalla completa.
   4) Desbordes de texto (importes KPI, emails en celdas) y .tabs
      con envoltura (Marketing lleva 6 pestañas).
   ============================================================ */

/* 1 · ritmo vertical */
.contenido > :is(.tabs,.card,.grid,.note,.secgrid,.tscroll) + :is(.card,.grid,.note,.secgrid,.tscroll){margin-top:18px}
.grid > .card,.secgrid > .card{margin-top:0} /* dentro de un grid el espaciado lo da el gap, nunca el ritmo */

/* 2 · los items de grid nunca empujan su pista */
.grid>*,.secgrid>*,.formgrid>*{min-width:0}
.contenido{min-width:0}

/* 4 · desbordes de contenido */
.card{min-width:0}
.kpi .val{overflow-wrap:anywhere}
table.list td{overflow-wrap:break-word}
.kv .v{overflow-wrap:anywhere;min-width:0}
.topbar h1{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tabs{flex-wrap:wrap;row-gap:6px}
.contenido img{max-width:100%;height:auto}
.contenido iframe,.contenido embed,.contenido object{max-width:100%}
.searchrow input,.searchrow select{max-width:100%}

/* 3 · escritorio con ventana reducida */
@media(max-width:1280px){
  main{padding:0 20px 34px}
  .kpi .val{font-size:var(--t-tit)}
}
@media(max-width:1200px){
  .g4{grid-template-columns:repeat(2,1fr)}
  .g3{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:1080px){
  .formgrid{grid-template-columns:1fr}
  .kv{grid-template-columns:38% 62%}
  .permgrid{grid-template-columns:1fr 1fr}
}

/* R4a · Deslizamiento visible de tablas anchas: el .tscroll ya desliza (JS del
   layout), pero en macOS la barra superpuesta es invisible y la tabla parece
   cortada. Barra fina siempre presente + sombra de borde que solo aparece
   cuando queda contenido oculto a ese lado (gradientes con attachment local). */
.tscroll{scrollbar-width:thin;scrollbar-color:var(--g20) transparent;
  background:
    linear-gradient(90deg,#fff 40%,rgba(255,255,255,0)) left/32px 100%,
    linear-gradient(270deg,#fff 40%,rgba(255,255,255,0)) right/32px 100%,
    radial-gradient(farthest-side at 0 50%,rgba(6,12,22,.16),transparent) left/16px 100%,
    radial-gradient(farthest-side at 100% 50%,rgba(6,12,22,.16),transparent) right/16px 100%;
  background-repeat:no-repeat;
  background-attachment:local,local,scroll,scroll}
.tscroll::-webkit-scrollbar{height:8px}
.tscroll::-webkit-scrollbar-thumb{background:var(--g20);border-radius:var(--r-ctrl)}
.tscroll::-webkit-scrollbar-thumb:hover{background:var(--g40)}
.tscroll::-webkit-scrollbar-track{background:transparent}
.tscroll table.list{background:transparent}

/* ============================================================
   R5 · Densidad progresiva en anchos medios (14/07/2026)
   Problema: entre 960 px (móvil) y pantalla completa, el CSS
   mantenía la densidad de escritorio grande y las tablas anchas
   (Justificativa, 12 columnas) acababan deslizándose dentro de
   su card con la columna Estado fuera de vista inicial. En media
   pantalla / portátil deben caber enteras. Tres palancas, solo
   CSS, sin tocar vistas:
   1) ≤1500 px: celdas y cards más compactas, barras de avance a
      60 px (pisa el width:80px inline: un !important de hoja de
      estilos prevalece sobre estilo inline no-important) y chips
      dentro de tablas anchas (.t-ancha, ≥5 columnas) con permiso
      de envolver a dos líneas — los estados largos («En curso ·
      objetivos cumplidos») dejan de fijar el ancho mínimo.
   2) ≤1280 px: menú lateral a 198 px (era 222) — 24 px extra al
      contenido justo donde más falta hace.
   3) .secgrid colapsa a una columna en 1240 px (antes 1080): los
      pares de cards con tablas (Histórico de Marketing, Avisos +
      Bitácora) respiran antes.
   ============================================================ */
@media(max-width:1500px){
  table.list{font-size:var(--t-apunte)}
  table.list th{padding:7px 8px;letter-spacing:.035em}
  table.list td{padding:7px 8px}
  .card{padding:14px 15px}
  main{padding:0 20px 36px}
  table.list .bar{width:60px!important}
  .t-ancha .chip{white-space:normal;line-height:1.35}
  .t-ancha th .flechas{margin-left:2px}
}
@media(max-width:1280px){
  #shell{grid-template-columns:198px 1fr}
  nav a{font-size:var(--t-base);padding:9px 16px}
  nav a.on{padding-left:13px}
  .aside-brand{padding:0 16px 14px}
}
@media(max-width:1240px){
  .secgrid{grid-template-columns:1fr}
}
@media(max-width:960px){
  #shell{grid-template-columns:1fr}   /* el aside vuelve a off-canvas (R2) */
  nav a{font-size:var(--t-cuerpo);padding:13px 20px}
  nav a.on{padding-left:17px}
}

/* ============================================================================
 * COLUMNAS PERSONALIZABLES · 25/07/2026
 * Cabecera de tarjeta con acciones a la derecha (☰ y Exportar), y el panel de
 * casillas que llevan los dos modales (elegir columnas y exportar a Excel).
 * ========================================================================== */
.cardhead{display:flex;align-items:center;gap:8px;flex-wrap:wrap;border-bottom:1px solid var(--g08);margin-bottom:10px;padding-bottom:6px}
.cardhead h3{flex:1;margin:0;border:none;padding-bottom:0}
.cardhead .acc{display:flex;gap:6px;align-items:center}
.colsel{max-height:52vh;overflow-y:auto;margin:6px 0 14px;border:1px solid var(--g15);border-radius:var(--r-caja);padding:10px 12px;background:#fff}
.colsel .gtit{font-size:var(--t-micro);font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--azul);margin:10px 0 6px;border-bottom:1px solid var(--g08);padding-bottom:3px}
.colsel .gtit:first-child{margin-top:0}
.colsel .lista{display:grid;grid-template-columns:1fr 1fr;gap:2px 16px}
.colsel label{display:flex;align-items:center;gap:7px;font-size:var(--t-base);padding:3px 0}
.colsel label.fija{color:var(--g40)}
.colsel input[type=checkbox]{width:auto;margin:0}
table.list th.der, table.list td.der{text-align:right}
@media(max-width:760px){.colsel .lista{grid-template-columns:1fr}}

/* --- Inventario digital · pestaña Flujos n8n (25/07/2026) ------------------ */
.famhead{display:flex;align-items:center;gap:10px;margin:18px 0 10px}
.famhead .bar{width:5px;height:19px;border-radius:var(--r-ctrl);background:var(--azul);flex:none}
.famhead h4{flex:1;margin:0;font-size:var(--t-apunte);letter-spacing:.04em;text-transform:uppercase;color:var(--navy)}
.fcard{background:#fff;border:1px solid var(--g15);border-left:4px solid var(--g20);border-radius:var(--r-caja);
  padding:11px 13px 10px;display:flex;flex-direction:column;gap:7px;min-width:0}
.fcard.on{border-left-color:var(--azul)}
.fcard.crit{border-left-color:var(--granate)}
.fhead{display:flex;align-items:flex-start;gap:8px}
.fhead .pip{flex:none;width:9px;height:9px;border-radius:50%;margin-top:4px;background:var(--g20);box-shadow:0 0 0 3px var(--g08)}
.fcard.on .fhead .pip{background:var(--verde);box-shadow:0 0 0 3px var(--verde-claro)}
.fname{flex:1;font-size:var(--t-base);font-weight:700;color:var(--navy);line-height:1.3;word-break:break-word}
.fhead .btn-ico{padding:2px 7px;font-size:var(--t-base)}
.fchips{display:flex;flex-wrap:wrap;gap:4px}
.ftxt{font-size:var(--t-min);color:var(--g60);line-height:1.45}
.ftxt.none{color:var(--g40);font-style:italic}
.fnota{font-size:var(--t-min);color:var(--mostaza);background:var(--amarillo-claro);border-radius:var(--r-ctrl);padding:5px 7px}
.fpie{display:flex;justify-content:space-between;align-items:baseline;gap:8px;
  border-top:1px dashed var(--g15);padding-top:6px;margin-top:auto}
@media(max-width:760px){.famhead{margin:14px 0 8px}}
a.card.kpi{display:block;text-decoration:none}
a.card.kpi:hover{border-color:var(--azul)}

/* ===========================================================================
   Tarjeta de entidad .dcard (26/07/2026)
   ---------------------------------------------------------------------------
   Modelo aprobado el 23/07 para docentes y replicado el 24/07 en personal:
   imagen centrada con aro, nombre, subtítulo y globos. Al usarla también
   Contactos (clientes y proveedores) pasa a la hoja común en vez de repetirse
   en cada vista. Los bloques <style> que aún viven en docentes.php y
   personal.php declaran lo mismo: no estorban, y se retirarán cuando toque
   tocar esas dos vistas.
   =========================================================================== */
.dcard{display:flex;flex-direction:column;align-items:center;text-align:center;
       padding:20px 18px 16px;transition:box-shadow .15s ease, transform .15s ease}
.dcard:hover{box-shadow:0 6px 18px rgba(31,62,112,.14);transform:translateY(-2px)}
.dcard .dnombre{margin-top:12px;font-size:var(--t-sec);font-weight:700;color:var(--navy);line-height:1.25;
  /* 27/07/2026: un nombre sin espacios —un IBAN, una referencia larga— salía
     fuera de la tarjeta. Que parta por donde haga falta antes que desbordar. */
  overflow-wrap:anywhere}
.dcard .dtitulo{margin-top:3px;font-size:var(--t-apunte);color:var(--g60);line-height:1.35;min-height:17px}
.dcard .destrellas{margin-top:9px;font-size:var(--t-cuerpo);letter-spacing:2px;color:var(--g15);user-select:none}
.dcard .destrellas .lbl{display:block;font-size:var(--t-min);letter-spacing:.05em;color:var(--g40);text-transform:uppercase;margin-top:2px}
.dcard .dglobos{margin-top:12px;display:flex;flex-wrap:wrap;gap:6px;justify-content:center}
.dcard .globo{display:inline-flex;align-items:center;gap:5px;font-size:var(--t-min);font-weight:var(--p-medio);color:var(--pizarra);background:#E7EDF5;border:none;border-radius:var(--r-pill);padding:3px 10px;line-height:1.35}
/* 28/07/2026: el globo se distinguía del distintivo por llevar borde —y uno
   de ellos discontinuo—. Ahora ambos comparten forma y se separan por tono:
   el distintivo dice ESTADO, el globo dice METADATO. */
.dcard .globo.exp{background:var(--hundido);color:var(--t60)}
.dcard .globo.baja{background:var(--hundido);color:var(--t60)}
.dcard /* El icono del globo ya no es un carácter: es un SVG y necesita su caja. */
.globo .ic,.globo svg{display:flex;flex:none;opacity:.7}

/* Globo pulsable (contraseña, contrato): mismo aspecto, cursor de acción. */
.dcard .globo.pulsa{cursor:pointer}
.dcard .globo.pulsa:hover{background:var(--tinte2)}
.dcard .globo.mono{font-family:'IBM Plex Mono',ui-monospace,monospace;letter-spacing:.03em}

/* Distintivo de contrato: ocupa el sitio de las estrellas en la tarjeta de
   proveedor. Gris cuando no hay contrato archivado; azul cuando lo hay, y
   entonces es pulsable y abre el PDF en el visor. */
.dcard .dcontrato{margin-top:10px}
.dsello{display:inline-flex;align-items:center;gap:6px;font-size:var(--t-min);font-weight:700;letter-spacing:.04em;
        text-transform:uppercase;border-radius:var(--r-pill);padding:5px 13px;border:1px solid var(--g20);
        background:#F6F7F9;color:var(--g60)}
.dsello.on{background:var(--azul);border-color:var(--azul);color:#fff;cursor:pointer}
.dsello.on:hover{background:var(--navy);border-color:var(--navy)}
.dsello .ic{font-size:var(--t-apunte)}

/* Cabecera de la ficha interior de contacto. */
.chead{display:flex;gap:18px;align-items:center;flex-wrap:wrap}
.chead .cnom{font-size:var(--t-tit);font-weight:700;color:var(--navy);line-height:1.15;overflow-wrap:anywhere}
.chead .cmeta{margin-top:5px;font-size:var(--t-apunte);color:var(--g60)}
.chead .cglobos{margin-top:8px;display:flex;flex-wrap:wrap;gap:6px}
.chead .globo{display:inline-flex;align-items:center;gap:5px;font-size:var(--t-min);font-weight:var(--p-medio);color:var(--pizarra);background:#E7EDF5;border:none;border-radius:var(--r-pill);padding:3px 10px;line-height:1.35}

/* Marca de cliente: el logotipo entero dentro del marco, sin recorte. */
.lmarca{display:flex;align-items:center;justify-content:center;max-width:100%}
.lmarca img{max-width:100%;max-height:100%;object-fit:contain;display:block}

/* Cuatro tarjetas por fila (26/07/2026): a 249 px de ancho, un correo largo
   sin espacios —o dos separados por coma— no encuentra dónde partir y se sale
   de la tarjeta. Se permite el corte en cualquier punto. Aplica también a
   Docentes y Personal, que comparten la clase. */
.dcard .globo{overflow-wrap:anywhere}

/* Aire entre la cabecera de la ficha y la rejilla de bloques (26/07/2026):
   iban demasiado pegados. */
.chead{margin-bottom:20px;padding-bottom:16px;border-bottom:1px solid var(--g08)}
.chead + .note{margin-top:0}

/* Paginador de rejilla (26/07/2026). Estaba declarado dentro de docentes.php;
   al usarlo también Contactos pasa a la hoja común. */
.dpager{display:flex;flex-wrap:wrap;gap:6px;align-items:center;justify-content:center;margin-top:18px}
.dpager .btn{padding:4px 11px;font-size:var(--t-apunte)}

/* Selector de sociedades (26/07/2026). Pastillas conmutables: cada sociedad es
   un código corto que se enciende al pulsarlo, con el nombre completo en el
   emergente. Las casillas con la razón social entera partían la línea y
   descuadraban el formulario. */
.entcampo label{display:block}
.entcampo .entayuda{font-weight:400;text-transform:none;letter-spacing:0;color:var(--g40);font-size:var(--t-min)}
.entsel{display:flex;gap:8px;flex-wrap:wrap;padding:4px 0 2px}
.entpill{cursor:pointer;user-select:none;line-height:1}
.entpill input{position:absolute;opacity:0;width:0;height:0}
.entpill span{display:inline-flex;align-items:center;justify-content:center;min-width:46px;padding:7px 14px;
              border:1px solid var(--g20);border-radius:var(--r-pill);background:#fff;color:var(--g60);
              font-size:var(--t-apunte);font-weight:700;letter-spacing:.05em;
              transition:background .12s ease,border-color .12s ease,color .12s ease}
.entpill:hover span{border-color:var(--azul);color:var(--navy)}
.entpill input:checked + span{background:var(--azul);border-color:var(--azul);color:#fff}
.entpill input:focus-visible + span{outline:2px solid var(--navy);outline-offset:2px}

/* En los formularios en línea (subida de contrato) el selector ocupa su propia
   fila: metido entre los campos, quedaba espachurrado en una columna. */
.inlineform .entcampo{flex:0 0 100%;margin-top:2px}

/* ============================================================
   R5 · Usabilidad · 26/07/2026
   ============================================================ */

/* Paginador con ventana deslizante: los saltos y las flechas necesitan su
   propio trato para no confundirse con los números pulsables. */
.tblpag .salto{color:var(--g20);padding:0 2px;user-select:none}
.tblpag .depag{color:var(--g40)}
.tblpag a.mudo{opacity:.3;pointer-events:none}
.tblpag a:hover:not(.on):not(.mudo){background:var(--tinte,#E5EBF5);color:var(--navy)}

/* Superficie táctil. En pantallas de dedo, los botones de fila —✎ y ✕— se
   quedaban en 22-24 px de alto y se fallaba el toque: 40 así en Hoy, 32 en
   Obligaciones, 31 en Inventario físico. Solo se agrandan donde el puntero es
   grueso; con ratón se dejan como están, que ahí se aciertan. */
@media (pointer:coarse) {
  .btn, button.btn, .tblpag a{min-height:34px;display:inline-flex;align-items:center;justify-content:center}
  .btn{padding-top:6px;padding-bottom:6px}
  table.list td .btn, table.list td button{min-width:34px}
  .dcard .globo.pulsa{min-height:30px}
  input[type=checkbox]{width:18px;height:18px}
}

/* ------------------------------------------------------------------
   Tablas que se pliegan (26/07/2026)
   ------------------------------------------------------------------
   Una tabla de siete columnas dentro de una tarjeta a media página no cabe:
   a 1280 px se salían 130 px en «Contratos con el cliente» y 88 en
   «Expedientes». Deslizaba, pero obligaba a arrastrar para leer el estado de
   un contrato. Ahora, cuando la tarjeta se estrecha, las columnas secundarias
   se ocultan y su contenido reaparece bajo la primera celda. No se pierde
   ningún dato: cambia de sitio. Se decide por el ancho de LA TARJETA, no de la
   ventana, así que funciona igual a media página que a ancho completo.
   ------------------------------------------------------------------ */
.card{container-type:inline-size}
.plegado{display:none}

@container (max-width: 620px) {
  table.t-plegable th.col-sec, table.t-plegable td.col-sec{display:none}
  table.t-plegable .plegado{display:block;margin-top:2px;font-size:var(--t-micro);color:var(--g60);line-height:1.45}
  table.t-plegable .plegado b{font-weight:600;color:var(--g60)}
}

/* Recordatorio de sociedad activa: banda discreta bajo la barra superior.
   No es una alerta —no hay nada que corregir—, solo evita leer una pantalla
   filtrada como si estuviera vacía. */
.entaviso{display:flex;gap:10px;align-items:center;flex-wrap:wrap;
          margin:0 0 2px;padding:7px 14px;font-size:var(--t-apunte);
          background:var(--tinte,#E5EBF5);border:1px solid var(--tinte2,#CBD8EC);
          border-radius:var(--r-caja);color:var(--navy2,#193259)}
.entaviso b{font-weight:700}
.entaviso a{margin-left:auto;color:var(--azul);font-weight:600;text-decoration:none;white-space:nowrap}
.entaviso a:hover{text-decoration:underline}

/* ============================================================
   R7 · Escala de separaciones y pie de tarjeta · 26/07/2026
   ------------------------------------------------------------
   Hasta hoy el aspecto se decidía en el HTML: 433 «margin-top» escritos a mano
   con trece valores distintos, y el pie explicativo de tarjeta repetido
   carácter por carácter 102 veces. Consecuencia: el ritmo vertical cambiaba de
   pantalla en pantalla, y cambiar el pie obligaba a tocar 102 sitios.

   A partir de aquí, cuatro separaciones y una clase para el pie. Quien escriba
   una vista nueva no tiene que decidir cuántos píxeles: elige el escalón.
   ============================================================ */

/* Escala. Cuatro escalones cubren todo lo que había: pegado, normal, entre
   bloques y separación mayor. */
.mt-1{margin-top:4px}
.mt-2{margin-top:8px}
.mt-3{margin-top:16px}
.mt-4{margin-top:24px}
.mt-0{margin-top:0}

/* Pie explicativo de tarjeta: la línea gris con la ℹ que cierra casi todas.
   Antes iba con el estilo escrito dentro del HTML; ahora basta la clase. */
.hint.pie{margin-top:8px;border-top:1px dashed var(--g15);padding-top:6px}

/* Aviso enmarcado dentro de una tarjeta (fondo ámbar, filo a la izquierda):
   también estaba escrito a mano en cada sitio. */
.hint.aviso{margin-top:8px;padding:8px 12px;border-left:3px solid var(--amarillo,#E8C547);
            background:var(--amarillo-claro,#FDF8E8);border-radius:0 7px 7px 0}

/* Raya de separación al cierre de una tarjeta (26/07/2026). El mismo recurso
   que cierra el pie explicativo, pero sobre un formulario o un bloque de
   detalle: en Wiki, Auditoría, Ausencias, Ficha y Panel admin iba escrito en
   línea con cuatro combinaciones distintas de margen y relleno. Una sola. */
.sep-top{margin-top:16px;border-top:1px dashed var(--g15);padding-top:8px}

/* Filas de elementos (26/07/2026). Diez estilos en línea distintos describían
   en realidad dos composiciones: una fila de elementos alineados al centro
   —botones, distintivos, un dato y su acción— y un par de campos de formulario
   alineados por abajo, para que las etiquetas no bailen. Al darles nombre, el
   espaciado deja de decidirse vista por vista. */
.enfila{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.enfila.holgada{gap:18px}
.enfila-campos{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap}

/* Tesorería (27/07/2026). La tarjeta de cuenta reutiliza .dcard y añade el
   saldo, que es el dato que se busca de un vistazo. */
.dcard .tsaldo{margin-top:10px;font-size:var(--t-tit);font-weight:700;color:var(--navy);letter-spacing:-.02em}
.globo.alerta{background:var(--granate-t);color:var(--granate-osc)}
/* El logotipo del banco en la tarjeta de cuenta va sobre el nombre, con el
   mismo marco rectangular de las tarjetas de cliente y proveedor. */
.dcard .lmarca{margin-bottom:4px}
