:root{
  --bg:#EEF0F3; --card:#FFFFFF; --ink:#0F2340; --ink-soft:#5B6472; --line:#E4E7EE;
  /* --green baja de #5f8b1f a #59821D: MISMO tono (84) y MISMA saturacion (64%), dos puntos de
     luz menos (33% -> 31%). Motivo: el blanco encima medía **4.04** y AA pide 4.5 al texto normal
     -y 16px en negrita NO es texto grande, el umbral son 18.66px-. Es el botón primario de toda la
     app, el toast de «ok», el contador de filtros y la cifra del KPI de acento. Ahora **4.53**.
     Se eligió sobre --green-press (#4A6A17, 6.24), que también existía y arreglaba todo de una: el
     precio de aquél era oscurecer el verde de la marca de forma visible (33% -> 25% de luz).
     Decidido y medido el 27-ago-2026; el detalle, en el commit d4f3907. */
  /* Y la REGLA que sale de medirlo: --green es FONDO y ACENTO, nunca tinta. Como texto sobre
     superficie clara medía 4.53 sobre blanco (justo encima del 4.5), 4.22 sobre --green-tenue y
     3.97 sobre --bg: tres márgenes distintos para el mismo color, y dos por debajo. La tinta verde
     es --green-ink, que da 7.80 sobre blanco y no depende de en qué tarjeta caiga. Lo vigila
     `test_colores_por_token.py`. */
  --green:#59821D; --green-press:#4a6a17; --green-ink:#3f5a1e; --green-soft:#eef5df;
  /* --soft se usa SOLO en los placeholders de la barra de filtros (sobre el gris del campo).
     Antes era #8b929c: 3,14:1 sobre blanco, por debajo del 4,5:1 de WCAG AA para texto pequeño;
     el proveedor con la pantalla al sol no leía qué se podía escribir en cada filtro. */
  /* --nav es la superficie del MENU y --nav-hdr la del ENCABEZADO: las dos pasan a BLANCO en
     T2 paso 4 (26-ago-2026, opcion B de tres maquetas medidas). Lo unico que el repositorio
     guardaba del diseno aprobado era el tinte de «aqui estas», #D2E7B6, y de ahi sale la
     superficie: ese tinte mide 1.33 contra #FFFFFF -que es el suelo de esta app- y solo 1.16
     contra --bg. Todo lo demas del armazon claro sale de tokens que ya existian y ya estaban
     medidos; no se inventa ningun tono.
     --marca-bg es el navy que NO es armazon y que por tanto NO sigue al armazon: la fila de grupo
     de las tablas y el logo del login llevan tinta blanca encima, asi que si hubieran seguido a
     --nav habrian quedado BLANCO SOBRE BLANCO. Es exactamente el fallo del `.totalpie`, y solo se
     vio porque el paso 2 puso cada color a la vista. */
  --lime:#7ab929; --nav:#FFFFFF; --nav-hdr:#FFFFFF; --marca-bg:#0f2340; --soft:#5F6875;
  --blue:#2e78b7; --blue-soft:#E7F0F8; --gold:#C98A12; --gold-soft:#faf0d6; --gold-ink:#7a5600;
  --gold-tinta:#3a2c00;   /* 4.63 sobre --gold. El #fff que habia daba 2.95: por debajo del 4.5 de
                             AA, y un 11px en negrita NO cuenta como texto grande. Medido 25-ago */
  --foco:#2E78B7;         /* 4.68 sobre --card, 4.33 sobre --bg. OPACO a proposito: el anillo que
                             habia, rgba(10,34,71,.10), se compone con el fondo y medido daba 1.22,
                             por debajo del 3 que pide un elemento grafico. Medido 25-ago */
  --ph:#6B7484;           /* 4.71 sobre --card: el texto de ejemplo de un campo hay que poder leerlo */
  /* Fuera --red (#c0392b), --ok (#5f8b1f) y --navy (#0f2340): definidos y usados en NINGÚN
     sitio, y eran alias de --danger, --green y --nav. Un token muerto no es gratis: en T2 paso 5
     habría que darle un valor propio en oscuro, y quien lo encuentre no sabrá cuál de los dos
     manda. Los tres del tamaño de letra (--f-lg, --f-xl, --f-2xl) sí se quedan aunque hoy no se
     usen: son la escala, y una escala con huecos deja de ser escala. */
  --link:#2e78b7; --danger:#B42318; --radius:14px; --field-h:52px;
  --red-soft:#FDE9E9;
  --shadow:0 1px 2px rgba(15,35,64,.05),0 4px 14px rgba(15,35,64,.07);
  --shadow-lg:0 8px 26px rgba(15,35,64,.13);

  /* ── T2 paso 2 (2026-08-26): el color vive SOLO en variables ────────────────────────────────
     Lo de aquí abajo estaba escrito a pelo DENTRO de los componentes, que es un color que ningún
     tema puede cambiar y que nadie encuentra cuando hay que cambiarlo. Se nombran por PAPEL y no
     por valor a propósito: tres de estos tokens valen #FFFFFF hoy y dejan de coincidir en cuanto
     el armazón pase a superficie clara (T2 paso 4).
     Donde el mismo papel tenía DOS valores casi iguales -el bloque copiado que siempre diverge-
     se unificó en uno, con el delta y el contraste medidos en DECISIONES.md. */

  /* Tinta del armazón. Con la superficie clara son la tinta y la tinta suave de la app: dos
     valores menos que mantener, y el tema oscuro de T2 paso 5 solo tendrá que redefinir --ink y
     --ink-soft para que el armazón lo siga. Medido el 27-ago sobre #FFFFFF. */
  --hdr-ink:var(--ink);            /* 15.73 */
  --hdr-ink-soft:var(--ink-soft);  /* 5.98 · el subtítulo del encabezado */
  --nav-ink-fuerte:var(--ink);     /* 15.73 · el enlace del menú bajo el cursor */
  --sobre-acento:#FFFFFF;     /* sobre verde o navy sólidos: botón, KPI de acento, chip activo,
                                 fila de grupo de la tabla, logo del hero, contador de filtros, aviso */
  /* RETIRADO el 27-ago-2026: --sobre-acento-soft (era rgba(255,255,255,.85), luego #E7EEDD).
     El rótulo del KPI de acento es texto de 12px sobre --green, así que AA pide 4.5, y el escalón
     «suave» medía 3.40. Sobre el verde no hay presupuesto de contraste para un escalón: el blanco
     puro da 4.53 y es lo que queda. La jerarquía la sigue marcando el tamaño (12px/600 contra
     22px/800), que era su verdadero trabajo. */
  --spin-pista:rgba(255,255,255,.45);          /* el aro del spinner, sobre el botón verde */

  /* Botones del encabezado. OPACOS desde T2 paso 3 —el estándar prohíbe el alfa para estado— y
     sobre superficie clara desde el paso 4. El normal es la superficie hundida de la app; el de
     salir, su rojo pálido, con el rótulo en --danger (5.64) para que siga leyéndose como lo que es.
     Los bordes quedan por debajo del 3 que AA pide a un elemento gráfico, y no se suben: el botón
     se identifica por su RÓTULO —13.90 el normal, 5.64 el de salir—, el borde solo lo refuerza.
     Es el mismo criterio que se escribió en el paso 3, cuando el armazón era navy. Medido 27-ago. */
  --hdr-btn:var(--sup);           /* 1.13 contra el armazón · rótulo --ink encima: 13.90 */
  --hdr-btn-bd:var(--line);       /* 1.24 */
  --hdr-btn-hover:var(--sup-hover); /* 1.19 */
  --hdr-btn-mal:var(--red-soft);  /* 1.17 · rótulo --danger encima: 5.64 */
  --hdr-btn-mal-bd:#E8BDBA;       /* 1.69 · un tinte del 30% de --danger sobre el armazón */
  --hdr-btn-mal-hover:#F4DEDC;    /* 1.29 · tinte del 15% · el rótulo aguanta en 5.11 */

  /* Sombras y velos: el color de una sombra también es un color. Van enteras, como --shadow. */
  /* El encabezado y el menú son ahora superficies CLARAS, o sea del mismo material que una
     tarjeta: llevan la sombra de una tarjeta y no la de un bloque oscuro flotando. La de antes
     (.20 y .14 de navy, con 12 y 18px de difuminado) estaba calibrada para separar navy de gris. */
  --hdr-sombra:0 1px 2px rgba(15,35,64,.05),0 4px 14px rgba(15,35,64,.07);
  --nav-sombra:1px 0 2px rgba(15,35,64,.05),4px 0 14px rgba(15,35,64,.07);
  --tab-sombra:0 -2px 14px rgba(15,35,64,.10);
  --toast-sombra:0 8px 24px rgba(0,0,0,.25);
  --modal-sombra:0 -10px 40px rgba(10,34,71,.22);
  --anillo-verde:0 0 0 4px rgba(95,139,31,.15);   /* el paso en curso del asistente de creación */
  --velo-nav:rgba(15,35,64,.45);                  /* la página, con el menú abierto en móvil */
  --velo-modal:rgba(10,34,71,.42); --velo-modal-0:rgba(10,34,71,0);

  /* Superficies neutras, en escala desde --card (lo que está más arriba) hacia el fondo */
  --sup-1:#FAFBFD;      /* apenas despegada: zona de soltar archivos, panel de solo lectura */
  --sup:#EEF1F6;        /* hundida: campo deshabilitado, cabecera de tabla, etiqueta, X del modal */
  --sup-2:#E7EBF1;      /* un paso más: píldora de dato, barra segmentada, paso del asistente */
  --sup-hover:#E3E8F0;  /* la hundida, bajo el cursor */
  --sup-linea:#C3CDDB;  /* borde PUNTEADO de lo que se suelta o se dibuja. Mide 1.61 sobre blanco:
                           por debajo del 3 que AA pide a un elemento gráfico. Anotado, no tocado:
                           subirlo cambia el peso del recuadro y eso se decide con la maqueta de
                           T2 paso 4. Antes eran DOS valores (#C3CDDB y #CFD6E2) para lo mismo. */
  --modal-asa:#D7DBE3;  /* el asa del modal en móvil */

  /* Pastillas de estado */
  /* El chip activo llevaba `background:var(--ink)` con `--sobre-acento` encima. En oscuro --ink
     es CLARO, asi que eso habria sido blanco sobre blanco: el fallo del `.totalpie` por tercera
     vez. Con estos dos el chip se invierte SOLO con el tema, y mide 15.73 en claro y 14.37 en
     oscuro. Encontrado al construir el tema oscuro, medido el 27-ago. */
  --chip-on-bg:var(--ink); --chip-on-ink:var(--card);
  --pill-bg:#E7ECF5; --pill-bd:#C7D0E0;
  --pill-espera-bg:#FEF3E2;
  --pill-ok-bg:#E6F4EA;
  /* El OTRO «aquí estás»: la columna activa de la barra inferior, en móvil. Nunca se había
     medido contra su propia superficie y daba **1.199**, por debajo del suelo de 1.33 de esta app
     y hasta del 1.20 de asistencia. Es un tinte del 24% de --green sobre --card, que es lo mínimo
     que llega a 1.33. Medido 26-ago: 1.331, con --green-ink encima en 5.86. */
  --tab-on:#D9E3C9;

  /* El aviso ámbar («ojo con esto»), que es más cálido que --gold-soft y no es lo mismo */
  --aviso-bg:#FFF7E6; --aviso-bd:#F0D9A8; --aviso-ink:#B45309;

  /* El borde de la superficie pálida de cada familia, que no existía como token */
  --green-bd:#CFE3B4; --green-tenue:#F5F8EF; --green-bd-tenue:#E6EEDA;
  --gold-bd:#E6D2A2; --blue-bd:#CFDCEE; --blue-ink:#1C5D9B;
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;min-height:100%}
/* ARREGLO DE LA REVISION DEL 07-sep: el `body` no declaraba font-size en NINGUN sitio, asi que el
   texto corriente valia el 16px por defecto del navegador; pero abajo `html[data-letra="grande"]
   body{font-size:var(--f-base)}` (al final del fichero) lo fija en 15.5px. Resultado: elegir
   «letra grande» en Configuracion hacia el parrafo MAS PEQUENO que en «normal». Al declararlo aqui
   el token manda en los dos estados y la escala es real: normal 14px -> grande 15.5px.
   Va con el token y no con un 14px literal para que el bloque de «letra grande» siga siendo el
   unico sitio donde se decide cuanto sube cada tamano. (La casa -HORARIOS/frontend/css/app.css:95-
   tampoco lo declara: alli el mismo defecto sigue vivo, aqui se cierra.)
   PENDIENTE ACTA FASE 0: cerrarlo por el token deja el texto corriente en «normal» en 14px, no en
   los 16px del navegador que valia hasta hoy. Se elige asi porque es la variante quirurgica -todo
   lo demas de este fichero se mide entre 11 y 16px, y --f-base ya gobierna el menu lateral
   (`.as-link`) y las filas de hoja (`.sheet-link`), asi que un body de 16px era el unico tamano
   fuera de la escala-. La otra salida seria subir --f-base a 16px en :root, pero eso mueve TODO lo
   que ya lo usa. Si el dueno prefiere 16/17.5 en vez de 14/15.5, se cambia el token, no esta
   regla. */
body{background:var(--bg);color:var(--ink);font-size:var(--f-base);
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  padding-bottom:env(safe-area-inset-bottom)}
a{color:var(--link);text-decoration:none}
.wrap{width:100%;max-width:440px;margin:0 auto;padding:14px}
.wrap.wide{max-width:1200px}
h2{color:var(--ink)}

/* Header */
.hdr{position:sticky;top:0;z-index:10;background:var(--nav-hdr);color:var(--hdr-ink);display:flex;
  align-items:center;gap:8px;padding:10px 14px;padding-top:max(10px,env(safe-area-inset-top));
  border-bottom:1px solid var(--nav-linea);box-shadow:var(--hdr-sombra)}
.hdr .htitle{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;line-height:1.15}
.hdr h1{font-size:16px;font-weight:700;margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Era `opacity:.72`, que es un color escrito de otra manera: ningún tema lo alcanza y su
   contraste depende de lo que haya detrás. Mismo píxel, ahora por token. */
.hdr .sub{font-size:11px;color:var(--hdr-ink-soft);font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hbtn{display:inline-flex;align-items:center;gap:6px;height:38px;padding:0 13px;border-radius:999px;
  background:var(--hdr-btn);border:1px solid var(--hdr-btn-bd);color:var(--hdr-ink);font-size:13px;
  font-weight:600;cursor:pointer;text-decoration:none;white-space:nowrap;line-height:1;flex:none;transition:background .15s}
.hbtn:hover{background:var(--hdr-btn-hover)}
.hbtn .hi{font-size:15px;line-height:1}
.hbtn-back{padding:0 14px 0 9px}.hbtn-back .hi{font-size:20px;margin-top:-1px}
/* El rótulo en --danger: hereda de .hbtn la tinta del encabezado, que con el armazón claro es
   --ink, y entonces el botón de salir no se distinguía del de al lado más que por el fondo pálido.
   5.64 sobre --hdr-btn-mal. Medido 27-ago. */
.hbtn-danger{background:var(--hdr-btn-mal);border-color:var(--hdr-btn-mal-bd);color:var(--danger)}
.hbtn-danger:hover{background:var(--hdr-btn-mal-hover)}
.hbtn .ht{max-width:180px;overflow:hidden;text-overflow:ellipsis}
.badge{background:var(--gold);color:var(--gold-tinta);font-size:11px;font-weight:800;border-radius:20px;padding:3px 8px;min-width:22px;text-align:center;flex:none}
@media(max-width:599.98px){ .hbtn .ht{display:none} .hbtn{padding:0 11px}.hbtn-back{padding:0 11px} }

/* App shell: barra lateral + superior */
.appside{position:fixed;top:0;left:0;bottom:0;width:248px;background:var(--nav);color:var(--nav-ink);z-index:40;
  display:flex;flex-direction:column;overflow-y:auto;transition:transform .22s ease;
  box-shadow:var(--nav-sombra)}
.as-brand{display:flex;align-items:center;gap:10px;padding:16px 16px 12px;border-bottom:1px solid var(--nav-linea)}
.as-brand .as-logo{font-size:24px;line-height:1}
.as-brand b{font-size:15px;display:block;line-height:1.1}
.as-brand small{display:block;font-size:11px;opacity:.66;margin-top:1px}
.as-nav{padding:8px 10px 24px;flex:1}
.as-grp{font-size:10.5px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;opacity:.5;margin:15px 8px 6px}
.as-link{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:10px;color:var(--nav-ink);
  font-size:14px;font-weight:600;margin-bottom:2px;cursor:pointer;transition:background .13s,color .13s}
.as-link .as-ic{font-size:16px;width:20px;text-align:center;flex:none}
.as-link:hover{background:var(--nav-hover);color:var(--nav-ink-fuerte)}
.as-link.on{background:var(--green);color:var(--sobre-acento)}
.as-link .as-badge{margin-left:auto;background:var(--gold);color:var(--gold-tinta);border-radius:20px;font-size:11px;font-weight:800;padding:1px 7px;min-width:20px;text-align:center}
.as-foot{padding:10px 16px;border-top:1px solid var(--nav-linea);font-size:11px;opacity:.6}
.hamb{display:none;background:var(--hdr-btn);border:1px solid var(--hdr-btn-bd);color:var(--hdr-ink);
  width:38px;height:38px;border-radius:10px;font-size:18px;cursor:pointer;flex:none;align-items:center;justify-content:center}
.appoverlay{display:none;position:fixed;inset:0;background:var(--velo-nav);z-index:35}
@media(min-width:900px){ body.app-shell{padding-left:248px} }
@media(max-width:899.98px){
  .appside{transform:translateX(-100%)}
  body.nav-open .appside{transform:none}
  body.nav-open .appoverlay{display:block}
  .hamb{display:inline-flex}
}

/* Cards */
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  padding:14px;margin-bottom:12px;box-shadow:var(--shadow);transition:box-shadow .15s,transform .15s}
.card h3{margin:0 0 4px;font-size:16px;color:var(--green-ink)}
.card.link{cursor:pointer}.card.link:hover{box-shadow:var(--shadow-lg);transform:translateY(-1px)}
.muted{color:var(--ink-soft);font-size:13px}
.row{display:flex;gap:10px;align-items:center}
.row.wrap{flex-wrap:wrap}
.spread{justify-content:space-between}
.big{font-size:24px;font-weight:800;color:var(--ink)}

/* Botones */
.btn{height:var(--field-h);border:none;border-radius:var(--radius);background:var(--green);
  color:var(--sobre-acento);font-size:16px;font-weight:700;cursor:pointer;display:flex;align-items:center;
  justify-content:center;gap:8px;width:100%;transition:background .15s,transform .04s}
.btn:active{background:var(--green-press);transform:translateY(1px)}
.btn.ghost{background:var(--card);color:var(--ink);border:1px solid var(--line)}
.btn.gold{background:var(--gold);color:var(--gold-tinta)}
.btn.blue{background:var(--blue)}
.btn.danger{background:var(--danger)}
.btn.sm{height:44px;font-size:14px;width:auto;padding:0 16px}
.btn[disabled]{opacity:.6;cursor:progress}
/* BLOQUEADO no es ENVIANDO. `[disabled]` de arriba es el boton mientras sube algo -de ahi el
   `cursor:progress`, que promete que aquello acaba solo-, y con `opacity:.6` un boton primario
   verde queda verde palido: sigue leyendose como «pulsame». El boton que no se puede pulsar
   todavia se pinta con la superficie hundida, la misma de un campo deshabilitado, y con la tinta
   suave: --ink-soft sobre --sup mide 5.28, o sea que el motivo se LEE. Se le quita la opacidad
   para que el contraste sea el medido y no uno atenuado. */
.btn.bloq,.btn.bloq[disabled]{background:var(--sup);color:var(--ink-soft);
  border:1px solid var(--line);cursor:not-allowed;opacity:1}
.btn.bloq:active{background:var(--sup);transform:none}
/* El arco va en `currentColor`, no en blanco. Medido: sobre la tarjeta clara de «Estamos leyendo
   su RUT» (registro.html, fondo --blue-soft) el arco blanco daba **1.15** y la pista compuesta
   1.07 — o sea, un hueco en blanco donde el usuario espera ver que algo se mueve. Con
   currentColor mide 13.65 ahí y NO cambia nada sobre el botón verde, donde currentColor ya es
   blanco. Es el mismo fallo del `.totalpie` que quedó blanco sobre blanco. Medido 26-ago. */
.spin{width:16px;height:16px;border:2.5px solid var(--spin-pista);border-top-color:currentColor;
  border-radius:50%;animation:sp .7s linear infinite}
@keyframes sp{to{transform:rotate(360deg)}}

/* Campos */
label{display:block;font-size:13px;font-weight:600;margin:10px 0 4px;color:var(--ink)}
input,select,textarea{width:100%;min-height:var(--field-h);background:var(--card);
  border:1px solid var(--line);border-radius:var(--radius);padding:12px 14px;font-size:16px;
  color:var(--ink);outline:none;font-family:inherit}
textarea{min-height:80px;resize:vertical}
input[type=checkbox],input[type=radio]{width:auto;min-height:0;height:auto;accent-color:var(--green)}
input[type=file]{padding:9px 12px;font-size:14px}
input::placeholder,textarea::placeholder{color:var(--ph);opacity:1}
input:focus,select:focus,textarea:focus{border-color:var(--ink);outline:2px solid var(--foco);outline-offset:1px}
input:disabled,select:disabled,textarea:disabled{background:var(--sup);color:var(--ink-soft);
  -webkit-text-fill-color:var(--ink-soft);cursor:not-allowed;border-color:var(--line)}
/* Campo de contrasena con boton de ver/ocultar. El envoltorio lo pone `ojoClave()` (js/api.js) a
   partir del id del input, asi que ninguna pantalla escribe este marcado a mano. El boton mide
   --tap (44) dentro de un campo de --field-h (52), asi que cabe sin recortar el area tocable. El
   relleno derecho del input deja sitio al boton: sin el, el texto de la clave pasa por debajo. */
.pwbox{position:relative}
.pwbox input{padding-right:calc(var(--tap) + 8px)}
.pwver{position:absolute;right:4px;top:50%;transform:translateY(-50%);
  width:var(--tap);height:var(--tap);display:flex;align-items:center;justify-content:center;
  border:none;background:none;color:var(--ink-soft);cursor:pointer;border-radius:12px;padding:0}
.pwver:hover{background:var(--sup);color:var(--ink)}
.pwver:focus-visible{outline:2px solid var(--foco);outline-offset:1px}
/* Datos solo-lectura compactos (p.ej. tercero SINCO): panel gris + filas clave/valor */
.lockpanel{background:var(--sup-1);border:1px solid var(--line);border-radius:12px;padding:8px 12px}
.kvg{display:grid;grid-template-columns:1fr 1fr;gap:0 26px}
@media(max-width:560px){.kvg{grid-template-columns:1fr}}
.kvg .kv{border-bottom:1px dashed var(--line);padding:5px 0}
.kvg .kv:last-child,.kvg .kv:nth-last-child(2):nth-child(odd){border-bottom:none}
.kv small{color:var(--ink-soft);font-size:12px;flex:0 0 auto}
/* El valor ya NO se recorta al 60%: una direccion de correo entera es el dato mas largo de esta
   ficha y era justo el que salia cortado ("controldepresupuesto@cimelec.c"). Se le deja todo el
   hueco que sobre y se parte por donde haga falta antes que esconder la mitad. */
.kv b{font-size:13px;text-align:right;min-width:0;overflow-wrap:anywhere}
.lockbadge{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:800;
  color:var(--ink-soft);background:var(--sup-2);border-radius:8px;padding:2px 9px}
.card h3 .lockbadge{float:right;margin-top:2px}
[role="button"]:focus-visible,.chip:focus-visible,a:focus-visible,/* Los navegadores NO le dan al <button> la letra del documento: sin esto, cualquier
   botón sin clase salía en la tipografía por defecto del sistema, media talla más
   pequeña y con otro trazo, al lado de un input que sí hereda. */
button{font-family:inherit}
button:focus-visible{
  outline:3px solid var(--foco);outline-offset:2px;border-radius:8px}
.grid3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:8px}
@media(max-width:520px){.grid2{grid-template-columns:1fr}}

/* Chips */
.chips{display:flex;gap:8px;flex-wrap:wrap}
.chip{border:1px solid var(--line);background:var(--card);border-radius:20px;padding:8px 14px;
  font-size:14px;cursor:pointer;user-select:none}
.chip.on{background:var(--chip-on-bg);color:var(--chip-on-ink);border-color:var(--chip-on-bg)}

/* Pills de estado. El fondo neutro va en `.pill` a secas: antes una pill sin modificador
   ('Directo', 'Robot creando…', los chips de responsabilidades del RUT) se veía como texto en
   negrita de 11 px sin recuadro, y no se leía como etiqueta. Las clases de abajo lo sobrescriben. */
.pill{display:inline-block;font-size:11px;font-weight:700;border-radius:10px;padding:2px 8px;
  background:var(--pill-bg);color:var(--ink)}
.pill.borrador,.pill.abierta,.pill.cargado{background:var(--pill-bg);color:var(--ink)}
/* La tinta ámbar era #8A5A00 aquí y --gold-ink (#7a5600) en las dos pastillas de al lado: el mismo
   papel con dos valores. Unificada en --gold-ink, que además mide mejor (6.06 contra 5.40). */
.pill.enviado,.pill.en_revision,.pill.pendiente,.pill.pendiente_carga{background:var(--pill-espera-bg);color:var(--gold-ink)}
/* La tinta es --green-ink y no --green: son 11px en NEGRITA sobre --pill-ok-bg, o sea AA pide
   4.5, y --green ahí mide 3.99 incluso después de oscurecerlo (antes, 3.56). --green-ink da 6.87.
   Medido el 27-ago-2026. */
.pill.aprobado,.pill.aprobada,.pill.cargado_ok,.pill.completado,.pill.vigente{background:var(--pill-ok-bg);color:var(--green-ink)}
.pill.requiere_ajustes{background:var(--gold-soft);color:var(--gold-ink)}
.pill.rechazado,.pill.anulada,.pill.vencido,.pill.vencida{background:var(--red-soft);color:var(--danger)}
.pill.gold{background:var(--gold-soft);color:var(--gold-ink)}

/* Barra avance */
.bar{height:8px;border-radius:6px;background:var(--line);overflow:hidden;margin-top:6px}
.bar > i{display:block;height:100%;background:var(--green)}
.bar.warn > i{background:var(--gold)}.bar.over > i{background:var(--danger)}

/* KPIs */
.kpis{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px}
.kpi{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:14px;box-shadow:var(--shadow)}
.kpi .k{font-size:12px;color:var(--ink-soft);font-weight:600}
.kpi .v{font-size:22px;font-weight:800;margin-top:3px}
.kpi.accent{background:var(--green);border-color:var(--green);color:var(--sobre-acento)}
.kpi.accent .k{color:var(--sobre-acento)}

/* Stepper (wizard registro) */
.steps{display:flex;gap:6px;margin-bottom:16px}
.steps > div{flex:1;height:5px;border-radius:3px;background:var(--line)}
.steps > div.on{background:var(--green)}

/* Listas / tablas */
.item{padding:12px 0;border-bottom:1px solid var(--line)}
.item:last-child{border-bottom:none}
.empty{text-align:center;color:var(--ink-soft);padding:40px 16px;font-size:15px}
.tblwrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table.tbl{width:100%;border-collapse:collapse;font-size:13px}
table.tbl th{text-align:left;color:var(--ink-soft);font-weight:700;font-size:11px;text-transform:uppercase;
  letter-spacing:.03em;padding:8px 10px;border-bottom:2px solid var(--line);white-space:nowrap}
table.tbl td{padding:9px 10px;border-bottom:1px solid var(--line);vertical-align:top}
table.tbl tr:last-child td{border-bottom:none}
table.tbl td.num,table.tbl th.num{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}

/* Documento fila */
.doc{display:flex;align-items:center;gap:12px;padding:12px 0;border-bottom:1px solid var(--line)}
.doc:last-child{border-bottom:none}
.doc .di{font-size:22px;width:26px;text-align:center;flex:none}
.doc .dm{flex:1;min-width:0}
.doc .dm b{font-size:14px;display:block}
.doc .dm small{color:var(--ink-soft);font-size:12px}
/* LA BOTONERA RESERVA SU ANCHO Y NO COMPITE CON EL NOMBRE. Era un `.row` sin propiedad flex, o
   sea `flex:0 1 auto`: su tamano base es el de su CONTENIDO. Y `.dm` es `flex:1 1 0%`, base cero.
   Asi que en cuanto dentro de la botonera entro un texto largo -«Vencido: suba la version nueva,
   o apruebelo al crear», casi el doble que el anterior, tanda del 02-sep- las acciones reclamaron
   su ancho de contenido y al nombre no le quedo nada: salia A UNA PALABRA POR LINEA («RUT /
   (DIAN)») y las dos pastillas se montaban. Con `flex:none` la botonera vale lo que valen sus
   botones -que son dos iconos y un «Ver»- y el resto es del nombre, que es quien tiene que
   quedarse el espacio sobrante.
   El texto, ademas, ya no vive aqui: se fue a `.dm`, donde esta el resto del estado del documento.
   Las dos cosas hacen falta: una arregla el caso, la otra impide que vuelva con otro contenido. */
.doc .dacc{display:flex;gap:6px;align-items:center;flex:none}
/* El aviso del vencido, en su propia linea bajo el nombre (`small` es inline por omision, y la
   linea de las pastillas ya ocupa la primera). */
.doc .dm .dhint{display:block;margin-top:2px;color:var(--aviso-ink)}
/* En el telefono la fila se PARTE antes que estrujarse. 26 px de icono + el nombre + tres botones
   no caben en 360, y `.doc` no tenia ninguna regla para pantalla estrecha: la unica salida era
   comprimir el nombre, que es el fallo de arriba por el otro camino. Con `flex:1 0 100%` la
   botonera se lleva una linea entera para ella y se alinea a la derecha. */
@media (max-width:520px){
  .doc{flex-wrap:wrap}
  .doc .dacc{flex:1 0 100%;justify-content:flex-end}
}

/* Toast */
.toast{position:fixed;left:50%;bottom:24px;transform:translateX(-50%);background:var(--ink);
  color:var(--sobre-acento);padding:12px 18px;border-radius:12px;font-size:14px;font-weight:600;z-index:100;
  box-shadow:var(--toast-sombra);opacity:0;transition:opacity .2s;max-width:90%}
.toast.show{opacity:1}.toast.ok{background:var(--green)}.toast.err{background:var(--danger)}.toast.warn{background:var(--gold);color:var(--gold-tinta)}

/* Modal */
.modal{position:fixed;inset:0;background:var(--velo-modal);display:none;align-items:flex-end;z-index:90}
.modal.show{display:flex;animation:mdlFade .18s ease}
@keyframes mdlFade{from{background:var(--velo-modal-0)}to{background:var(--velo-modal)}}
@supports((backdrop-filter:blur(2px)) or (-webkit-backdrop-filter:blur(2px))){
  .modal{-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}}
.modal .box{position:relative;background:var(--card);width:100%;max-width:520px;margin:0 auto;
  border-radius:20px 20px 0 0;padding:0 18px 18px;max-height:92vh;overflow:auto;
  box-shadow:var(--modal-sombra);animation:sheetUp .24s cubic-bezier(.2,.8,.2,1)}
@media(min-width:600px){ .modal .box.ancho{max-width:980px} }
/* El titulo y la X van PEGADOS arriba del modal, no dentro del contenido que se desplaza. Antes la
   X era `position:absolute` sobre la caja: bastaba bajar un poco -la hoja de notificaciones tiene
   docenas de avisos- para que el unico boton de cerrar quedara fuera de la vista y hubiera que
   volver a subir. Con la caja como contenedor de desplazamiento, `sticky` deja la barra a la vista
   siempre. El titulo lo separa `modal()` del resto del HTML (js/ui.js). */
.modal-hd{position:sticky;top:0;z-index:5;background:var(--card);display:flex;align-items:flex-start;
  gap:10px;margin:0 -18px 12px;padding:20px 18px 10px}
.modal-hd::before{content:"";position:absolute;top:8px;left:50%;transform:translateX(-50%);
  width:40px;height:4px;border-radius:3px;background:var(--modal-asa)}
.modal-hd h3{margin:0;flex:1 1 auto;min-width:0}
.modal .box h3{margin:0 0 12px;font-size:17px;color:var(--green-ink)}
.modal-x{flex:0 0 auto;margin-left:auto;width:var(--tap);height:var(--tap);border:none;border-radius:50%;
  background:var(--sup);color:var(--ink-soft);font-size:14px;cursor:pointer;line-height:1;
  display:flex;align-items:center;justify-content:center}
.modal-x:hover{background:var(--sup-hover);color:var(--ink)}
@keyframes sheetUp{from{transform:translateY(28px);opacity:.4}to{transform:none;opacity:1}}
@media(min-width:600px){
  .modal{align-items:center}
  .modal .box{border-radius:18px;padding:0 22px 22px;animation:popIn .18s ease}
  .modal-hd{margin:0 -22px 12px;padding:22px 22px 10px}
  .modal-hd::before{display:none}
}
@keyframes popIn{from{transform:scale(.96);opacity:0}to{transform:none;opacity:1}}
@media(prefers-reduced-motion:reduce){.modal.show,.modal .box{animation:none}}

/* ===== Barra de filtros compartida (js/ui.js barraFiltros) =====
   La monta `barraFiltros` para las listas que NO se agrupan por empresa -el informe de solicitudes
   y los usuarios internos-, que es lo que `tablaFiltrable` no sabe hacer. Todo por token: aqui no
   hay un solo color a pelo. */
/* SE QUEDA FIJA al desplazar, igual que la barra de `tablaFiltrable` (app.css:738): con 21
   solicitudes o con 6 usuarios hay que volver arriba para cambiar un filtro, y eso es justo lo que
   se venia a quitar. `--fbar-h` la publica `barraFiltros` midiendose (js/ui.js), y la usa la
   cabecera de la tabla para pegarse DEBAJO de ella y no por debajo. */
.fbar{display:flex;gap:8px;flex-wrap:wrap;align-items:center;background:var(--bg);
  padding:8px 0 6px;margin-bottom:6px}
/* SOLO SE PEGA EN ESCRITORIO, y esto es medido: a 390 y a 320 la barra se parte en cuatro lineas y
   mide 214 px: pegada, congelaria un cuarto de una pantalla de 800. En el telefono la lista es
   corta y la barra queda a un dedo de distancia. El corte es el 899.98/900 del armazon, que es la
   unica frontera de esta app. */
@media(min-width:900px){
  .fbar{position:sticky;top:var(--hdr-h);z-index:8}
}
.fbar .fbusca{flex:1 1 220px;min-width:0;display:flex;align-items:center;gap:8px;
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  padding:0 12px;min-height:var(--tap);color:var(--ink-soft);margin:0}
.fbar .fbusca input{border:none;background:none;min-height:0;padding:0;font-size:14px;flex:1;
  outline:none;color:var(--ink)}
.fbar select{width:auto;min-width:150px;min-height:var(--tap);font-size:13.5px;padding:6px 10px}
.fbar .icbtn{min-width:var(--tap);min-height:var(--tap);display:inline-flex;align-items:center;
  justify-content:center;border:1px solid var(--line);border-radius:var(--radius);
  background:var(--card);color:var(--ink-soft);cursor:pointer;padding:0 10px}
.fbar .icbtn:hover{background:var(--sup);color:var(--ink)}
.fbar .fcuenta{font-size:12px;color:var(--ink-soft);font-variant-numeric:tabular-nums}
/* La accion principal de la barra. DISCRETA a proposito -pedido del dueño: «mas sutil, no un boton
   gigante»-: el mismo alto y el mismo borde que los demas controles de la barra, con la tinta de
   marca para que se distinga de un filtro sin gritar. No lleva la clase `.btn`, que es el boton
   verde de accion de pantalla completa. */
.fbar .bprim{margin-left:auto;min-height:var(--tap);display:inline-flex;align-items:center;gap:6px;
  border:1px solid var(--green-bd);border-radius:var(--radius);background:var(--card);
  color:var(--green-ink);cursor:pointer;padding:0 14px;font:600 13.5px/1 inherit;white-space:nowrap}
.fbar .bprim:hover{background:var(--green-soft)}
.fbar .bprim:focus-visible{outline:2px solid var(--foco);outline-offset:1px}
@media(max-width:899.98px){
  .fbar .fbusca{flex:1 1 100%}
  .fbar select{flex:1 1 45%;min-width:0}
}

/* ===== Sello de la FUENTE (panel interno) =====
   Sustituye al boton «Sincronizar con SINCO»: el DataMart se refresca una vez al dia, asi que lo
   que hace falta saber no es «sincroniza ya» sino de cuando es el dato. */
.fuente{display:flex;align-items:center;gap:8px;flex-wrap:wrap;background:var(--green-soft);
  border:1px solid var(--green-bd);border-radius:12px;padding:8px 12px;font-size:12.5px;
  color:var(--green-ink);margin-bottom:12px}
.fuente b{font-variant-numeric:tabular-nums}
.fuente .sep{flex:1 1 auto}
.fuente.vieja{background:var(--gold-soft);border-color:var(--gold-bd);color:var(--gold-ink)}

/* ===== Tabla-informe (panel interno) =====
   Se desplaza DENTRO de su caja: la pagina nunca se desplaza en horizontal. */
/* LA CAJA ES LA QUE SE DESPLAZA, en los dos ejes, y la cabecera se pega a SU borde (top:0).
   Antes la caja solo tenia `overflow-x` y la cabecera se pegaba con `top:calc(--hdr-h + --fbar-h)`:
   `overflow-x:auto` convierte la caja en contenedor de desplazamiento TAMBIEN en vertical, asi que
   ese `top` no medía desde la ventana sino desde el borde de la caja, y la fila de cabecera
   aparecia flotando 122 px DENTRO de la tabla, encima de las filas. Se vio en produccion.
   `tablaFiltrable` lo resuelve al reves (`overflow:visible` en escritorio), pero aqui no vale: esta
   tabla declara `min-width:940px` y a 900-1200 desbordaria la PAGINA en horizontal, que es lo que
   el estandar prohibe. Con la caja como region propia, la pagina nunca se desplaza de lado. */
.inf-w{overflow:auto;background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  max-height:calc(100vh - var(--hdr-h) - var(--fbar-h) - 150px);min-height:180px}
table.inf{width:100%;border-collapse:collapse;font-size:13px;min-width:940px}
/* `height:var(--tap)` porque la cabecera es PULSABLE (ordena por esa columna) y medida daba 35 px,
   nueve por debajo del token tactil. Es una fila de cabecera de 44 px, que es lo normal en una
   tabla de datos, y quita la duda en los dos lados del corte de 900. */
table.inf th{position:sticky;top:0;z-index:2;background:var(--sup);text-align:left;
  font-size:11.5px;text-transform:uppercase;letter-spacing:.03em;color:var(--ink-soft);
  padding:9px 10px;height:var(--tap);white-space:nowrap;box-shadow:inset 0 -2px 0 var(--line)}
table.inf th[role=button]{cursor:pointer}
table.inf th[role=button]:hover{color:var(--ink)}
table.inf td{padding:9px 10px;border-top:1px solid var(--line);vertical-align:middle}
table.inf td.num{text-align:right;font-variant-numeric:tabular-nums}
table.inf tr.fila{cursor:pointer}
table.inf tr.fila:hover td{background:var(--sup-1)}
table.inf .lnk{color:var(--link);font-weight:600}
table.inf .mal{color:var(--danger);font-weight:700}
.punto{width:9px;height:9px;border-radius:50%;display:inline-block;flex:none;margin-right:7px}
.masfilas{display:block;width:100%;margin-top:10px}

/* ===== Traza del ciclo de vida (ficha del panel) ===== */
.traza{margin:0;padding:0;list-style:none}
.traza li{display:grid;grid-template-columns:24px 1fr;gap:10px;padding:0 0 14px}
.traza .marca{width:24px;height:24px;border-radius:50%;background:var(--sup);display:flex;
  align-items:center;justify-content:center;color:var(--ink-soft)}
.traza li.ok .marca{background:var(--green-soft);color:var(--green-ink)}
.traza li.avi .marca{background:var(--gold-soft);color:var(--gold-ink)}
.traza li.err .marca{background:var(--red-soft);color:var(--danger)}
.traza .cuando{font-size:11.5px;color:var(--ink-soft);font-variant-numeric:tabular-nums}
.traza .que{font-size:13.5px;font-weight:600}
.traza .quien{font-size:12px;color:var(--ink-soft)}
.traza .detal{font-size:12.5px;color:var(--ink-soft);margin-top:3px;line-height:1.5}
/* Lo reconstruido desde `auditoria` se distingue de lo observado: no conoce el estado de partida
   y su hora es la del evento, no la del cambio. Decirlo es parte del dato. */
.aprox{font-size:10px;font-weight:700;border-radius:20px;padding:1px 7px;background:var(--sup);
  color:var(--ink-soft);text-transform:uppercase;letter-spacing:.03em;vertical-align:middle}

/* ===== Fichas de usuario interno (bitacora-style) ===== */
/* Los indicadores en UNA LINEA de texto, sin tarjetas (07-sep-2026, pedido del dueño: «eliminemos
   las tarjetas», «comprimamos mejor»). Eran cuatro cajas con borde que ocupaban 90 px de alto para
   decir cuatro numeros; ahora son 24 y se leen igual. Las cifras van con `tabular-nums` para que no
   baile la linea al teclear en el buscador. */
.kpitira{display:flex;flex-wrap:wrap;gap:4px 14px;align-items:baseline;
  font-size:13px;color:var(--ink-soft);margin:0 0 10px}
.kpitira b{color:var(--ink);font-weight:800;font-variant-numeric:tabular-nums;margin-right:3px}
.kpitira span{white-space:nowrap}
/* El desplegable de los roles tampoco es una tarjeta: es una linea que se abre. */
.masinfo{margin:0 0 10px}
.masinfo > summary{cursor:pointer;font-size:13px;font-weight:600;color:var(--green-ink);
  min-height:var(--tap);display:flex;align-items:center;list-style:none}
.masinfo > summary::-webkit-details-marker{display:none}
.masinfo > summary::before{content:"▸";margin-right:7px;color:var(--ink-soft)}
.masinfo[open] > summary::before{content:"▾"}
.masinfo > div{background:var(--sup-1);border:1px solid var(--line);border-radius:12px;
  padding:10px 14px;margin-top:4px}
/* La celda de identidad: iniciales + nombre + correo, en el ancho de una columna. */
.uid{display:flex;align-items:center;gap:10px;min-width:0}
.uid .av{width:34px;height:34px;border-radius:50%;flex:none;display:flex;align-items:center;
  justify-content:center;font-weight:800;font-size:12.5px;background:var(--blue-soft);
  color:var(--blue-ink)}
.uid .un{min-width:0}
.uid .un b{font-size:13.5px;display:block;line-height:1.3}
.uid .em{color:var(--ink-soft);font-size:12px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;max-width:34ch}
.ustat{font-size:12.5px;color:var(--ink-soft);font-variant-numeric:tabular-nums;white-space:nowrap}
/* La tabla de usuarios necesita menos ancho que la del informe: son siete columnas y tres de
   ellas son un numero. Con los 940 de `.inf` se desplazaba de mas en escritorio. */
table.inf.tusu{min-width:720px}
table.inf.tusu tr:hover td{background:var(--sup-1)}
.uacc{display:flex;gap:6px;justify-content:flex-end}
.uacc .btn.sm{padding:0 10px;white-space:nowrap}

/* ===== Portal proveedor: layout amplio (escritorio) ===== */
.wrap.app{max-width:1200px}
@media(max-width:899.98px){ .wrap.app{max-width:460px} }
@media(min-width:640px){ .kpis{grid-template-columns:repeat(4,1fr)} }
.cardgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px}
.empgrp{display:flex;align-items:center;gap:10px;margin:24px 2px 10px}
.empgrp .en{font-size:15px;font-weight:800;color:var(--ink)}
.empgrp .ec{font-size:12px;color:var(--ink-soft);font-weight:600}
.empgrp .el{flex:1;height:1px;background:var(--line)}
.empgrp .et{font-weight:800;color:var(--green-ink);white-space:nowrap;font-variant-numeric:tabular-nums}
.ocard{background:var(--card);border:1px solid var(--line);border-left:4px solid var(--green);
  border-radius:var(--radius);padding:13px 14px;box-shadow:var(--shadow);cursor:pointer;
  transition:box-shadow .15s,transform .12s}
.ocard:hover{box-shadow:var(--shadow-lg);transform:translateY(-1px)}
.ocard .t{font-weight:800;font-size:15px}
.ocard .m{color:var(--ink-soft);font-size:12.5px;margin-top:2px}
.ocard .v{font-size:17px;font-weight:800;margin-top:8px}
.ocard.warn{border-left-color:var(--gold)}
.ocard.blue{border-left-color:var(--blue)}
.kv{display:flex;justify-content:space-between;gap:10px;font-size:12.5px;padding:2px 0}
.kv span{color:var(--ink-soft)} .kv b{font-variant-numeric:tabular-nums}

/* ===== Tablas filtrables (estilo tablero) ===== */
.tf .filtros{display:flex;flex-wrap:wrap;gap:8px 10px;align-items:flex-end;background:var(--card);
  border:1px solid var(--line);border-radius:12px;padding:9px 12px;margin-bottom:12px;box-shadow:var(--shadow);
  position:sticky;z-index:9}
/* Encabezado de tabla fijo (top lo ajusta el JS bajo la barra de filtros) */
table.tbl thead th{position:sticky;z-index:5;background:var(--sup);box-shadow:inset 0 -2px 0 var(--line)}
table.tbl thead th.sortable{cursor:pointer;user-select:none;white-space:nowrap}
table.tbl thead th.sortable:hover{background:var(--sup-hover);color:var(--ink)}
/* Filas de grupo dentro de la tabla única (alineación perfecta de columnas) */
/* --marca-bg y NO --nav: esta fila lleva tinta blanca encima, así que cuando el armazón pasó a
   blanco (T2 paso 4) habría quedado blanco sobre blanco. La fila de grupo no es armazón. */
tr.rEmp td{background:var(--marca-bg);color:var(--sobre-acento);font-weight:800;font-size:13px;padding:9px 10px}
tr.rEmp .grow{display:flex;justify-content:space-between;gap:10px}
tr.rPro td{background:var(--green-soft);color:var(--green-ink);font-weight:700;font-size:12px;padding:6px 10px}
tr.rEmp td,tr.rPro td{border-bottom:1px solid var(--line)}
/* En escritorio el contenedor NO debe crear scroll (rompe el sticky del thead); en móvil sí (scroll horizontal). */
@media(min-width:900px){ .tf .tblwrap{overflow:visible} }
.tf .fl{display:flex;flex-direction:column;font-size:11px;font-weight:800;color:var(--ink-soft);gap:2px;
  text-transform:uppercase;letter-spacing:.06em}
.tf .fl input,.tf .fl select{min-height:32px;height:32px;font-size:13px;min-width:130px;padding:4px 10px;
  border-radius:8px;background:var(--bg);border:1px solid transparent;color:var(--ink)}
.tf .fl input::placeholder{color:var(--soft)}
.tf .fl input:focus,.tf .fl select:focus{background:var(--card);border-color:var(--ink);outline:2px solid var(--foco);outline-offset:1px}
.tf .filtros .btn,.tf .tfacc .btn{height:32px;align-self:flex-end;font-size:12.5px;padding:0 14px}
/* Fila de acciones (Excel / Limpiar / contador). Va FUERA de .filtros a propósito: es lo único
   de la barra que no era un filtro y el colapso de móvil se la llevaba por delante, dejando la
   descarga a Excel fuera de la pantalla. */
.tf .tfacc{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:10px}
.tf .fcount{margin-left:auto;align-self:center;font-size:11px;color:var(--ink-soft);font-weight:800;
  background:var(--bg);border-radius:999px;padding:4px 10px}
/* En el móvil las ocho filas de filtros de Facturas ocupaban ~40 % de la pantalla ANTES de
   ver un solo dato, y encima fijas (position:sticky) para que no se pudieran desplazar fuera.
   Ahí se colapsan detrás de un botón; en escritorio, donde caben en una línea, no cambia nada.
   El `position:static` del colapso lo tiene en cuenta _stick() en ui.js: si no, el thead queda
   pegado a un offset que ya no existe. */
.tf .ftoggle{display:none}
/* 899.98 y no 700: el mismo numero con el que la app dice «esto es un dedo» y con el que la tabla
   pasa a tarjetas. Dos cortes que gobiernan la misma cosa -la barra en modo tactil- tienen que
   compartir numero, o acaban discrepando. */
@media(max-width:899.98px){
  .tf .filtros{position:static;display:none}
  .tf .filtros.abierta{display:flex}
  .tf .ftoggle{display:inline-flex}
}
.subgrp{display:flex;align-items:center;gap:8px;font-weight:700;color:var(--blue);font-size:13px;margin:14px 2px 6px}
.subgrp .ec{color:var(--ink-soft);font-weight:600;font-size:11px}
table.tbl tbody tr:hover{background:var(--green-soft)}
.lnk{color:var(--link);cursor:pointer;text-decoration:underline}
.trace{display:flex;flex-wrap:wrap;gap:6px}
.tag{display:inline-block;font-size:11px;font-weight:700;border-radius:8px;padding:2px 8px;background:var(--sup);color:var(--ink)}
.tag.cxp{background:var(--blue-soft);color:var(--blue-ink)}.tag.ce{background:var(--green-soft);color:var(--green-ink)}

/* Login hero */
.hero{text-align:center;padding:34px 0 18px}
.hero .logo{width:66px;height:66px;border-radius:18px;background:var(--marca-bg);color:var(--sobre-acento);display:flex;
  align-items:center;justify-content:center;font-size:32px;margin:0 auto 14px;box-shadow:var(--shadow-lg)}
.hero h1{font-size:22px;margin:0 0 2px;color:var(--ink)}
.hero p{margin:0;color:var(--ink-soft);font-size:14px}
.center{text-align:center}
.mt{margin-top:12px}.mb{margin-bottom:12px}

/* ============================================================================================
   Componentes traídos de la app de asistencia (20-ago-2026). Allí ya están medidos y probados en
   móvil, así que el portal los reusa en vez de inventar su propia versión: barra segmentada,
   contenedor de tabla con scroll propio, skeleton de carga y caja de error con reintento.
   La barra segmentada la estrenó el formulario SG-F-01 ("Todo el formulario / Solo lo que me
   falta") y no existía en este CSS: sin ella, los dos botones salían como botones del navegador y
   no se veía cuál estaba elegido.
   ============================================================================================ */
.segbar{display:flex;background:var(--sup-2);border-radius:12px;padding:4px;gap:4px;margin-bottom:12px}
.segbar button{flex:1;border:none;background:none;padding:9px 0;border-radius:9px;font-size:14px;
  font-weight:700;color:var(--ink-soft);cursor:pointer}
.segbar button.on{background:var(--card);color:var(--ink);box-shadow:var(--shadow)}
.segbar button:focus-visible{outline:3px solid var(--foco);outline-offset:2px}
@media(max-width:560px){ .segbar{flex-wrap:wrap} .segbar button{flex:1 1 45%;min-width:120px} }

/* El scroll horizontal vive DENTRO de la tabla, nunca en la página. */
.tabla-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}

/* Carga y error: en vez de un "Cargando…" plano, el hueco con la forma de lo que viene. */
.loadbox{display:flex;flex-direction:column;gap:10px;padding:6px 0}
.skel{height:56px;border-radius:12px;background:linear-gradient(90deg,var(--sup) 25%,var(--sup-hover) 37%,var(--sup) 63%);
  background-size:400% 100%;animation:sk 1.2s ease infinite}
@keyframes sk{0%{background-position:100% 0}100%{background-position:0 0}}
/* 16-sep-2026: un aviso en ambar dentro de un modal o una tarjeta (la clave provisional, un dato
   que falta). Con los tokens del dorado que ya usan las pastillas de espera. */
.warnbox{background:var(--gold-soft);color:var(--gold-ink);border:1px solid var(--gold);border-radius:10px;
  padding:10px 12px;font-size:13px;line-height:1.45;margin:0 0 8px}
.errbox{text-align:center;color:var(--danger);padding:22px 16px}
.errbox .btn{max-width:240px;margin:12px auto 0}
@media(prefers-reduced-motion:reduce){ .skel,.spin{animation:none} }

/* ============================================================================================
   ARMAZÓN ESTANDARIZADO (2026-08-21) — el mismo que la app de asistencia.
   Va al final a propósito: estas reglas ganan sobre las de arriba sin reescribirlas.
     · Tokens de tamaño: un solo sitio para la letra y para el alto de lo que se toca.
     · Menú: lateral en escritorio (colapsable y recordado) + barra inferior de pestañas en
       móvil. Nunca los dos a la vez, y los dos salen del MISMO mapa (js/ui.js navMapa()).
     · Anchos variables: la columna de lectura se ensancha en escritorio y el scroll horizontal
       vive dentro de la tabla, nunca en la página.
   ============================================================================================ */
:root{
  --f-xs:11px; --f-sm:12px; --f-md:13px; --f-base:14px; --f-lg:16px; --f-xl:20px; --f-2xl:26px;
  --tap:44px;                 /* alto mínimo de cualquier cosa que se toca */
  --tabbar-h:58px;
  /* El alto REAL del encabezado lo mide el JS (`medirHeader()` en js/ui.js) y lo sobreescribe aquí.
     Este valor es el del primer pintado, antes de que el JS corra: sin él, `top:var(--hdr-h)` de la
     barra pegajosa no resuelve y `top` cae a `auto`. Va declarado y NO como valor de reserva de
     `var()`, que es lo que el estándar prohíbe: un reserva pinta para siempre y nadie se entera. */
  --hdr-h:64px;
  /* Alto de la barra de filtros compartida. Lo remide `barraFiltros` (js/ui.js); este es el valor
     del primer pintado. Sin el, el `calc()` del thead se invalida entero y la cabecera no se pega. */
  --fbar-h:58px;
  --ico-nav:20px; --ico-hdr:20px; --ico-tab:22px;
  /* Colores del menú como tokens: si un color no es token, ningún tema lo puede cambiar. */
  /* El menú lateral sobre superficie clara (T2 paso 4). Opacos desde el paso 3, y ahora los
     mismos neutros que usa el resto de la app: una línea es --line, un hover es --sup, la tinta es
     --ink. Medido 27-ago contra #FFFFFF. */
  --nav-linea:var(--line);         /* 1.24 · separador; no tiene mínimo */
  --nav-ink:var(--ink);            /* 15.73 */
  --nav-ink-soft:var(--ink-soft);  /* 5.98 · el rótulo de grupo y el pie */
  --nav-hover:var(--sup);          /* 1.13 · hover; no tiene mínimo */
  /* El tinte de «aquí estás»: #D2E7B6 es EL VALOR APROBADO el 26-ago, y mide **1.33** contra la
     superficie clara, que es justo el suelo que esta app se fijó (PROYECTO.md §9). No se toca sin
     volver a medir. Encima: la tinta --green-ink mide 5.89 y la barra de acento --green 3.42, por
     encima del 3 que AA pide a un elemento gráfico. */
  --nav-on-bg:#D2E7B6;
  --nav-on-ink:var(--green-ink); --nav-on-bar:var(--green);
}

/* ---- Iconos (js/icons.js): heredan color y se alinean con el texto ---- */
.ico{display:inline-block;vertical-align:-.18em;flex:none}
.appside .as-link .ico{width:var(--ico-nav);height:var(--ico-nav)}
/* Separa lo del dia a dia de «Cerrar sesion», que es la unica accion del menu sin vuelta. Va por
   token: un color a pelo aqui seria un color que ningun tema puede cambiar. */
.as-sep{height:1px;background:var(--nav-linea);margin:9px 12px 3px}
.hdr .ico{width:var(--ico-hdr);height:var(--ico-hdr)}
.tabbar a .ico{width:var(--ico-tab);height:var(--ico-tab)}
.ico-btn{display:inline-flex;align-items:center;justify-content:center;min-width:var(--tap);
  min-height:var(--tap);border:none;background:none;color:inherit;cursor:pointer;padding:0}

/* ---- Menú lateral: "aquí estás" con fondo tenue + línea de acento ----
   El bloque verde sólido dejaba el texto blanco en 4.04 de contraste y AA pide 4.5. Así queda muy
   por encima, y la línea va en un box-shadow interior, que no ocupa espacio ni mueve el texto. */
.appside{color:var(--nav-ink)}
.as-brand{border-bottom-color:var(--nav-linea)}
/* El logo iba en --lime, que sobre la superficie clara mide 2.39 y AA pide 3 a un elemento
   gráfico (sobre el armazón navy pasaba). --green da 4.53. Medido 27-ago.
   Es la ÚNICA excepción a «--green nunca hace de tinta»: esto no es texto, es la marca, y a un
   elemento gráfico AA le pide 3 y no 4.5. Va etiquetada para que la excepción se vea AQUÍ, donde
   está el color, y no escondida en la prueba —que la reconoce por esta misma etiqueta—. */
.as-brand .as-logo{display:flex;align-items:center;color:var(--green)/*marca-grafica*/}
.as-brand small{color:var(--nav-ink-soft);opacity:1}
.as-grp{color:var(--nav-ink-soft);opacity:1}
.as-link{color:var(--nav-ink);min-height:42px;font-size:var(--f-base);text-decoration:none}
.as-link .as-ic{display:flex;align-items:center;width:20px;font-size:inherit}
.as-link:hover{background:var(--nav-hover);color:var(--nav-ink-fuerte)}
.as-link.on{background:var(--nav-on-bg);color:var(--nav-on-ink);box-shadow:inset 3px 0 0 var(--nav-on-bar)}
.as-link:focus-visible{outline:3px solid var(--foco);outline-offset:-2px}
.as-foot{border-top-color:var(--nav-linea);color:var(--nav-ink-soft);opacity:1}
.hamb{width:40px;height:40px}

/* En escritorio el botón del header COLAPSA el menú (y se recuerda). En móvil no hay cajón. */
@media(min-width:900px){
  body.app-shell{transition:padding-left .2s ease}
  body.app-shell.nav-colapsado{padding-left:0}
  body.nav-colapsado .appside{transform:translateX(-100%)}
  .hamb{display:inline-flex}
  .hdr .hbtn-danger{display:none}
  body.nav-colapsado .hdr .hbtn-danger{display:inline-flex}
}

/* ---- Barra inferior de pestañas (solo móvil/tablet angosta) ---- */
.tabbar{position:fixed;left:0;right:0;bottom:0;z-index:45;display:none;
  background:var(--card);border-top:1px solid var(--line);
  padding-bottom:env(safe-area-inset-bottom);box-shadow:var(--tab-sombra)}
.tabbar a{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:3px;min-height:var(--tabbar-h);padding:6px 2px 5px;color:var(--ink-soft);text-decoration:none;
  font-size:var(--f-xs);font-weight:600;position:relative;-webkit-tap-highlight-color:transparent}
.tabbar a .tlbl{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.1}
/* Marca la columna completa: se ve de reojo y con la pantalla al sol. El `inset` no ocupa espacio. */
.tabbar a.on{color:var(--green-ink);background:var(--tab-on);box-shadow:inset 0 3px 0 var(--green)}
.tabbar a:active{background:var(--bg)}
.tabbar a.on:active{background:var(--green-soft)}
.tabbar .tbadge{position:absolute;top:5px;left:50%;margin-left:4px;background:var(--gold);color:var(--gold-tinta);
  font-size:10.5px;font-weight:800;line-height:16px;min-width:16px;padding:0 4px;border-radius:999px;text-align:center}
@media(max-width:899.98px){
  .tabbar{display:flex}
  body.app-shell{padding-bottom:calc(var(--tabbar-h) + env(safe-area-inset-bottom))}
  .appside{display:none}                    /* el cajón lateral se retira: navega la barra inferior */
  .appoverlay{display:none!important}
  .hamb{display:none}                       /* sin cajón no hay nada que abrir */
  .hdr .hbtn-danger{display:none}           /* "Salir" vive en la hoja "Más" */
  .toast{bottom:calc(var(--tabbar-h) + 16px + env(safe-area-inset-bottom))}
}
@media(min-width:900px){ .tabbar{display:none} }

/* ---- Hoja "Más": lo que no cabe en las pestañas ---- */
.sheet-grp{font-size:var(--f-xs);font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink-soft);margin:14px 2px 4px}
.sheet-link{display:flex;align-items:center;gap:12px;padding:12px 4px;min-height:var(--tap);
  border-bottom:1px solid var(--line);color:var(--ink);text-decoration:none;font-size:var(--f-base);font-weight:600}
.sheet-link:last-of-type{border-bottom:none}
.sheet-link .ico{color:var(--ink-soft)}
.sheet-link .sarr{margin-left:auto;color:var(--soft)}
.sheet-link:active{background:var(--bg)}

/* ---- El menu de la persona, en el encabezado (16-sep-2026; lo pinta js/ui.js _menuUsuario) ----
   Un boton con las iniciales sobre --green (--sobre-acento encima, 4.53) y el nombre; el nombre se
   esconde por debajo de 600 con la regla de `.hbtn .ht` que ya existia. El menu es una tarjeta. */
.umenu{position:relative;flex:none}
.ubtn{padding:0 9px 0 4px;gap:7px}
.uav{width:28px;height:28px;border-radius:50%;background:var(--green);color:var(--sobre-acento);
  display:grid;place-items:center;font-size:11px;font-weight:800;letter-spacing:.02em;flex:none}
.upop{position:absolute;right:0;top:calc(100% + 6px);z-index:70;min-width:250px;max-width:min(340px,92vw);
  background:var(--card);border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow-lg);padding:6px}
.upop[hidden]{display:none}
.upop-cab{padding:8px 10px 10px;border-bottom:1px solid var(--line);margin-bottom:4px;display:flex;flex-direction:column;gap:2px}
.upop-cab b{font-size:var(--f-base);color:var(--ink)}
.upop-cab small{font-size:var(--f-sm);color:var(--ink-soft);word-break:break-all}
.upop-roles{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}
.upop-it{display:flex;align-items:center;gap:10px;width:100%;min-height:40px;padding:0 10px;border:0;
  background:none;border-radius:8px;color:var(--ink);font:inherit;font-size:var(--f-md);font-weight:600;cursor:pointer;text-align:left}
.upop-it:hover,.upop-it:focus-visible{background:var(--sup)}
.upop-it .ico{color:var(--ink-soft)}
.upop-it.danger{color:var(--danger)}
.upop-it.danger .ico{color:var(--danger)}
.upop-it.danger:hover{background:var(--red-soft)}

/* ---- Tocable con el dedo (y con guantes en obra) ---- */
.chip{min-height:calc(var(--tap) - 4px);display:inline-flex;align-items:center}
.hbtn{min-height:40px}
.segbar button{min-height:38px}

/* ---- Anchos variables ----
   La columna de una sola pantalla no debe quedar como un hilo junto al menú de 248px, ni estirarse
   hasta ser ilegible: se ensancha a un panel cómodo y centrado. Y nada desborda a lo ancho. */
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{overflow-x:hidden}
img,canvas,svg,video{max-width:100%}
.wrap,.wrap.wide{padding-left:clamp(10px,3vw,14px);padding-right:clamp(10px,3vw,14px)}
@media(min-width:900px){ .wrap:not(.wide){max-width:680px} }
/* ...PERO las pantallas de la aplicacion NO son formularios: son tablas y paneles, y 680 px en un
   monitor de 1600 dejan tres cuartas partes en blanco mientras la tabla se desplaza de lado dentro
   de un cajon. `.wrap.app` ya pedia 1200 px en la linea 548 de este mismo fichero; la regla de
   arriba, escrita despues y con la misma especificidad, se lo comia sin que se notara. Esto lo
   devuelve, y por eso va DESPUES. (15-sep-2026: el dueno lo dijo de tres pantallas distintas.) */
@media(min-width:900px){ .wrap.app{max-width:1200px} }
@media(min-width:1460px){ .wrap.app{max-width:1400px} }

/* Las tablas de la casa, en UNA LINEA POR CELDA. Con el ancho de verdad ya no hace falta partir
   "Notificacion SGD facturas SINCO" en cuatro renglones ni un asunto en cinco: una fila de cinco
   lineas hace que cinco correos llenen la pantalla y que la cabecera se pierda de vista. Lo que no
   cabe se corta con puntos suspensivos y se lee entero en el panel de al lado o en el titulo. */
.tbl td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:34ch}
.tbl td:first-child{max-width:12ch}
.tbl th{white-space:nowrap}
/* La cabecera se queda arriba al desplazar: sin esto, a la tercera pantalla de filas ya no se sabe
   que columna es cual. Fondo OPACO -- una cabecera translucida deja ver las filas por debajo. */
.tblwrap{position:relative}
.tbl thead th{position:sticky;top:0;z-index:2;background:var(--sup)}
@media(max-width:599.98px){
  table.data{font-size:12.5px}
  table.data th,table.data td{padding:7px 8px}
  .kpi b{font-size:22px}
}

/* ============================================================================================
   BARRA DE FILTROS FIJA (2026-08-21) — la de la app de asistencia, traída a las tablas del portal.
   Una sola fila: buscador que crece + pastillas de lo que hay puesto + "Filtros (n)" + acciones en
   iconos. El panel con los campos se abre bajo demanda y NO es sticky.
   Antes, en Facturas, lo primero que veía el proveedor eran ocho filas de filtros -fijas- antes de
   un solo dato, y en móvil se colapsaban todas detrás de un botón sin decir qué estaba filtrado.
   ============================================================================================ */
.tf .barra{position:sticky;top:var(--hdr-h);z-index:9;background:var(--bg);padding:7px 0 6px;margin:0 0 6px}
.tf .barfila{display:flex;align-items:center;gap:6px;min-width:0}
.tf .barbusca{flex:1 1 180px;min-width:110px;display:flex;align-items:center;gap:6px;background:var(--card);
  border:1px solid var(--line);border-radius:999px;height:38px;padding:0 6px 0 11px;color:var(--ink-soft)}
.tf .barbusca input{flex:1;min-width:0;border:none;background:none;height:36px;min-height:0;padding:0;
  font-size:var(--f-md);color:var(--ink)}
.tf .barbusca input:focus{outline:none;box-shadow:none;border:none}
.tf .barbusca input::-webkit-search-cancel-button{display:none}
.tf .qx{border:none;background:none;color:var(--ink-soft);cursor:pointer;width:28px;height:28px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;flex:none}
.tf .barchips{display:flex;gap:5px;flex:0 1 auto;min-width:0;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.tf .barchips::-webkit-scrollbar{display:none}
.tf .pchip2{flex:none;display:inline-flex;align-items:center;gap:5px;border:1px solid var(--pill-bd);background:var(--pill-bg);
  color:var(--ink);border-radius:999px;padding:6px 11px;font-size:var(--f-xs);white-space:nowrap;min-height:34px}
.tf .pchip2 b{font-weight:700}
.tf .xchip{border:none;background:none;color:inherit;cursor:pointer;padding:0 0 0 2px;display:inline-flex;align-items:center}
.tf .btnfil{flex:none;display:inline-flex;align-items:center;gap:5px;height:38px;padding:0 13px;border-radius:999px;
  border:1px solid var(--ink);background:var(--card);color:var(--ink);font-size:var(--f-sm);font-weight:600;cursor:pointer;white-space:nowrap}
.tf .btnfil b{background:var(--green);color:var(--sobre-acento);border-radius:999px;padding:0 6px;font-size:var(--f-xs)}
.tf .icbtn{flex:none;width:38px;height:38px;border:1px solid var(--line);background:var(--card);color:var(--ink);
  border-radius:999px;display:flex;align-items:center;justify-content:center;cursor:pointer}
.tf .icbtn:hover,.tf .btnfil:hover{background:var(--bg)}
.tf .fcount{flex:none;font-size:var(--f-xs);color:var(--ink-soft);font-weight:800;background:var(--card);
  border:1px solid var(--line);border-radius:999px;padding:5px 10px;white-space:nowrap}
/* El panel de campos: cerrado por defecto en TODOS los anchos y nunca fijo. */
.tf .filtros{position:static;display:none;margin:0 0 10px}
.tf .filtros.abierta{display:flex}
/* Mismo corte, y hacia falta medirlo: al subir los controles de la barra a `--tap` (44px) la fila
   dejo de caber en una linea, y a 768px el contador «6 / 6» se salia 9px del ancho de la ventana.
   Estaba colgado de 700 desde antes; ahora envuelve donde los controles son de dedo. */
@media(max-width:899.98px){
  .tf .barfila{flex-wrap:wrap}
  .tf .barbusca{flex:1 1 auto;min-width:0}
  .tf .barchips{order:3;flex:1 0 100%;margin-top:6px}
  .tf .fcount{order:2}
}
/* ============================================================================================
   TARJETAS EN MOVIL (T4 — 2026-09-02). Opcion C de tres maquetas medidas, que estan guardadas
   en `maquetas/2026-09-01-ordenes-en-el-telefono.html` con los numeros de las tres.

   El dato que lo decidio: con las 7 columnas reales de Ordenes la tabla pedia **173px** de
   arrastre lateral a 375 y **228px** a 320, y lo que quedaba fuera de la vista era justo Total
   y Pendiente. La C deja ver **8 ordenes** de una vez contra 3 de la tarjeta que lo ensena todo,
   porque en esa pantalla lo que se hace es BUSCAR una en una lista, no leerlas una por una.

   Ni un color a pelo: los tokens de aqui ya existian y ya estaban medidos. Y el corte es el PAR
   `899.98 / 900` que esta app ya usa para «esto es un dedo» -donde enciende la barra inferior de
   pestanas y retira el menu lateral-, no uno nuevo: asi las tarjetas y el tamano de lo que se toca
   dependen del MISMO numero. `ui.js` consulta ese mismo corte con `matchMedia`, para que la hoja de
   estilos y el JS no puedan desincronizarse.
   ============================================================================================ */
.tfcards{display:block}
.tfc{display:flex;align-items:stretch;overflow:hidden;margin-bottom:7px;background:var(--card);
  border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow)}
.tfc-cuerpo{flex:1;min-width:0;display:flex;align-items:center;gap:10px;min-height:var(--tap);
  padding:9px 4px 9px 12px;border:0;background:none;color:inherit;font:inherit;text-align:left;cursor:pointer}
.tfc-cuerpo:focus-visible{outline:2px solid var(--foco);outline-offset:-2px}
.tfc-izq{min-width:0}
.tfc-no{display:block;font-weight:800;font-size:var(--f-base)}
.tfc-sub{display:block;margin-top:1px;font-size:var(--f-sm);color:var(--ink-soft);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tfc-der{margin-left:auto;text-align:right;white-space:nowrap}
/* `--f-xs` (11px) y no un 9.5 a pelo: la escala de letra vive en un solo sitio, y un tamano
   incrustado aqui no se movia el dia que alguien la suba. */
.tfc-der span{display:block;font-size:var(--f-xs);font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;color:var(--ink-soft)}
.tfc-der b{font-size:var(--f-lg);font-variant-numeric:tabular-nums}
.tfc-acc{flex:0 0 var(--tap);width:var(--tap);display:flex;align-items:center;justify-content:center;
  border:0;border-left:1px solid var(--line);background:none;color:var(--link);cursor:pointer}
.tfc-acc:focus-visible{outline:2px solid var(--foco);outline-offset:-2px}
/* Los MISMOS rotulos de grupo de la tabla, sin el <table> alrededor. `--marca-bg` y no `--nav`,
   por lo mismo que `tr.rEmp`: llevan tinta blanca encima. */
.gemp{display:flex;justify-content:space-between;gap:10px;margin:2px 0 7px;padding:8px 10px;
  border-radius:8px;background:var(--marca-bg);color:var(--sobre-acento);font-weight:800;
  font-size:var(--f-sm)}
.gpro{margin:0 0 7px;padding:5px 10px;border-radius:7px;background:var(--green-soft);
  color:var(--green-ink);font-weight:700;font-size:var(--f-xs)}
/* Ordenar en movil. Sin esto la funcion DESAPARECE al quitar el encabezado: en la tabla se ordena
   pulsando el <th>, y en tarjetas no hay <th> que pulsar. Se esconde en escritorio, donde el
   encabezado sigue estando y este control seria un segundo camino para lo mismo. */
.tfsort{display:none}
.tfsort>span{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-soft)}
.tfsort select{border:1px solid var(--line);background:var(--card);color:var(--ink);
  /* 16px, no 13: por debajo de eso Safari de iOS hace ZOOM al enfocar el campo y deja la pagina
     ampliada y corrida -es la misma regla, con el mismo motivo, que veinte lineas mas abajo sube
     los campos de filtro-. Y este control SOLO existe en movil, asi que no hay un valor de
     escritorio que respetar. Se escapo porque no lleva la clase `.fl`. */
  border-radius:999px;padding:0 10px;font-size:var(--f-lg);max-width:44vw}
/* La region que DICE el orden a quien no ve la flecha. No ocupa sitio; no es `display:none`, que
   la sacaria del arbol de accesibilidad y no se anunciaria nada. */
.vo{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
.tfsort .icbtn b{font-size:12px;line-height:1}
.tfsort .icbtn[disabled]{opacity:.45;cursor:default}
/* EL TAMANO DE LO QUE SE TOCA VA EN 899.98, no en 700, y la diferencia se midio: esta app ya
   considera «esto es un dedo» hasta 899.98 -ahi enciende la barra inferior de pestanas, retira el
   menu lateral y ahi mismo sube los campos de filtro a `--tap`-. Colgado de 700 dejaba un iPad
   vertical (768px) con la barra de pestanas puesta y los botones de la tabla en 38px.
   Los cuatro de aqui estaban por debajo del minimo desde que se escribieron, y el barrido de T1
   no los vio porque solo miro los campos de la hoja de filtros. Los dos ultimos, encima, no los
   puede ver NINGUN barrido de carga: nacen ocultos y solo aparecen cuando ya hay algo escrito o
   algun filtro puesto. */
@media(max-width:899.98px){
  /* LAS TARJETAS Y EL TAMANO DE LO QUE SE TOCA CUELGAN DEL MISMO NUMERO, y eso es la mitad del
     motivo para elegirlo. El primer intento las puso en el par 700 -«el corte que ya existe»- y
     medido eso dejaba dos definiciones de «esto es un dedo» a la vez: entre 700 y 899 la app ya
     enciende la barra inferior de pestanas y retira el menu lateral, o sea que se navega con el
     dedo, y la tabla seguia puesta. Los numeros de esa banda: **85px de arrastre lateral** en
     Ordenes -y mas en Facturas, que tiene 8 columnas- justo para leer la columna que decide, con
     sus enlaces de texto en 17px de alto. 768px es un iPad en vertical, no un caso raro.
     EL PRECIO, dicho: entre 786 y 899 la tabla SI cabe (0 de arrastre), asi que ahi se cambia una
     tabla que funciona por tarjetas, y el Total queda a un toque. Se acepta porque el corte exacto
     donde la tabla empieza a caber depende de CUANTAS columnas tenga cada tabla -785 en Ordenes,
     mas en Facturas-, y eso no es un numero que pueda vivir en una hoja de estilos. */
  .tfsort{display:inline-flex;align-items:center;gap:6px;flex:none}
  .tfsort select,.tf .icbtn,.tf .btnfil{min-height:var(--tap);height:var(--tap)}
  .tf .icbtn,.tf .btnfil{min-width:var(--tap)}
  .tf .barbusca{min-height:var(--tap)}
  .tf .barbusca input{height:auto;min-height:var(--tap)}
  /* La ✕ de limpiar la busqueda (28x28) y la ✕ de quitar un filtro (~15x13). No se agranda el
     DIBUJO, se agranda el AREA con el pseudoelemento, que es lo que el estandar propone cuando el
     icono no puede crecer sin descuadrar la fila. */
  .tf .qx,.tf .xchip{position:relative}
  .tf .qx::after,.tf .xchip::after{content:"";position:absolute;inset:-9px}
  .tf .qx::after{inset:-8px}
  .tf .pchip2{min-height:var(--tap)}
}

/* 16px es el umbral por debajo del cual Safari de iOS hace ZOOM al enfocar un campo y deja la
   pagina desplazada. En escritorio los 13px se quedan: la barra de filtros tiene que caber en una
   linea. Mismo corte y mismo motivo que en sarlaft.html, donde ya se aplico el 21-ago. */
@media(max-width:899.98px){
  .tf .fl input,.tf .fl select{font-size:16px;min-height:var(--tap);height:auto}
}
@media(max-width:390px){
  .tf .barfila{gap:5px}
  .tf .btnfil .ft{display:none}
  .tf .btnfil{padding:0 11px}
}


/* ============================================================================================
   TEMA OSCURO (T2 paso 5 — 2026-08-27). El ultimo paso de la tanda.

   Como esta escrito, y por que asi. El estandar pide TRES estados, no dos:
     · `:root` a secas, arriba de este archivo, es la paleta CLARA completa.
     · `@media (prefers-color-scheme: dark)` con el guarda `:root:not([data-tema="claro"])`, para
       que quien ELIGE claro le gane a un sistema oscuro.
     · `:root[data-tema="oscuro"]` otra vez, para que la eleccion tambien gane en el otro sentido.
   Sin el guarda, elegir claro no serviria de nada en un sistema oscuro; sin el tercer bloque, el
   boton no podria poner oscuro en un sistema claro. Los dos bloques llevan LOS MISMOS valores: si
   se toca uno hay que tocar el otro, y `test_colores_por_token.py` falla si divergen.

   Y solo se redefinen VALORES: ni un selector de componente aparece aqui. Lo que hace que eso
   alcance es el paso 4, que dejo el armazon colgando de --ink, --line y --sup por alias; el armazon
   se pone oscuro sin que este bloque lo mencione.

   Lo medido, con el barrido completo en `DECISIONES.md`: 47 pares y los dos suelos del tinte de
   «aqui estas», TODOS en su umbral en los dos temas. Los tres que hubo que resolver a proposito:
     · el tinte de «aqui estas» quedo en #24391A, que es el 25% del verde de marca sobre la
       superficie del armazon y mide **1.33** exacto, el mismo suelo que en claro;
     · la barra de acento del activo pasa a --lime: --green sobre ese tinte da 2.77 y AA pide 3 a un
       elemento grafico; --lime da 6.66;
     · el chip activo, arriba.

   Lo que NO cambia, y no es olvido: --green, --gold, --blue y --gold-tinta / --sobre-acento. Son
   superficies de color con su tinta encima, y esa pareja mide lo mismo con cualquier fondo detras.
   ============================================================================================ */
@media (prefers-color-scheme: dark){
  :root:not([data-tema="claro"]){
    /* Superficies. En oscuro la elevacion es LUZ, pero se conserva el ORDEN relativo del tema
       claro (card por encima de bg, sup por encima de card) para que ninguna regla cambie de token. */
    --bg:#0B1420; --card:#141F2C;
    --sup-1:#18242F; --sup:#1E2B38; --sup-2:#253342; --sup-hover:#2C3B4C;
    --line:#27343F;          /* 1.31 sobre --card · separador, sin minimo */
    --sup-linea:#42566B;     /* 2.20 · el borde punteado de soltar. En claro mide 1.61 */
    --modal-asa:#3B4959;     /* 1.81 */

    /* Tinta. El armazon la sigue por alias (paso 4), asi que no hace falta nombrarlo aqui. */
    --ink:#E9EFF6;           /* 14.37 sobre --card · 15.98 sobre --bg */
    --ink-soft:#A0AEBE;      /* 7.36 sobre --card · 6.37 sobre --sup */
    --ph:#93A1B2;            /* 6.32 · el texto de ejemplo de un campo */
    --soft:#93A1B2;          /* 5.47 sobre --sup · los placeholders de los filtros */

    /* El armazon es el material de una tarjeta, igual que en claro era el del papel. */
    --nav:#141F2C; --nav-hdr:#141F2C;
    /* El navy de la marca SUBE: #0F2340 sobre #0B1420 casi no se ve. Con blanco encima, 13.64. */
    --marca-bg:#1C2E4A;
    /* El tinte de «aqui estas»: 25% del verde de marca sobre el armazon. 1.33, el suelo de la app. */
    --nav-on-bg:#24391A; --tab-on:#24391A;
    --nav-on-bar:var(--lime);   /* 6.66 sobre el tinte. --green daria 2.77 y AA pide 3 */
    --hdr-btn-mal-bd:#5E2A26; --hdr-btn-mal-hover:#3A1F1D;

    /* Verde. --green es FONDO (lleva blanco encima, 4.53) y NO cambia; --green-ink es TINTA y se
       invierte. Las superficies palidas pasan a tenidas oscuras del mismo tono. */
    --green-press:#6B9B24;
    --green-ink:#B7DA8B;     /* 10.63 sobre --card · 8.61 sobre el tinte */
    --green-soft:#1B2913; --green-bd:#33491F; --green-tenue:#161F12; --green-bd-tenue:#26351A;
    --lime:#9BCC53;

    /* Ambar. --gold no cambia: es fondo del contador, con --gold-tinta encima (4.63). */
    --gold-soft:#2A2011; --gold-ink:#E2B054; --gold-bd:#4A3818;
    --aviso-bg:#2A2011; --aviso-bd:#4A3818; --aviso-ink:#E8A94E;
    --pill-espera-bg:#2E2413;

    /* Azul. --blue no cambia (fondo); el enlace y el anillo de foco SI, que son tinta y grafico. */
    --blue-soft:#12233A; --blue-bd:#25405F; --blue-ink:#7FB8E6;
    --link:#7FB8E6;
    --foco:#7FB8E6;          /* 7.84 sobre --card · AA pide 3 a un elemento grafico */

    /* Rojo. En oscuro el rojo es TINTA (el rotulo de salir, la pastilla rechazada): se aclara. */
    --danger:#F09189;        /* 7.22 sobre --card · 7.40 sobre --red-soft */
    --red-soft:#2C1614;

    /* Pastillas */
    --pill-bg:#212E3D; --pill-bd:#3A4C61; --pill-ok-bg:#182615;

    /* Sombras y velos. Sobre un fondo oscuro una sombra de navy al 5% no separa nada: el negro
       tiene que ser mas negro y mas opaco. Los velos suben por lo mismo. */
    --shadow:0 1px 2px rgba(0,0,0,.34),0 4px 14px rgba(0,0,0,.42);
    --shadow-lg:0 8px 26px rgba(0,0,0,.52);
    --hdr-sombra:0 1px 2px rgba(0,0,0,.34),0 4px 14px rgba(0,0,0,.42);
    --nav-sombra:1px 0 2px rgba(0,0,0,.34),4px 0 14px rgba(0,0,0,.42);
    --tab-sombra:0 -2px 14px rgba(0,0,0,.42);
    --toast-sombra:0 8px 24px rgba(0,0,0,.55);
    --modal-sombra:0 -10px 40px rgba(0,0,0,.6);
    --anillo-verde:0 0 0 4px rgba(155,204,83,.22);
    --velo-nav:rgba(0,0,0,.62);
    --velo-modal:rgba(0,0,0,.6); --velo-modal-0:rgba(0,0,0,0);
  }
}
:root[data-tema="oscuro"]{
    /* Superficies. En oscuro la elevacion es LUZ, pero se conserva el ORDEN relativo del tema
       claro (card por encima de bg, sup por encima de card) para que ninguna regla cambie de token. */
    --bg:#0B1420; --card:#141F2C;
    --sup-1:#18242F; --sup:#1E2B38; --sup-2:#253342; --sup-hover:#2C3B4C;
    --line:#27343F;          /* 1.31 sobre --card · separador, sin minimo */
    --sup-linea:#42566B;     /* 2.20 · el borde punteado de soltar. En claro mide 1.61 */
    --modal-asa:#3B4959;     /* 1.81 */

    /* Tinta. El armazon la sigue por alias (paso 4), asi que no hace falta nombrarlo aqui. */
    --ink:#E9EFF6;           /* 14.37 sobre --card · 15.98 sobre --bg */
    --ink-soft:#A0AEBE;      /* 7.36 sobre --card · 6.37 sobre --sup */
    --ph:#93A1B2;            /* 6.32 · el texto de ejemplo de un campo */
    --soft:#93A1B2;          /* 5.47 sobre --sup · los placeholders de los filtros */

    /* El armazon es el material de una tarjeta, igual que en claro era el del papel. */
    --nav:#141F2C; --nav-hdr:#141F2C;
    /* El navy de la marca SUBE: #0F2340 sobre #0B1420 casi no se ve. Con blanco encima, 13.64. */
    --marca-bg:#1C2E4A;
    /* El tinte de «aqui estas»: 25% del verde de marca sobre el armazon. 1.33, el suelo de la app. */
    --nav-on-bg:#24391A; --tab-on:#24391A;
    --nav-on-bar:var(--lime);   /* 6.66 sobre el tinte. --green daria 2.77 y AA pide 3 */
    --hdr-btn-mal-bd:#5E2A26; --hdr-btn-mal-hover:#3A1F1D;

    /* Verde. --green es FONDO (lleva blanco encima, 4.53) y NO cambia; --green-ink es TINTA y se
       invierte. Las superficies palidas pasan a tenidas oscuras del mismo tono. */
    --green-press:#6B9B24;
    --green-ink:#B7DA8B;     /* 10.63 sobre --card · 8.61 sobre el tinte */
    --green-soft:#1B2913; --green-bd:#33491F; --green-tenue:#161F12; --green-bd-tenue:#26351A;
    --lime:#9BCC53;

    /* Ambar. --gold no cambia: es fondo del contador, con --gold-tinta encima (4.63). */
    --gold-soft:#2A2011; --gold-ink:#E2B054; --gold-bd:#4A3818;
    --aviso-bg:#2A2011; --aviso-bd:#4A3818; --aviso-ink:#E8A94E;
    --pill-espera-bg:#2E2413;

    /* Azul. --blue no cambia (fondo); el enlace y el anillo de foco SI, que son tinta y grafico. */
    --blue-soft:#12233A; --blue-bd:#25405F; --blue-ink:#7FB8E6;
    --link:#7FB8E6;
    --foco:#7FB8E6;          /* 7.84 sobre --card · AA pide 3 a un elemento grafico */

    /* Rojo. En oscuro el rojo es TINTA (el rotulo de salir, la pastilla rechazada): se aclara. */
    --danger:#F09189;        /* 7.22 sobre --card · 7.40 sobre --red-soft */
    --red-soft:#2C1614;

    /* Pastillas */
    --pill-bg:#212E3D; --pill-bd:#3A4C61; --pill-ok-bg:#182615;

    /* Sombras y velos. Sobre un fondo oscuro una sombra de navy al 5% no separa nada: el negro
       tiene que ser mas negro y mas opaco. Los velos suben por lo mismo. */
    --shadow:0 1px 2px rgba(0,0,0,.34),0 4px 14px rgba(0,0,0,.42);
    --shadow-lg:0 8px 26px rgba(0,0,0,.52);
    --hdr-sombra:0 1px 2px rgba(0,0,0,.34),0 4px 14px rgba(0,0,0,.42);
    --nav-sombra:1px 0 2px rgba(0,0,0,.34),4px 0 14px rgba(0,0,0,.42);
    --tab-sombra:0 -2px 14px rgba(0,0,0,.42);
    --toast-sombra:0 8px 24px rgba(0,0,0,.55);
    --modal-sombra:0 -10px 40px rgba(0,0,0,.6);
    --anillo-verde:0 0 0 4px rgba(155,204,83,.22);
    --velo-nav:rgba(0,0,0,.62);
    --velo-modal:rgba(0,0,0,.6); --velo-modal-0:rgba(0,0,0,0);
}

/* ============================================================================================
   APARIENCIA DE LA PERSONA — LETRA, DENSIDAD Y EL CAMBIO DE TEMA
   ARREGLO DE LA REVISION DEL 07-sep: `js/prefs.js` guardaba, subia al perfil y sellaba en el
   <html> los atributos `data-letra` y `data-densidad`, y `backend/app/main.py` los aceptaba como
   valores validos de PREFS_VALIDAS, pero NINGUN selector de este fichero los leia: elegir «letra
   grande» o «densidad compacta» en Configuracion no movia un pixel. Lo mismo con la clase
   `cambiando-tema`, que prefs.js pone y quita sin que existiera la regla que la usa. Las tres
   reglas venian de HORARIOS y este app.css se copio de PROVEEDORES, que no las trae.
   Van al FINAL a proposito: ganan sobre las de arriba sin tener que reescribirlas, y solo
   redefinen tokens que ya estan declarados en el bloque del armazon (--f-xs..--f-2xl y --tap).
   ============================================================================================ */

/* Mientras se cambia de tema, NADA se anima. Las transiciones de fondo existen para el hover, y
   en un cambio de tema hacen que el control se quede un momento con el color del tema anterior:
   `.btn` y `.hbtn` llevan `transition:background .15s`, asi que durante 150 ms un boton del
   encabezado seguia con el gris del tema claro sobre un encabezado ya oscuro. `js/prefs.js`
   (sinAnimarElCambio) pone esta clase, fuerza el repintado y la quita al frame siguiente. */
html.cambiando-tema, html.cambiando-tema *, html.cambiando-tema *::before, html.cambiando-tema *::after{
  transition:none !important; animation:none !important;
}

/* Letra grande (Configuracion > Apariencia). Sube los tokens de tamano y el alto minimo de lo que
   se toca: una letra mas grande con el mismo boton de 44px descuadra la fila. */
html[data-letra="grande"]{
  --f-xs:12px; --f-sm:13px; --f-md:14.5px; --f-base:15.5px; --f-lg:17.5px; --f-xl:22px; --f-2xl:29px;
  --tap:48px;
}
html[data-letra="grande"] body{font-size:var(--f-base)}
/* ARREGLO DE LA REVISION DEL 07-sep: el bloque copiado solo nombraba `table.data`, que es la clase
   de las tablas de HORARIOS. En esta app las tablas se pintan como `table.tbl` (app.css:335) y
   `table.inf` (app.css:477) -- `.data` no aparece en ningun .html ni en ningun .js de aqui --, asi
   que «letra grande» no movia ni una tabla. Se conserva `table.data` para que el bloque siga
   sirviendo si se copia de vuelta, y se anaden las dos clases que esta app SI usa. */
html[data-letra="grande"] .muted,
html[data-letra="grande"] table.tbl,
html[data-letra="grande"] table.inf,
html[data-letra="grande"] table.data{font-size:var(--f-md)}
html[data-letra="grande"] .card h3{font-size:var(--f-lg)}

/* Densidad compacta (Configuracion > Apariencia; solo tiene efecto en pantallas anchas, que es
   donde sobra el aire). Lleva !important a proposito: es una preferencia de la PERSONA y tiene que
   ganarle al padding propio de cada pantalla.
   El corte es el mismo 900px del armazon (menu lateral), no uno nuevo. */
@media(min-width:900px){
  html[data-densidad="compacta"] .card{padding:9px 11px!important;margin-bottom:8px!important}
  /* ARREGLO DE LA REVISION DEL 07-sep: igual que arriba, el bloque copiado solo nombraba
     `table.data`, clase que esta app no usa; se anaden `table.tbl` y `table.inf`, que son las
     tablas de verdad de aqui, y se conserva `.data` por si se copia de vuelta a HORARIOS. */
  html[data-densidad="compacta"] table.tbl th, html[data-densidad="compacta"] table.tbl td,
  html[data-densidad="compacta"] table.inf th, html[data-densidad="compacta"] table.inf td,
  html[data-densidad="compacta"] table.data th,
  html[data-densidad="compacta"] table.data td{padding:5px 8px!important}
  html[data-densidad="compacta"] table.tbl,
  html[data-densidad="compacta"] table.inf,
  html[data-densidad="compacta"] table.data{font-size:12.5px}
  html[data-densidad="compacta"] .kpi{padding:8px 10px!important}
  /* En HORARIOS el numero del KPI es un <b>; aqui el armazon lo pinta como `.kpi .v`
     (app.css:306). Se cubren los dos para que el bloque siga sirviendo si se copia de vuelta. */
  html[data-densidad="compacta"] .kpi b,
  html[data-densidad="compacta"] .kpi .v{font-size:20px}
  html[data-densidad="compacta"] .item{padding:8px 0!important}
}

/* ═══════════════════════════ BANDEJA UNICA (frontend/js/bandeja.js) ═══════════════════════════
   Bloque ANADIDO al final, sin tocar nada de arriba (CONTRATO_BANDEJA.md G.4.3). Todo va bajo
   `.bandeja`, que es la clase del contenedor de esa pantalla.
   16-sep-2026: aqui quedaban las pastillas, las fechas, la banda y el panel de honestidad de la
   PRIMERA Bandeja (la del formulario, 10-sep). Esa pantalla ya no existe -la de hoy es
   css/bandeja.css entera- y estas reglas, con dos clases de especificidad, le GANABAN a la hoja
   nueva: medido, la pastilla «Hoy» salia con 34 px de alto minimo y la barra unica con 65 px en vez
   de 44. Se quitan. Lo que se conserva es lo que la vista Tabla sigue usando. */
/* La barra de color del area (columna 1, 3px): NO se pinta con html:true, se pinta con una variable
   que bandeja.js pone por fila SOLO si el valor casa con /^#[0-9a-f]{3,8}$/i. Va en la primera celda
   y no en el <tr> porque `table.tbl` colapsa bordes y ahi la sombra del <tr> no se dibuja. */
.bandeja table.tbl tbody tr > td:first-child{box-shadow:inset 3px 0 0 var(--co-area,transparent);padding-left:8px;width:6px}
.bandeja .tfc{box-shadow:inset 3px 0 0 var(--co-area,transparent)}
.bandeja .noleido,.bandeja .tfc.noleido .tfc-no{font-weight:700}
.bandeja .bnd-sc{margin-left:6px;vertical-align:middle}
/* ============================================================================================
   LECTURA DEL CORREO (paso 6; js/lectura.js). Es el panel DERECHO del diseno
   (DISENO_v2.md:113): en escritorio se ancla a la derecha sobre la lista, y por debajo del corte
   de la casa (900 px) ocupa la pantalla entera, que es lo que pide el apartado "Movil" de esa
   misma seccion.

   Tres cosas que no son adorno:
     - `position:fixed` y no un tercer panel en la reja: la Bandeja ya es una tabla que se
       desplaza sola, y meterle una columna la partiria en dos zonas de desplazamiento.
     - el marco del cuerpo tiene ALTURA PROPIA y su propio desplazamiento: el correo de dentro es
       un documento ajeno que puede medir dos metros, y si creciera con la pagina empujaria la
       cabecera y la tira de adjuntos fuera de la vista.
     - la tira de adjuntos va ARRIBA del cuerpo, que es la decision del diseno y el motivo por el
       que esta pantalla existe: el archivo se encuentra sin leer el correo.
   ============================================================================================ */
.lec{position:fixed;inset:0 0 0 auto;width:min(560px,100%);max-width:100%;background:var(--card);
  border-left:1px solid var(--line);box-shadow:-8px 0 24px rgba(15,35,64,.12);
  display:none;flex-direction:column;overflow-y:auto;z-index:60;padding:14px 16px 20px}
.lec.abierto{display:flex}
/* NINGUN hijo del panel se encoge. El panel es una columna flexible que SE DESPLAZA ella misma, y
   sin esto los hijos se reparten el alto de la pantalla: medido el 13-sep, `.lec-marco` -que lleva
   `overflow:hidden`- se quedaba en 40 px con un <iframe> de 476 dentro, o sea que el cuerpo del
   correo se veia como una raya blanca. Es el fallo clasico de una columna flexible con
   desplazamiento: `flex-shrink` vale 1 por defecto. */
.lec > *{flex:0 0 auto}
.lec .lec-x{flex:0 0 auto}
.lec-cargando{display:flex;flex-direction:column;gap:12px}
.lec-cab{display:flex;flex-direction:column;gap:6px;border-bottom:1px solid var(--line);padding-bottom:10px}
.lec-chips{flex-wrap:wrap;gap:6px}
.lec-ficha{border-left:3px solid var(--co-area,transparent);padding-left:6px;font-variant-numeric:tabular-nums}
.lec-asunto{margin:6px 0 2px;font-size:var(--f-lg,18px);line-height:1.3;word-break:break-word}
.lec-dir{font-size:13px;line-height:1.45;word-break:break-word}
.lec-dir b{color:var(--ink-soft);font-weight:600;margin-right:4px}
.lec-fecha{font-size:13px}
.lec-acciones{flex-wrap:wrap;gap:6px;padding-top:8px}
.lec-banda{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin:10px 0;padding:10px 12px;
  border-left:4px solid var(--gold-ink,var(--ink));background:var(--gold-soft);border-radius:8px}
.lec-banda p{margin:0;flex:1 1 240px;font-size:13px}
.lec-adjuntos{margin:12px 0 4px}
.lec-adj-t{font-size:13px;font-weight:600;margin-bottom:6px}
.lec-adj-l{list-style:none;margin:0;padding:0;display:flex;gap:8px;overflow-x:auto;
  scrollbar-width:none;-webkit-overflow-scrolling:touch}
.lec-adj-l::-webkit-scrollbar{display:none}
.lec-adj{flex:0 0 auto;min-width:190px;max-width:260px;border:1px solid var(--line);border-radius:10px;
  padding:8px 10px;display:flex;flex-direction:column;gap:4px;background:var(--bg)}
.lec-adj .row{gap:6px;min-height:var(--tap,44px);align-items:center}
.lec-adj-n{font-size:13px;font-weight:600;word-break:break-word}
.lec-adj-m{font-size:var(--f-xs,12px)}
.lec-nodesc{font-size:var(--f-xs,12px)}
.lec-barras{list-style:none;margin:10px 0;padding:10px 12px;background:var(--gold-soft);
  border-radius:8px;font-size:13px;display:flex;flex-direction:column;gap:4px}
.lec-marco{margin-top:10px;border:1px solid var(--line);border-radius:10px;overflow:hidden;background:#fff}
/* El marco del cuerpo NO hereda el tema de la pagina: dentro hay un documento ajeno con su propio
   fondo, y forzarle el nuestro cambiaria el correo. Fondo blanco, que es sobre lo que se escribio. */
.lec-marco iframe{display:block;width:100%;height:min(62vh,720px);border:0;background:#fff}
.lec-cuerpo-error{padding:16px 0}
.lec-pie{font-size:var(--f-xs,12px);padding-top:10px}
.lec-hilo{list-style:none;margin:8px 0;padding:0;max-height:48vh;overflow:auto}
.lec-hilo li{padding:8px 0;border-bottom:1px solid var(--line)}
.lec-hilo .muted{font-size:var(--f-xs,12px)}
.lec-sellos{gap:6px;flex-wrap:wrap;margin-bottom:6px}
.lec-auth.ok{background:var(--green-soft);color:var(--green-ink)}
.lec-auth.mal{background:#fdeceb;color:#8a1c12}
.lec-auth.nd{background:var(--bg);color:var(--ink-soft)}
.lec-cabtabla{max-height:46vh;overflow:auto}
.lec-cabtabla table{width:100%;border-collapse:collapse;font-size:12px}
.lec-cabtabla th{text-align:left;vertical-align:top;padding:4px 8px 4px 0;color:var(--ink-soft);
  font-weight:600;white-space:nowrap}
.lec-cabtabla td{padding:4px 0;word-break:break-all}
@media (max-width:899px){
  .lec{width:100%;border-left:0;padding:12px}
  .lec-marco iframe{height:min(56vh,640px)}
  /* Con el panel abierto la lista de detras no se desplaza: en un telefono, dos zonas de
     desplazamiento superpuestas hacen que el dedo mueva la de abajo. */
  body.lec-abierta{overflow:hidden}
}

/* ============================================================================================
   CASOS Y TRANSPARENCIA (paso 7; js/casos.js y js/transparencia.js).

   Las dos pantallas son listas y formularios, o sea que casi todo sale de los componentes que ya
   existen (`.card`, `.btn`, `tablaFiltrable`). Lo de aqui es lo que no tenian: la tarjeta de
   introduccion de los casos, la lista de pendientes, y las fichas de los reclamos con su respuesta.
   ============================================================================================ */
.casos .cas-intro p,.transp .tra-cab p{margin:0 0 10px}
.casos .cas-intro{display:flex;flex-direction:column;align-items:flex-start;gap:4px}
.casos .cas-t,.transp .tra-t{margin:18px 0 8px;font-size:var(--f-lg,16px)}
.casos .cas-f,.transp .tra-f{display:flex;flex-direction:column;gap:4px;font-size:var(--f-xs,12px);
  color:var(--ink-soft)}
.casos .cas-f input,.transp .tra-f input{margin:0}
.casos .cas-pend{border-left:4px solid var(--gold-ink,var(--ink))}
.casos .cas-lista,.transp .tra-reclamos{list-style:none;margin:8px 0 0;padding:0;
  display:flex;flex-direction:column;gap:10px}
.casos .cas-lista li,.transp .tra-reclamos li{border-top:1px solid var(--line);padding-top:10px;
  font-size:13px}
.casos .cas-lista li:first-child,.transp .tra-reclamos li:first-child{border-top:0;padding-top:0}
.casos .cas-dl{display:grid;grid-template-columns:auto 1fr;gap:4px 12px;margin:8px 0;font-size:13px}
.casos .cas-dl dt{color:var(--ink-soft);font-weight:600}
.casos .cas-dl dd{margin:0;word-break:break-word}
.transp .tra-fechas{flex-wrap:wrap;gap:10px;align-items:end}
.transp .tra-aviso{border-left:4px solid var(--gold-ink,var(--ink));background:var(--gold-soft)}
.transp .tra-aviso p{margin:0 0 6px;font-size:13px}
.transp .tra-aviso p:last-child{margin:0}
/* La respuesta de la empresa se separa de lo que escribio el titular: son dos voces distintas y en
   un reclamo importa cual es cual. */
.transp .tra-resp{margin-top:6px;padding:8px 10px;background:var(--bg);border-radius:8px}
