/* ============================================================================
   SOFTLINE UI — Sistema de diseño unificado de Intra Line
   ----------------------------------------------------------------------------
   Tokens de marca (--sl-*) + componentes (.sl-*).
   Doc: _devel/design-system.md
   Coexiste con Bootstrap 3 (Nice Admin) y PREDOMINA sobre él.
   Cargar SIEMPRE después del bundle de Bootstrap/Nice Admin.

   ESCALA / ACCESIBILIDAD
   ----------------------------------------------------------------------------
   Los tamaños de los componentes se expresan en REM, de modo que toda la UI
   escala proporcionalmente (con reflow correcto, sin transform borroso) desde
   un único mando: el font-size raíz. La preferencia por usuario
   (usuarios_preferencias.up_ui_scale) se pinta como <html data-ui-scale="...">.
   'normal' ya parte de un tamaño cómodo (112.5% del navegador), y grande/mayor
   escalan desde ahí (ideal para baja visión; convive con Ctrl/+/- del navegador).
   Los % son relativos al tamaño del navegador, así respetan su config base.
   Como este archivo solo se carga en pantallas migradas, la escala solo afecta
   a esas pantallas (piloto actual: clientes_fichas).
   ============================================================================ */

html[data-ui-scale="normal"] { font-size: 112.5%; }  /* ~18px base (nuevo baseline) */
html[data-ui-scale="grande"] { font-size: 125%;   }  /* ~20px base */
html[data-ui-scale="mayor"]  { font-size: 137.5%; }  /* ~22px base */

/* ——— 1. Design tokens —————————————————————————————————————————————————— */
:root {
  /* Marca: azul */
  --sl-blue:        #034D96;
  --sl-blue-600:    #023C77;
  --sl-blue-100:    #E6EEF7;
  --sl-blue-050:    #F3F7FB;

  /* Marca: rosa (acento) */
  --sl-pink:        #E33678;
  --sl-pink-600:    #C21F5F;
  --sl-pink-050:    #FDEEF4;

  /* Marca: púrpura (focus/realce) */
  --sl-purple:      #80388D;

  /* Acción destructiva (botón de eliminar) — ver .sl-btn--danger
     ⚠️ NO reutilizar "--sl-red" para esto: ese token ya existe más abajo con
     #D5384C y significa un ESTADO ("sin empezar / bloqueado", lo consume
     .sl-lock-btn--locked entre otros). Son dos cosas distintas que dio la
     casualidad de que son rojas; fundirlas ataría el color de un botón al de un
     estado y repintaría los candados al tocar cualquiera de los dos.
     El tono -600 es el mismo salto de luminosidad (-11 pp en HSL) que separa
     --sl-pink de --sl-pink-600, el par existente más parecido en tono y
     luminosidad: así el oscurecido al hover se siente igual que en el resto. */
  --sl-danger:      #E3274B;
  --sl-danger-600:  #BA1837;

  /* Marca de terceros: Clockify (integración de tiempos) — ver .sl-btn--clockify.
     #03A9F4 es el azul de marca de Clockify tal cual, deliberadamente distinto de
     --sl-blue (#034D96, la marca de SOFT LINE): identifica una acción de esa
     integración externa, no una acción propia de la app. El tinte "-050" sigue el
     mismo cálculo que --sl-blue-050/--sl-pink-050 (mezcla ~92% blanco). */
  --sl-clockify:    #03A9F4;
  --sl-clockify-050: #EBF8FE;

  /* Superficies */
  --sl-bg-page:     #FFFFFF;   /* fondo de página blanco; las cajas se definen por borde */
  --sl-bg-card:     #FFFFFF;
  --sl-bg-soft:     #FAFBFC;   /* zonas internas (cabeceras de panel/tabla): casi blanco */

  /* Bordes */
  --sl-border:      #babcbf;
  --sl-border-2:    #CFD6DE;
  --sl-border-3:    #eaeaea;

  /* Texto (fg-3 oscurecido a #6B7685 para cumplir contraste WCAG AA) */
  --sl-fg-1:        #034D96;
  --sl-fg-2:        #4A5B6F;
  --sl-fg-3:        #6B7685;
  --sl-grey:        #a2a2a2;

  /* Sombras */
  --sl-shadow-sm:   0 1px 2px rgba(3,77,150,.06);
  --sl-shadow-md:   0 4px 14px rgba(3,77,150,.08);
  --sl-shadow-card: 0 1px 2px rgba(3,77,150,.06), 0 4px 12px rgba(3,77,150,.04);

  /* Foco accesible */
  /* old foco --sl-focus:       0 0 0 3px rgba(128,56,141,.35);*/
  --sl-focus: 0 0 0 3px rgb(227 54 120 / 35%);

  /* Radios (en px: son cosméticos, no necesitan escalar) */
  /*
  --sl-radius-sm:   4px;
  --sl-radius-md:   8px;
  --sl-radius-lg:   12px;
  */
  --sl-radius-xxs: 6px;
  --sl-radius-sm:  8px;
  --sl-radius-md:  8px;
  --sl-radius-lg:   8px;
  --sl-radius-pill: 999px;

  /* Espaciado (escala 4px, en rem para que escale con la interfaz) */
  --sl-space-1: .25rem;
  --sl-space-2: .5rem;
  --sl-space-3: .75rem;
  --sl-space-4: 1rem;
  --sl-space-5: 1.5rem;

  /* Tipografía */
  --sl-font: 'Montserrat', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

  /* Alto de la barra inferior de la app (.sl-appfooter). En px y no en rem a
     propósito: es una franja de chrome, no texto de contenido, y no debe crecer
     con la preferencia de escala de la interfaz. */
  --sl-appfooter-h: 40px;

  /* Estados semánticos */
  --sl-state-progress: #ffa630;
  --sl-state-neutral:  #a8a8a8;
  --sl-state-done:     #5cb063;
  --sl-state-review:   #FF5C8D;
  --sl-state-urgent:   #FF5566;
}

/* ——— 2. Contenedor de página ——————————————————————————————————————————— */
/* Fondo de página blanco. El tema legacy pinta body { background:#eee }; como
   este CSS solo se carga en pantallas migradas, lo blanqueamos solo ahí (gana
   por orden de carga, sin !important). Las cajas se definen por su borde gris. */
body { background: var(--sl-bg-page); }

#sl-app {
  font-family: var(--sl-font);
  -webkit-font-smoothing: antialiased;
  color: var(--sl-fg-2);
  background: var(--sl-bg-page);
  min-height: 100%;
  /* Base para el texto legacy suelto que hereda (Bootstrap/Nice Admin lo dejaba en ~15px
     fijos, sin ligar a la escala). En rem para que ahora SÍ escale con data-ui-scale. */
  font-size: .875rem;
  /* Montserrat 400 + antialiasing se veía fino/desvaído; 500 (medium) mejora la legibilidad. */
  font-weight: 500;
}
/*.fa, .fa-brands, .fa-duotone, .fa-light, .fa-regular, .fa-solid, .fa-thin, .fab, .fad, .fal, .far, .fas, .fat {
  line-height: 0 !important;
}*/

/* ——— 3. Tipografía ————————————————————————————————————————————————————— */
.sl-title {
  font-size: 1.0625rem; font-weight: 700; color: var(--sl-blue);
  letter-spacing: -0.01em; margin: 0; line-height: 1.2;
}
.sl-title--sm { font-size: .8rem; font-weight: 600; color: var(--sl-blue); }

.sl-eyebrow {
  font-size: .8125rem;
  font-weight: 700;
  color: var(--sl-pink);
  line-height: 1.2;
}
.sl-label {
  font-size: .5625rem; font-weight: 800; letter-spacing: .12em;
  text-transform: uppercase; color: var(--sl-fg-3); margin: 0;
}
.sl-meta-label {
  font-size: 14px;
  font-weight: 500;
  letter-spacing: .01em;
  color: var(--sl-grey);
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sl-meta-value { font-size: .75rem; font-weight: 700; color: var(--sl-blue); line-height: 1.3; }
.sl-meta-value--pink { color: var(--sl-pink); }

.sl-text { font-size: .8125rem; font-weight: 400; color: var(--sl-fg-2); line-height: 1.45; }
.sl-text--muted { font-size: .6875rem; font-weight: 500; color: var(--sl-grey); }
/* Rosa de marca como color de texto suelto. Uso actual: la "Fecha prev." del listado de asuntos
   (asunto y encargo), que antes iba en texto normal / en un style="color:blue" inline. Se destaca
   porque es LA fecha que se mira en ese listado y comparte celda vecina con "Fecha cr.", que va en
   texto normal: sin color, ambas se confundian de un vistazo. */
.sl-text--pink { color: var(--sl-pink); }

/* ——— 4. Botones ———————————————————————————————————————————————————————— */
.sl-btn, #sl-app tr.footable-filtering .input-group .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .375rem;
  height: 32px; padding: 0 .75rem;
  font-family: var(--sl-font); font-size: .75rem; font-weight: 500; line-height: 1;
  color: var(--sl-fg-2);
  background: #fff; border: 1px solid var(--sl-border);
  border-radius: var(--sl-radius-sm);
  cursor: pointer; white-space: nowrap; text-decoration: none;
  transition: background .15s, color .15s, border-color .15s, box-shadow .15s, transform .1s;
}
.sl-btn:hover, #sl-app tr.footable-filtering .input-group .btn:hover { transform: translateY(-1px); text-decoration: none; }
.sl-btn:focus, #sl-app tr.footable-filtering .input-group .btn:focus { outline: none; box-shadow: var(--sl-focus); }
.sl-btn:active, #sl-app tr.footable-filtering .input-group .btn:active { transform: translateY(0); }
.sl-btn[disabled],
#sl-app tr.footable-filtering .input-group .btn[disabled],
.sl-btn.is-disabled,
#sl-app tr.footable-filtering .input-group .btn.is-disabled { opacity: .5; cursor: not-allowed; transform: none; }
/* Indicador con forma de botón pero que NO es un control: informa de un estado y no hace nada
   al pulsarlo (p.ej. "encargo creado por un cliente"). Mismo criterio que .sl-lock-btn.is-static
   para el candado sin permiso: si no hay acción, que no la prometa ni el cursor ni el hover. */
.sl-btn.is-static { cursor: default; }
.sl-btn.is-static:hover, .sl-btn.is-static:focus { transform: none; box-shadow: none; }
#sl-app tr.footable-filtering .input-group .input-group-addon, #sl-app tr.footable-filtering .input-group .input-group-btn {
  width: auto;
  display: flex;
  gap: 5px;
}
.sl-btn--primary, #sl-app tr.footable-filtering .input-group .btn-primary { background: var(--sl-blue); border-color: var(--sl-blue); color: #fff; }
/* :focus a propósito: "a:hover,a:focus{color:#0055b3}" del theme base pisa el color y deja el texto ilegible en un <a> enfocado. */
.sl-btn--primary:hover, .sl-btn--primary:focus, #sl-app tr.footable-filtering .input-group .btn-primary:hover { background-color: var(--sl-blue-600) !important; border-color: var(--sl-blue-600); color: #fff; }
.sl-btn--primary i { border: none !important; width: unset !important; line-height: 0; }

#sl-app tr.footable-filtering .input-group .input-group-btn .btn.btn-default { position: relative !important; }

.sl-btn--pink { background: var(--sl-pink); border-color: var(--sl-pink); color: #fff; }
.sl-btn--pink:hover, .sl-btn--pink:focus { background: var(--sl-pink-600); border-color: var(--sl-pink-600); color: #fff; }

.sl-btn--ghost { background: transparent; color: var(--sl-fg-2); }
.sl-btn--ghost:hover, .sl-btn--ghost:focus { background: var(--sl-blue); border-color: var(--sl-blue); color: #fff; }

/* Acción destructiva. Relleno sólido, no contorno: hasta 2026-09-14 era un botón
   "fantasma" (fondo transparente, borde gris, texto gris) que solo se teñía al pasar
   el ratón, así que en reposo era indistinguible del botón de editar de al lado —
   justo la acción de la que conviene distinguirlo. Ahora se lee de un vistazo.
   Estructura calcada de .sl-btn--primary, incluido el ":focus": no es simetría, es
   necesario — el theme base trae "a:hover,a:focus{color:#0055b3}" y varios de estos
   botones son <a>, así que sin él el texto se vuelve azul al enfocarlos. */
.sl-btn--danger { background: var(--sl-danger); border-color: var(--sl-danger); color: #fff; }
.sl-btn--danger:hover, .sl-btn--danger:focus { background-color: var(--sl-danger-600) !important; border-color: var(--sl-danger-600); color: #fff; }

/* Semáforo en forma de botón — .sl-btn--ok / .sl-btn--warn (2026-09-17).
   Nacen para los desplegables del resumen de la ficha de asunto
   (modules/resumen.asunto.pills.tpl), donde el COLOR DEL BOTÓN es el estado del grupo: verde
   todo acabado, rojo algo sin asignar o atrasado, ámbar algo esperando a alguien. Hasta ahora
   .sl-btn solo tenía --primary, --pink, --danger y --ghost, así que ese semáforo no se podía
   expresar con un botón; en pills sí, porque $pill_color acepta cualquier token de color.
   Estructura calcada de .sl-btn--danger, ":focus" incluido y por su mismo motivo: el theme base
   trae "a:hover,a:focus{color:#0055b3}" y estos botones pueden ser <a>.

   ⚠️ EL ÁMBAR NO LLEVA TEXTO BLANCO, y no es un descuido ni una asimetría gratuita. --sl-amber
      es #E2A900: blanco encima da 2,1:1, ilegible. Con --sl-blue-600 (#023C77, token que ya
      existe) sube a 5,17:1 y pasa AA sin inventar un color nuevo. Es la razón de que --warn sea
      el único botón sólido del sistema con tinta oscura; si alguien lo "corrige" a #fff por
      simetría, rompe la legibilidad.

   ⚠️ El verde SÍ lleva blanco, a 3,49:1, que se queda corto para AA en texto pequeño. Se deja
      así A PROPÓSITO: es exactamente el contraste que --sl-green ya tiene como texto sobre
      blanco en el resto de la app (.sl-copy.is-copied, los iconos de tarea hecha), de modo que
      no se introduce aquí un problema nuevo. Arreglarlo de verdad es tocar --sl-green, y eso
      repinta media aplicación — decisión de diseño, no de esta pantalla. Queda anotado. */
.sl-btn--ok { background: var(--sl-green); border-color: var(--sl-green); color: #fff; }
.sl-btn--ok:hover, .sl-btn--ok:focus { background-color: var(--sl-green-600) !important; border-color: var(--sl-green-600); color: #fff; }

.sl-btn--warn { background: var(--sl-amber); border-color: var(--sl-amber); color: var(--sl-blue-600); }
.sl-btn--warn:hover, .sl-btn--warn:focus { background-color: var(--sl-amber-600) !important; border-color: var(--sl-amber-600); color: var(--sl-blue-600); }

/* "Contorno", no relleno sólido — a propósito, para diferenciarlo de los botones de acción
   propia (--primary/--pink/--danger/...) de un botón que dispara una integración EXTERNA
   (Clockify). Misma receta que .sl-generic-id-badge (fondo claro del color + borde + texto/icono
   del mismo color, en vez de fondo sólido + texto blanco): fondo -050, borde y color en
   --sl-clockify. El :hover reutiliza el mismo "filter: brightness()" del id-badge en vez de un
   -600 sólido, porque aquí no hay relleno que oscurecer, solo un tinte claro. */
.sl-btn--clockify { background: var(--sl-clockify-050); border-color: var(--sl-clockify); color: var(--sl-clockify); }
.sl-btn--clockify:hover, .sl-btn--clockify:focus { filter: brightness(0.92); border-color: var(--sl-clockify); color: var(--sl-clockify); }

.sl-btn--pill { border-radius: var(--sl-radius-pill); }
.sl-btn--xs { /*height: 1.3rem;*/ height: 24px; padding: .3rem; }
.sl-btn--xxs { height: 1rem; padding: .3rem; border-radius: var(--sl-radius-xxs); }
.sl-btn--icon, #sl-app tr.footable-filtering .input-group .btn { width: 32px; min-width: 32px; max-width: 32px; padding: 0; }
.sl-btn--icon.sl-btn--xs { width: 24px; max-width: 24px; min-width: 24px; }
.sl-btn--icon.sl-btn--xxs { width: 1rem; }
.sl-btn--icon i, .sl-btn--icon.sl-btn--xs i {
  line-height: 0 !important;
}
.sl-btn--icon.sl-btn--xxs i {
  font-size: .60rem;
}

/* Flecha de dropdown que gira al abrirse el menú.
   Se pone JUNTO a la .caret de Bootstrap 3 (bootstrap-niceadmin-bundle-theme.css:2817), que
   es quien dibuja el triángulo con bordes: <span class="caret sl-caret"></span>. Aquí solo se
   añaden las tres cosas que le faltan, sin repetir la geometría:
     · el color del texto del botón en vez del negro fijo de Bootstrap,
     · el giro de 180° cuando el menú está abierto,
     · y quitarle el margin-left de BS3, porque .sl-btn ya separa con `gap`.
   El gancho del estado es el .open que Bootstrap pone en el PADRE del .dropdown-toggle, así
   que no hace falta ni una línea de JS. Genérico a propósito: vale para cualquier dropdown
   del design system, no solo para el de "Imprimir" de los encargos.
   El triángulo cabe entero en su caja de borde (8x4px) y el origen de la rotación es su
   centro, así que al girar no se desplaza ni un píxel. */
#sl-app .sl-caret {
  margin-left: 0;
  border-top-color: currentColor;
  /* En un .dropup, Bootstrap 3 apaga el borde superior y dibuja el triangulo con el
     INFERIOR, y ademas le clava el color negro literal
     (bootstrap-niceadmin-bundle-theme.css: ".dropup .caret { border-bottom: 4px solid #000 }").
     Sin esta linea, la flecha de los desplegables que se abren hacia arriba —los de
     documentos y fotos— sale negra en vez de tomar la tinta del boton. En un dropdown
     normal no hace nada: ahi ese borde mide 0. */
  border-bottom-color: currentColor;
  transition: transform .15s ease;
}
#sl-app .open > .dropdown-toggle .sl-caret { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  #sl-app .sl-caret { transition: none; }
}

/* Variante de botón-icono que además lleva un badge de notificación (contador),
   p.ej. los botones del header en modules/barra_top_right.tpl (ALERTAS, AVISOS,
   NOTIFICACIONES) y el botón "Abrir encargo" de asuntos.tpl (.sl-encargo-num-btn).
   Se añade JUNTO a las clases mínimas: "sl-btn sl-btn--primary sl-btn--icon
   sl-btn--icon-badge".
   El icono principal DEBE ser el primer hijo del botón, y debe quedar como el
   ÚNICO hijo que participa en el centrado flex de .sl-btn: cualquier otro hijo
   directo —el badge ".sl-badge-count", el <span class="username"> (subrayado de
   estado que viaja con los botones del header, ver span.num.alertas.tpl y
   barra_top_right.tpl), o un segundo <i> decorativo (p.ej. el candado
   ".encargo-blocked" de un encargo bloqueado, ver asuntos.tpl)— se saca del
   flujo con position:absolute (por eso ":not(:first-child)" y no ":not(i)": un
   segundo <i> también debe salir del flujo). Así el icono principal queda
   perfectamente centrado por el justify-content/align-items de .sl-btn en vez
   de compartir el centrado con esos elementos vecinos (antes el icono quedaba
   desplazado). La posición concreta de cada hijo adicional (badge en una
   esquina, candado en otra) la decide quien use la clase. */
.sl-btn--icon-badge {
  position: relative;
  overflow: visible;
}
.sl-btn--icon-badge > *:not(:first-child) {
  position: absolute;
}
/* El badge asoma en la esquina superior derecha (-6px) sin llegar a tapar el
   icono del todo. !important porque ".megaheader ul li .badge" (mega-design.css,
   bundleado en compiled.css) ya fija position:absolute;top:0;right:0 con la
   misma especificidad (0,2,2 vs 0,2,0 aquí): al empatar en nº de clases, gana
   por nº de selectores de tipo (ul, li), así que sin !important el badge se
   quedaría clavado en la esquina en vez de asomar hacia fuera. */
.sl-btn--icon-badge .sl-badge-count {
  top: -6px !important;
  right: -6px !important;
  left: auto !important;
}

/* --- Botón de adjudicación con las clases del sistema ---------------------
   modules/boton.adjudicacion.tpl es de los de antes: emite id="adjud" y TODA su geometría
   cuelga de ese id en css/style.css:8234 — "button#adjud { height:22px; width:23px }" más un
   "position:absolute" para el reloj y otro para el badge. Con esas medidas el botón salía a
   23x22 al lado de los 24x24 de sus vecinos en la cabecera de la tabla de partes, y se le
   notaba (usuario 2026-09-15). Medido, no estimado.

   No basta con darle las clases del sistema: "button#adjud" es (1,0,1) y le gana a
   ".sl-btn--xs" (0,1,0), así que la altura seguía siendo 22px. De ahí este bloque, que es un
   desempate de especificidad y nada más.

   ⚠️ Va acotado con ".sl-btn" a propósito, y eso NO es decoración: el mismo partial se pinta
      en los tres diálogos de proyectos (dialog.proyecto.listado.*) —que viven fuera de
      #sl-app y conservan sus clases de Bootstrap— y como fila del menú "+ Nuevo", donde
      lleva ".sl-menu__link". Ninguno de los tres tiene ".sl-btn", así que a ninguno le llega
      esto y se quedan exactamente como estaban.

   ⚠️ Las medidas se repiten aquí (24px) en vez de heredarse, y es inevitable: para ganarle a
      un selector de id hay que volver a declarar la propiedad. Si .sl-btn--xs cambia de
      altura, esto hay que cambiarlo con ella.

   El id, de paso, es un defecto en sí mismo: se emite una vez por fila, o sea que en una
   tabla de partes hay tantos id="adjud" como adjudicaciones. No se toca aquí porque es el
   gancho del que cuelga todo el CSS legacy de arriba. */
#sl-app button#adjud.sl-btn--xs { height: 24px; }
#sl-app button#adjud.sl-btn--icon.sl-btn--xs { width: 24px; min-width: 24px; max-width: 24px; }
/* El RELOJ vuelve al flujo para que lo centre el flex de .sl-btn, en vez de quedarse clavado
   en 2,2 como lo dejaba el CSS legacy para una caja de 23x22 — ahí dentro de 24x24 se salía
   por arriba y quedaba recortado.

   Y el BADGE (la marca de acción: + / ✓ / ✎) pasa a ser un DISCO del color del botón en la
   esquina inferior derecha, en vez del "background: none" que trae de css/style.css:8261.
   Esto no es cosmética, es lo único que lo hace visible, y costó dos intentos:

     1) Con el reloj centrado y el badge sin fondo, el "+" cae ENCIMA del reloj — y los dos
        son blancos. Blanco sobre blanco: el usuario lo reportó como "no se ve el icono".
     2) Sacándolo fuera del botón ("top:-5px; right:-5px", al estilo de .sl-btn--icon-badge)
        es peor: queda blanco sobre el fondo claro de la página. Invisible del todo, y sin un
        solo error en ninguna parte que lo delate.

   Con fondo propio, el badge recorta un hueco limpio en el reloj y se lee a 24px. Es el
   mismo recurso que usa cualquier icono-con-insignia; lo que no se puede reutilizar aquí es
   ".sl-badge-count", que es el círculo ROSA de los contadores del header y este badge no
   cuenta nada: marca qué hace el botón.

   El color va con var(--sl-blue) porque estos dos botones son siempre .sl-btn--primary
   (línea 201). Si algún día se pinta en otro color, esto hay que revisarlo. */
#sl-app button#adjud.sl-btn > i#icon { position: static; top: auto; left: auto; }
#sl-app button#adjud.sl-btn > span.badge {
  top: auto; bottom: -1px; right: -1px; left: auto;
  width: 11px; min-width: 11px; height: 11px;
  background: var(--sl-blue); border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 8px; line-height: 1;
}

/* --- Grupo de botones-badge del header (modules/barra_top_right.tpl) ------
   AYUDA / ALERTAS / BONO / AVISOS / NOTIFICACIONES: la tira de botones-icono del
   extremo derecho del header (.megaheader), fuera de #sl-app.

   Tres correcciones sobre lo que traía mega-design.css, las tres medidas en
   pantalla y no supuestas (1600px, cliente softline, bg_class="white-bg"):

   1) EL BADGE ATERRIZABA ENCIMA DEL BOTÓN DE AL LADO. El contador de AVISOS
      ocupaba 1536-1551 contra un botón que empieza en 1551.

      ⚠️ EL HUECO ENTRE BOTONES NO SE TOCA, Y ESO ES DELIBERADO. La primera
      versión de este arreglo ensanchaba el gap de 5px a .5rem, y era tratar el
      síntoma: el hueco de 5px ya IGUALA al del grupo de la izquierda del header
      (Asuntos, Comerciales, Llamadas...), que no usa gap ninguno sino el
      carácter de espacio que queda entre sus <a> en el HTML — mide 4-5px según
      el redondeo. Al subirlo, la derecha se veía más suelta que la izquierda.

      Lo que sobra es lo que ASOMA EL BADGE: la regla genérica de arriba lo saca
      -6px, más que el hueco entero. Aquí se mete a -3px, que con el hueco de
      5px deja 2px de aire —suficientes, porque el badge lleva su anillo blanco
      de 2px— y sigue leyéndose como un contador pegado a la esquina.

   2) EL BADGE DEL ÚLTIMO BOTÓN SE SALÍA DEL HEADER. La <ul> termina justo en el
      borde derecho del header (1588) y el badge llegaba a 1589. El padding va
      en la <ul> y no en el <header>, que lo comparte con el resto de la barra.

   3) EL BADGE NO ERA EL DEL SISTEMA DE DISEÑO. ".megaheader ul li .badge"
      (mega-design.css) fija width/height de 15px y ni anillo ni sombra;
      ".sl-badge-count" pide 17px + anillo blanco de 2px + sombra. Empatan en
      especificidad —(0,2,2) los dos: 2 clases y los tipos ul+li—, así que hasta
      ahora ganaba mega-design por ir declarado en compiled.css, que se carga
      ANTES que este archivo. Se repite aquí el mismo selector con los tipos
      ul+li para empatar y ganar por orden de cascada, sin !important.
      Ojo: NO vale escribirlo como ".megaheader .sl-badge-count" (0,2,0) —
      perdería el empate y volveríamos a los 15px.

   ⚠️ EL SELECTOR DE LA <ul> LLEVA ".nav" Y NO SOBRA. Lo que hay que ganarle es
   ".megaheader ul.nav.top-menu-avisos" (mega-design.css:764), que es (0,3,1).
   Escribirlo aquí como ".megaheader ul.top-menu-avisos" —que es lo natural, y
   lo que se probó primero— da (0,2,1) y PIERDE: el orden de cascada solo
   desempata cuando la especificidad empata. Medido. */
.megaheader ul.nav.top-menu-avisos {
  /* gap: NO se declara. El de 5px de mega-design.css es el bueno: iguala al del
     grupo de la izquierda del header. Ver el punto 1) de arriba. */
  padding-right: 3px;
}
.megaheader ul li .sl-badge-count {
  width: 17px; height: 17px; min-width: 17px;
  border: 2px solid #fff;
  box-shadow: 0 1px 2px rgba(0,0,0,.25);
}
/* El badge asoma menos que en el resto de la aplicación, para caber en el hueco
   de 5px del header sin pisar al vecino (punto 1). Acotado a esta <ul> y no
   cambiado en la regla genérica: el otro sitio que usa .sl-btn--icon-badge es el
   botón "Abrir encargo" de asuntos.tpl, que no está en una tira apretada y donde
   el -6px de serie está bien.
   Lleva !important porque el que se está pisando también lo lleva; entre dos
   declaraciones !important gana la más específica, y esta es (0,4,1) contra
   (0,2,0). */
.megaheader ul.nav.top-menu-avisos .sl-badge-count {
  top: -3px !important;
  right: -3px !important;
}

/* EL BADGE DE "ALERTAS" NO SE POSICIONABA CONTRA SU BOTÓN, sino contra un
   contenedor intermedio, y acababa flotando hacia el hueco que queda a su
   izquierda, entre AYUDA y ALERTAS (usuario 2026-09-15). Medido, no supuesto:
   el badge caía en x=1423 cuando la esquina del botón está en x=1453 — 30px
   a la izquierda y 15px por debajo de donde tenía que estar.

   La causa es que ALERTAS es el ÚNICO de los cinco botones cuyo badge NO es
   hijo directo del <a>: va envuelto en <span id="num_alertas">, y ese
   envoltorio NO sobra — es el ANCLA DE REFRESCO por AJAX. usuarios_alertas.php
   lo nombra en 'update_elements' para repintar modules/span.num.alertas.tpl
   entero (badge + subrayado, que son DOS elementos) al crear o borrar una
   alerta, así que hace falta un único elemento al que sustituirle el interior.

   Lo que rompe es que el envoltorio sí es hijo directo, con lo que la regla
   genérica de arriba (".sl-btn--icon-badge > *:not(:first-child)") le da
   'position:absolute' con todos los offsets en auto: se queda en su posición
   estática —el CENTRO del botón, porque .sl-btn es flex con justify/align
   center— y con caja de 0x0. Y al quedar POSICIONADO, pasa a ser el bloque
   contenedor del badge que lleva dentro: el "top/right: -3px" de la regla de
   arriba deja de medirse desde la esquina del botón y se mide desde ese punto
   central. El badge nunca estuvo mal colocado; estaba midiendo desde otro
   sitio.

   Se le clava al envoltorio una caja de 0x0 en la esquina superior derecha del
   botón. Sigue fuera del flujo (el icono se centra igual, comprobado) y sigue
   sin pintar nada (el <span class="username"> de dentro queda también a 0x0,
   como en los demás botones), pero ahora el badge mide sus -3px desde donde
   debe. Comprobado midiendo los dos: ALERTAS y NOTIFICACIONES dan exactamente
   el mismo desplazamiento respecto a su botón (-2px arriba y -2px a la derecha
   del borde) y el mismo tamaño (17x17).

   Va por id y no por clase a propósito: esto no es vocabulario nuevo del
   sistema de diseño, es el desempate de un caso concreto — igual que el bloque
   de "button#adjud" de más arriba. Si algún día un segundo botón necesita un
   envoltorio-ancla así, ENTONCES toca convertirlo en clase. */
.megaheader .sl-btn--icon-badge > #num_alertas {
  top: 0; right: 0;
  width: 0; height: 0;
}

/* El <li> del aviso "Error de JavaScript" (#resaltar_error_js) está vacío el
   99,9% del tiempo, pero un flex item de ancho 0 SIGUE consumiendo su gap. Se
   oculta el <li> entero y lo enseña window.onerror (modules/js/common.tpl.js),
   que ya tocaba el padre para el margen. Hace falta ocultar el <li> y no solo
   el <a>: el gap lo reparte el contenedor entre sus items, no entre lo que se
   ve dentro de ellos. */
.megaheader ul.top-menu-avisos > li.li-error-js { display: none; }

/* NOTA: el botón de AYUDA del header (modules/manual_boton_header.tpl) NO lleva
   punto de "manual desfasado" y por eso aquí no hay ninguna clase para él. El
   motivo está escrito en esa plantilla: calcularlo obligaría a cargar lib_manual
   sin configurar en cada página, para obtener siempre false. */

/* --- Botón del manual en el PIE de los diálogos --------------------------
   Las dos clases las pone la librería del manual (manual/boton.tpl con pie=1), que
   mueve el <a> al .modal-footer; el aspecto lo decide cada proyecto, y aquí es el
   del sistema de diseño. Las clases del <a> vienen de my_controller.php
   ($manual_boton_dialogo_vars), así que esto es solo la COLOCACIÓN.

   Absoluto a la izquierda y no un float: el pie es "display:block; text-align:center"
   y lo que hay dentro es un único <div> con los botones del diálogo, centrado. Un
   float lo desplazaría —Cerrar dejaría de estar en el centro del diálogo para estar
   en el centro del hueco sobrante—, mientras que sacándolo del flujo los botones de
   verdad no se enteran de que hay algo a su lado.

   El pie ya tiene su padding vertical, así que el botón se centra con top/translate
   en vez de fijar una altura que tendría que perseguir a la del pie. */
.modal-footer.phman-pie { position: relative; }
.phman-boton--pie {
  position: absolute;
  left: 18px;               /* el padding lateral del pie de bootstrap-dialog */
  top: 50%;
  transform: translateY(-50%);
}
/* .sl-btn levanta el botón 1px al pasar el ratón (translateY(-1px)), y ese transform
   PISARÍA al de centrado, dejándolo caer a la mitad de su alto justo al apuntarlo.
   Se recompone entero: primero el centrado, luego el gesto. */
.phman-boton--pie:hover, .phman-boton--pie:focus {
  transform: translateY(-50%) translateY(-1px);
}
@media (max-width: 575.98px) {
  /* En móvil el pie se queda sin sitio: el botón vuelve al flujo, arriba del todo. */
  .phman-boton--pie { position: static; transform: none; display: inline-flex; margin: 0 0 .5rem; }
  .phman-boton--pie:hover, .phman-boton--pie:focus { transform: translateY(-1px); }
}

/* --- Copiar al portapapeles (components/copy-btn.tpl) ---------------------
   Un <button> que se hace pasar por el texto que envuelve: NO fija ni tamaño, ni peso, ni color
   de fuente, y hereda todo del sitio donde se coloca vía $copy_class (p.ej. "sl-meta-label
   color-blue" en la cabecera del asunto). Así el nº de asunto se sigue viendo exactamente igual
   que antes de ser pulsable — lo único que se añade es el icono de la derecha.
   Es un <button> de verdad, no un <span onclick>: entra en el orden de tabulación y se activa
   con Enter/Espacio sin escribir una línea de JS. */
/* El reset de tipografía va en :where(), que vale CERO de especificidad: así le gana a la hoja
   del navegador (que pondría Arial 13.3px en un <button>) pero pierde contra CUALQUIER clase que
   le pase quien lo usa. Con un ".sl-copy { font: inherit }" normal pasaba lo contrario: empata en
   especificidad con .sl-meta-label y, al estar declarado más abajo en este archivo, ganaba el
   reset y el nº de asunto salía a 16px en vez de a los 14px que le tocaban. Medido, no supuesto. */
:where(.sl-copy) {
  font: inherit;
  color: inherit;
  text-align: inherit;
}
.sl-copy {
  display: inline-flex;
  align-items: baseline;
  vertical-align: middle;
  gap: .375rem;
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  -webkit-appearance: none;
          appearance: none;
}
/* El icono está siempre, pero atenuado: si solo apareciera al pasar por encima nadie sabría que
   el número se puede copiar sin tropezarse con ello por casualidad. Al 45% no compite con el
   dato, y sube a pleno color en hover/foco. */
.sl-copy__icon {
  flex: none;
  font-size: .8125em;
  line-height: 1;
  transition: opacity .15s, color .15s;
}
.sl-copy:focus-visible {
  outline: 2px solid var(--sl-blue);
  outline-offset: 2px;
  border-radius: var(--sl-radius-xxs);
}
/* Confirmación local, mientras sl_copy() mantiene la clase (1,2 s). El aviso de copyClipboard()
   sale en una esquina; esto confirma en el propio elemento QUÉ se ha copiado. */
.sl-copy.is-copied .sl-copy__icon { opacity: 1; color: var(--sl-green); }
@media (prefers-reduced-motion: reduce) {
  .sl-copy__icon { transition: none; }
}

/* NOTA: el componente ".sl-generic-pill" (components/pill.tpl) vivía aquí y se ha movido a
   css/filtros-grid.css — es exclusivamente de los paneles de filtro, no de uso general. */

/* ——— 5. Píldoras, badges y etiquetas ——————————————————————————————————— */
.sl-pill {
  display: inline-flex; align-items: center;
  font-size: .625rem; font-weight: 400; letter-spacing: .06em; text-transform: uppercase;
  color: #fff; border: 1px solid transparent; border-radius: var(--sl-radius-pill);
  padding: .4375rem .375rem; line-height: 1; white-space: nowrap;
}
.sl-pill--status { background: var(--sl-pill-color, var(--sl-blue)); }

/* ".sl-badge-urgent" vivía aquí y se ha RETIRADO (2026-09-11): era una copia literal de .sl-pill
   con el color de urgente incrustado — declaración por declaración idénticas, salvo un
   "border: 1px solid var(--sl-state-urgent)" que sobre un fondo de ese mismo color es invisible.
   Sus 4 usos (los dos bloques de "N vencidas" de la home, el "%" de backlog del dashboard
   Ejecutivo y el "Sin email configurado" del extracto) pasan a la forma canónica, que es la que
   ya usaba la rama hermana del mismo <%if%> en home.executive.tpl:
       <span class="sl-pill sl-pill--status" style="--sl-pill-color: var(--sl-state-urgent);">
   Se había quedado comentada en r7079 con los 4 usos vivos, así que esos badges se veían como
   texto suelto sin pastilla. */

.sl-tag {
  display: inline-flex; align-items: center; gap: .25rem;
  font-size: .5625rem; font-weight: 700; color: var(--sl-blue); background: var(--sl-blue-100);
  border-radius: var(--sl-radius-pill); padding: .1875rem .5rem;
  white-space: nowrap; max-width: 8.75rem; overflow: hidden; text-overflow: ellipsis;
}

.sl-pill--outline {
  display: inline-flex; align-items: center;
  font-size: .625rem; font-weight: 400; letter-spacing: .06em; text-transform: uppercase;
  color: var(--sl-state-done); background: transparent;
  border: 1px solid var(--sl-state-done); border-radius: var(--sl-radius-pill);
  padding: .4375rem .375rem; line-height: 1; white-space: nowrap;
}

/* Badge numérico genérico (contador): círculo rosa reutilizable en cualquier parte de
   la UI (tabs, listados, menús...) para marcar recuentos — mismo estilo exacto que el
   badge del header (.megaheader ul.top-menu-avisos ... .badge: círculo, anillo blanco,
   sombra), pero como clase de uso general en vez de acoplada a ese selector concreto. */
.sl-badge-count {
  display: inline-flex; align-items: center; justify-content: center;
  width: 17px; height: 17px; padding: 0;
  border-radius: 50%;
  background: var(--sl-pink); color: #fff;
  font-size: 9px; font-weight: 700; line-height: 1;
  border: 2px solid #fff;
  box-shadow: 0 1px 2px rgba(0,0,0,.25);
  vertical-align: middle;
}

/* Marca de campo restringido por nivel de usuario (components/nivel-badge.tpl).
   Un badge rojo PEGADO al texto de la etiqueta, para los campos que solo ve un usuario a
   partir de cierto nivel — hoy "Importe" y "Desviación" del panel Seguimiento de la ficha de
   asunto, visibles solo para nivel 9. Sustituye a la convención anterior, que era pintar la
   etiqueta en rosa y añadirle el sufijo "(nivel 9)" al texto: el rosa ya significa "dato
   destacado" en esta ficha (Fecha prevista, Horas previstas) y no "dato restringido", y el
   sufijo se comía la mitad del ancho de una celda de 1/4 de panel — a petición del usuario
   2026-09-10.

   DOS CLASES, porque el badge y la etiqueta son HERMANOS y hace falta alguien que los ponga
   en la misma línea:
     · .sl-nivel-labelrow → envuelve etiqueta + badge, y es quien los alinea.
     · .sl-nivel-badge    → el badge en sí.

   El envoltorio es "inline-flex" y NO "flex" para que valga también dentro de un <th> de
   cabecera de tabla (la columna "Mapa" de partes.tpl, que solo ve el nivel 9): siendo flex
   ocuparía todo el ancho del <th> y el rótulo se iría a la izquierda, ignorando el
   text-align:center de la celda. Inline-flex se ajusta al contenido y se deja centrar. En la
   ficha de asunto no cambia nada: ahí el envoltorio es hijo de un contenedor flex, y un flex
   item "inline-flex" se blockifica a "flex" por definición.

   ⚠️ El badge es HERMANO de .sl-meta-label, NO va dentro: la etiqueta puede llevar su propio
   tooltip (lo lleva "Desviación", con las horas presupuestadas) y anidar un elemento con
   data-toggle="tooltip" dentro de otro dispara los DOS al pasar el ratón por el hijo.

   El badge no encoge (flex:0 0 auto) y la etiqueta sí (min-width:0): si la etiqueta no cabe,
   lo que se corta con "…" es el TEXTO —que para eso .sl-meta-label ya trae overflow:hidden +
   text-overflow:ellipsis— y nunca el badge, que es el dato que no se puede perder.

   min-width + radio de píldora (en vez de width fijo + 50% como .sl-badge-count) para que la
   MISMA clase valga tanto para un "9" —círculo perfecto— como para un "NIVEL 9" —píldora—, y
   el texto sea cosa de quien lo usa. Sin el anillo blanco ni la sombra de .sl-badge-count:
   ahí sirven para despegar el badge del icono que tiene DEBAJO, y aquí no hay nada debajo —
   engordaban el círculo 4px sin aportar nada. */
.sl-nivel-labelrow {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  min-width: 0;
}
.sl-nivel-labelrow > .sl-meta-label {
  min-width: 0;
}
.sl-nivel-badge {
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
  min-width: 16px; height: 16px;
  padding: 0 .25rem;
  border-radius: var(--sl-radius-pill);
  background: var(--sl-nivel-badge-color, var(--sl-red));
  color: #fff;
  font-size: 9px; font-weight: 700; letter-spacing: .04em; line-height: 1;
  white-space: nowrap;
  cursor: default;
}

/* Insignia de ID (asunto/encargo): letra de tipo suelta arriba, número grande debajo.
   components/id-badge.tpl. Genérica a propósito — el tipo ('A'/'E') y el número los decide quien
   la incluye, ver el comentario del propio .tpl. La letra NO lleva círculo/fondo propio (decisión
   explícita del usuario 2026-08-28: "la A suelta") — es texto normal, un peldaño más claro que el
   número para que quede claramente en segundo plano respecto a él. */
.sl-generic-id-badge {
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  min-width: 50px;
  min-height: 50px;
  background: var(--sl-blue-050);
  border: 1px solid var(--sl-border);
  border-radius: var(--sl-radius-card);
  padding: .3125rem .375rem;
  /* position:relative solo para anclar ".sl-generic-id-badge__badge" (badge de esquina opcional,
     ver $idb_badge_icon en components/id-badge.tpl) — sin offset propio, no cambia el layout de
     los badges que no lo usan. */
  position: relative;
}
.sl-generic-id-badge:hover {
  filter: brightness(0.9);
}
.sl-generic-id-badge[onclick] { cursor: pointer; }
.sl-generic-id-badge__tipo {
  font-size: 16px;
  font-weight: 900;
  line-height: 1;
  color: var(--sl-blue);
  font-family: var(--sl-font);
}
.sl-generic-id-badge__num {
  font-weight: 600;
  line-height: 1.1;
  color: var(--sl-blue);
  white-space: nowrap;
  font-family: Inconsolata;
  font-size: 14px;
}
.sl-generic-id-badge__num .cod-legacy { white-space: nowrap; } /* ver get_ref_interna() en asunto_model.php */

/* Badge de esquina del id-badge ($idb_badge_icon en components/id-badge.tpl): burbuja circular
   blanca superpuesta en la esquina superior DERECHA de la tarjeta. Esta regla es además la BASE
   de las dos esquinas: la izquierda es el modificador "--left" de aquí abajo, que solo cambia de
   qué borde cuelga. Ojo, el comentario decía "izquierda" desde que se escribió y era falso — con
   una sola plaza daba igual, con dos no. Genérica a propósito — el
   icono, el color y la rotación los decide quien la incluye, vía las variables puente
   --sl-generic-id-badge-badge-color/-rotate (mismo mecanismo que --sl-generic-pill-color en
   pill.tpl/filtros-grid.css), cada una con un valor por defecto sensato si no se pasan.
   Empezó siendo SOLO el candado ($idb_locked, mismo icono/color/rotación que ".candado-block", el
   candado de "asunto bloqueado" del listado más arriba en este archivo) — se generalizó a petición
   del usuario 2026-09-02 para poder reusar la misma burbuja con cualquier icono, por ejemplo el
   "ojito" de visible-por-cliente que antes vivía suelto y mal posicionado en
   ".asunto-marcas-clientes" (asuntos.tpl).

   El candado del listado de asuntos acabó también aquí (2026-09-02): antes iba pegado al título
   de la columna "Asunto" sobre un halo rosa de fondo (".content-candado-block", con un recorte
   calibrado a mano para simular el asa "enganchada") — el usuario lo quiso como el "ojito", así
   que esa clase y su halo se borraron de este archivo por quedar sin uso. Poco después cayó
   igual el candado de la ficha (dialog.ficha.tpl), que era un ".candado-block" suelto dentro
   de ".sl-ficha-title": siendo position:absolute sin ancestro posicionado, se anclaba al
   contenedor de la modal y salía lejos del título. Con eso ".candado-block" se quedó sin
   usos y también está borrada — este badge es hoy el ÚNICO candado de asunto bloqueado.

   ⚠️ "background" lee la variable puente, no --sl-pink a pelo: hasta 2026-09-02 la regla tenía
   "background: var(--sl-pink)" fija, así que --sl-generic-id-badge-badge-color se escribía en el
   inline style del <i> y NADIE la leía — el "ojito" del encargo pedía var(--sl-blue) y salía
   rosa. El fallback mantiene el rosa para quien no pase color (p.ej. $idb_locked). */
.sl-generic-id-badge__badge {
  position: absolute;
  top: -4px;
  right: -4px;
  font-size: 9px;
  color: white;
  background: var(--sl-generic-id-badge-badge-color, var(--sl-pink));
  border: 1px solid white;
  border-radius: 50%;
  width: 17px;
  height: 17px;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: rotate(var(--sl-generic-id-badge-badge-rotate, 0deg));
}

/* Plaza IZQUIERDA de esa misma burbuja ($idb_badge_left_* / $idb_fav en components/id-badge.tpl).
   Modificador y no clase suelta a propósito: así las métricas (17x17, borde blanco, radio,
   centrado, la variable puente del color) siguen viviendo en UN solo sitio y las dos esquinas no
   pueden separarse por descuido. Lo único que cambia es de qué borde cuelga.

   "right: auto" no es de adorno: la regla base fija "right:-4px", y dejar los dos puestos deja la
   caja sobre-restringida (left + right + width a la vez), un caso que el navegador resuelve
   descartando uno de los dos según la dirección del texto. Anclar por un solo borde quita esa
   ambigüedad en vez de confiar en cuál de los dos gana.

   Nació (2026-09-14) para el corazón de favorito del listado de asuntos, que hasta entonces era
   un ".es_favorito" con float:right SUELTO dentro del <td>, hermano del badge y no hijo suyo: no
   estaba anclado a nada, solo caía cerca, y se veía descolgado. Es el mismo fallo que ya tuvieron
   el candado y el "ojito" antes de mudarse a este componente, y esa clase ya no existe. */
.sl-generic-id-badge__badge--left {
  right: auto;
  left: -4px;
}

/* --- Beacon: aviso con piloto de luz (components/beacon.tpl) --------------
   Sustituto en CSS del viejo "¡Cliente con alertas!" (.cliente-con-alertas + img/alarma.webp
   girado con drop-shadow animado, css/style.css:8685). Aquel desentonaba al lado de las pills
   de la cabecera del asunto: 14px contra 11px, radio 4px contra radio de píldora, y 3px más
   alto. Este toma prestadas las MÉTRICAS EXACTAS de .sl-generic-pill (ver filtros-grid.css)
   para que sea una hermana de las pills de al lado, y concentra todo el efecto en la lámpara.

   Un solo color de entrada, --sl-beacon-color, del que salen lente, anillo, halo, borde,
   relleno y texto — mismo puente que --sl-generic-pill-color en components/pill.tpl.

   TRES animaciones a 1,4s y en fase, que son la MISMA idea contada tres veces (una luz que
   late), no tres efectos sueltos:
     · --lamp  la lente sube y baja de brillo
     · --ring  un anillo sale de la lente y se desvanece
     · --halo  la caja recibe ese destello en su sombra   ← es el heredero directo del
               drop-shadow rojo del .webp, que es lo que había que conservar. */
.sl-beacon {
  --sl-beacon-color: var(--sl-red);
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  margin: 0;
  /* Menos padding a la izquierda que a la derecha: la lente es un círculo y con el padding
     simétrico la pill queda visualmente descentrada hacia la derecha (mismo ajuste que hace
     .sl-generic-pill:has(> .sl-generic-pill__swatch) en filtros-grid.css). */
  padding: .1875rem .5rem .1875rem .375rem;
  font: 600 .6875rem/1.4 var(--sl-font);
  /* Exactamente los colores de .sl-generic-pill--tag (borde a color pleno, relleno al 12%, texto
     del mismo color). Se probó una variante de relleno macizo con texto blanco: destaca más, pero
     rompe la familia —en esta app TODAS las pastillas son de relleno traslúcido— y la lente
     blanca se ve gris en la fase baja del latido. Igualando la caja a la pill de siempre, lo
     ÚNICO que distingue a este aviso de sus vecinas es la lámpara, que es justo lo que se quería. */
  color: var(--sl-beacon-color);
  background: rgba(213, 56, 76, .12); /* fallback si el navegador no soporta color-mix() */
  background: color-mix(in srgb, var(--sl-beacon-color) 12%, transparent);
  border: 1px solid var(--sl-beacon-color);
  border-radius: var(--sl-radius-pill);
  white-space: nowrap;
  -webkit-appearance: none;
          appearance: none;
  animation: sl-beacon-halo 1.4s ease-in-out infinite;
}
button.sl-beacon { cursor: pointer; }
button.sl-beacon:hover { background: color-mix(in srgb, var(--sl-beacon-color) 22%, transparent); }
button.sl-beacon:focus-visible {
  outline: 2px solid var(--sl-beacon-color);
  outline-offset: 2px;
}
/* La lente. El radial-gradient le da la cúpula de vidrio: sin ese reflejo arriba a la izquierda
   es un punto plano, no una luz. */
.sl-beacon__lamp {
  position: relative;
  flex: none;
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 28%, rgba(255, 255, 255, .75), transparent 55%),
    var(--sl-beacon-color);
  animation: sl-beacon-lamp 1.4s ease-in-out infinite;
}
/* El anillo va con "border" y relleno transparente, y NO como un círculo sólido detrás con
   z-index negativo: así puede crecer por encima de la lente sin taparla y sin depender del
   contexto de apilamento del <button>. */
.sl-beacon__lamp::before {
  content: '';
  position: absolute;
  inset: -1px;
  border: 1px solid var(--sl-beacon-color);
  border-radius: 50%;
  animation: sl-beacon-ring 1.4s ease-out infinite;
}
@keyframes sl-beacon-lamp {
  0%, 100% { filter: brightness(.75); }
  50%      { filter: brightness(1.3); }
}
@keyframes sl-beacon-ring {
  0%       { transform: scale(.6); opacity: .85; }
  75%,100% { transform: scale(2.9); opacity: 0; }
}
@keyframes sl-beacon-halo {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  50%      { box-shadow: 0 0 .625rem -.0625rem color-mix(in srgb, var(--sl-beacon-color) 55%, transparent); }
}
/* Sin movimiento, pero SIN perder el aviso: la luz se queda encendida y con su halo fijo, que es
   la información; lo que se quita es el latido. */
@media (prefers-reduced-motion: reduce) {
  .sl-beacon,
  .sl-beacon__lamp,
  .sl-beacon__lamp::before { animation: none; }
  .sl-beacon { box-shadow: 0 0 .5rem -.0625rem color-mix(in srgb, var(--sl-beacon-color) 45%, transparent); }
  .sl-beacon__lamp::before { opacity: .45; transform: scale(1.9); }
}

/* ——— 6. Tarjetas ——————————————————————————————————————————————————————— */
.sl-card {
  position: relative;
  background: var(--sl-bg-card);
  border: 1px solid var(--sl-border);
  border-radius: var(--sl-radius-lg);
  margin-bottom: .4375rem;
  cursor: pointer;
  transition: border-color .15s, transform .1s;
}
.sl-card:hover { border-color: var(--sl-border-2); transform: translateY(-1px); }
.sl-card--accent { border-top: 2px solid var(--sl-card-accent, var(--sl-blue)); }
.sl-card--urgent { border: 3px solid #edb7c4; }
/* Tarjeta "vacía"/sin vincular (ej. llamadas sin cliente asociado): mismo tamaño que las demás
   de la rejilla, pero visualmente secundaria — no es un cliente real. */
.sl-card--muted { border-style: dashed; opacity: .82; }

.sl-card__body { padding: .75rem; }

.sl-card__title {
  display: inline-block;
  font-size: .8125rem; font-weight: 700; color: var(--sl-blue);
  line-height: 1.35; word-break: break-word; margin-bottom: .25rem; text-decoration: none;
}
.sl-card__title:hover { color: var(--sl-pink); text-decoration: none; }

.sl-card-meta {
  display: flex; gap: .5rem; flex-wrap: wrap;
  margin-top: .375rem; padding-top: .375rem; border-top: 1px solid var(--sl-border);
}
.sl-meta-block { display: flex; flex-direction: column; min-width: 0; }
.sl-meta-sep { width: 1px; background: var(--sl-border); align-self: stretch; margin: .125rem 0; }

.sl-card__action {
  position: absolute; top: .3125rem; right: .3125rem;
  width: 1.25rem; height: 1.25rem; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--sl-radius-sm); font-size: .625rem; line-height: 1;
  background: transparent; border: 1px solid transparent; color: var(--sl-fg-3);
  opacity: 0; cursor: pointer;
  transition: opacity .15s, background .15s, color .15s;
}
.sl-card:hover .sl-card__action { opacity: 1; }
.sl-card__action:hover { background: var(--sl-pink-050); border-color: var(--sl-pink); color: var(--sl-pink); }

/* ——— 6b. Cabecera de sección ——————————————————————————————————————————— */
.sl-page-header {
  display: flex; align-items: center; gap: .625rem;
  margin: 0 0 1rem; padding: 0 0 .625rem;
  font-size: 1.125rem; font-weight: 700; color: var(--sl-blue);
  line-height: 1.2;
}
.sl-page-header > i:first-child {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.875rem; height: 1.875rem; flex-shrink: 0;
  font-size: .875rem; color: var(--sl-blue);
  background: var(--sl-blue-100); border-radius: var(--sl-radius-md);
}
.sl-page-header--pink > i:first-child { color: var(--sl-pink); background: var(--sl-pink-050); }

/* ——— 6c. Panel estático (contenedor con cabecera) ——————————————————————— */
.sl-panel {
  background: var(--sl-bg-card); border: 1px solid var(--sl-border);
  border-radius: var(--sl-radius-md); box-shadow: var(--sl-shadow-sm);
  margin-bottom: 1rem; overflow: hidden;
}
.sl-panel__header {
  padding: var(--sl-space-2); /*border-bottom: 1px solid var(--sl-border);*/
  background: var(--sl-blue-050);
  font-size: .8125rem; font-weight: 600; color: var(--sl-blue); letter-spacing: .02em;
}

.sl-panel div:not(.collapse) .sl-panel__body:first-child > .sl-ficha-field-group {
  border-top: 0;
}
#asunto-encargos .sl-panel__header {
  border-bottom: 0;
}
.sl-panel__header > button.sl-disclosure__trigger {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--sl-blue);
  letter-spacing: .02em;
}
/* La barra de herramientas del bloque de encargos (título + filtros + acciones) pone su propio
   padding en .sl-enc-toolbar__aside, así que la cabecera no debe añadir el suyo. OJO: esta regla
   estuvo un tiempo como "#sl-app #encargos .sl-panel__header", y alcanzaba también a las
   cabeceras de las tarjetas de DENTRO del encargo (Estado y acciones, Datos del encargo, Notas,
   las tablas…), que se quedaban con el texto pegado al borde izquierdo mientras las del asunto
   sí tenían padding. Al pedir el usuario que las secciones del encargo se vieran igual que las
   del asunto (2026-09-10) se acotó a la barra, que es la única que lo necesitaba. */
#sl-app #encargos > .sl-enc-toolbar.sl-panel__header {
  padding: 0;
}
.sl-panel__header .sl-disclosure__chevron i {
  margin-right: 5px;
}
/* Cabecera con un botón de acción a la derecha del todo (ej. "Reclamar" en el panel Seguimiento
   de asunto.info.tpl): normalmente TODA la cabecera es el propio <button> de colapsar
   (.sl-panel__header.sl-disclosure__trigger en el mismo elemento), pero un <button> no puede
   contener otro <button> — así que aquí .sl-panel__header pasa a un <div> que aloja los dos en
   fila, el trigger de colapsar a la izquierda y el resto a la derecha. El trigger interior pierde
   su propio padding/borde (ya los pone este div) para que el texto quede exactamente en el mismo
   sitio que en las cabeceras de un único <button> (Cliente, Información, Notas) — a petición del
   usuario 2026-09-08. */
.sl-panel__header--row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
}
/* ——— Filtro dentro de la cabecera de un panel ————————————————————————————————————————
   Para que un filtro puesto en un .sl-panel__header se vea igual que el buscador de
   /asuntos, reutilizando su mismo markup (.panel-left-form > .sl-topbar-search > .sl-sf,
   ver modules/asuntos.filtros.tpl). Primer uso: la pestaña Auditoría de la ficha de asunto.

   ⚠️ Estas clases NO visten por sí solas: en /asuntos todo su aspecto viene de dos reglas
   ancladas a dónde viven, y ninguna de las dos alcanza a una cabecera de panel —
       "#sl-app .panel-heading .panel-left .panel-left-form form"  (más abajo en este archivo)
       "#sl-app .sl-topbar form#buscador_titulos .sl-sf"           (mega-design.css)
   La segunda está anclada al ID del formulario, así que ni siquiera basta con replicar las
   clases. Sin este bloque, el filtro sale sin flex, sin gap y con el label a tamaño de texto.

   Se declara aquí y no en mega-design.css a propósito: ese archivo solo llega al navegador
   dentro de css/crunch/compiled.css y obliga a pasar crunch-css-js.bat, mientras que
   softline-ui.css se carga directo (ver head.tpl) y además gana por orden de cascada.

   ⚠️ NO se estiliza el input. El de /asuntos lleva .form-control, y Bootstrap declara
   ".form-control { width: 100% }": en un filtro estrecho eso lo revienta. El input se queda
   con .sl-input —que no declara width— para que mande su atributo size. */
#sl-app .sl-panel__header .panel-left-form,
#sl-app .sl-panel__header .sl-topbar-search,
#sl-app .sl-panel__header .sl-topbar-search .sl-sf {
  display: flex;
  align-items: center;
  margin: 0;
}
#sl-app .sl-panel__header .sl-topbar-search {
  flex-wrap: wrap;
  gap: .375rem .875rem;
}
#sl-app .sl-panel__header .sl-topbar-search .sl-sf {
  gap: .375rem;
}
#sl-app .sl-panel__header .sl-topbar-search label.label-filtros-sin-cabecera {
  margin: 0;
  line-height: 1.1;
  font-size: .75rem;
  font-weight: 600;
  color: var(--sl-fg-3);
  white-space: nowrap;
}
.sl-panel__header--row > .sl-disclosure__trigger {
  padding: 0;
  border: 0;
  /* ⚠️ Para que .sl-disclosure__summary pueda truncar. El trigger es a la vez flex ITEM de esta
     cabecera y flex CONTAINER del resumen, y un flex item nace con min-width:auto, que resuelve
     a min-content — y el min-content de un texto con white-space:nowrap es la CADENA ENTERA. Sin
     este 0 el trigger se niega a encoger: medido, un resumen largo ocupaba 1234px dentro de una
     cabecera de 476px. Y no se veía como scroll porque .sl-panel lleva overflow:hidden, así que
     el desbordamiento se recortaba en silencio: en "Seguimiento" eso se lleva por delante el
     botón "Reclamar". El min-width:0 hay que ponerlo en CADA eslabón flex de la cadena
     (cabecera → trigger → resumen), no solo en el último. */
  min-width: 0;
}
/* Layout de 2 columnas de modules/asunto.info.tpl: Cliente+Seguimiento apilados a la izquierda,
   Notas a la derecha — MISMA altura que la columna izquierda (a petición del usuario
   2026-09-08; antes era align-items:flex-start, cada columna medía solo lo que pedía su propio
   contenido). Flex y no Bootstrap .row/.col-md-*: esa rejilla ya se evita en el resto de ese
   archivo (sus márgenes negativos quedaban recortados por el "overflow:hidden" de .sl-panel,
   ver el comentario de la sección Notas en el propio .tpl). Colapsa a una columna por debajo de
   768px (mismo punto de corte que tenía antes col-md-6); como en el HTML la columna de
   Cliente+Seguimiento ya va antes que la de Notas, el apilado en móvil sale en el mismo orden de
   siempre sin nada más que hacer. */
.sl-asunto-info-row {
  display: flex;
  align-items: stretch;
  gap: 1rem;
}
.sl-asunto-info-row > .sl-asunto-info-col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
/* --media: la columna se queda en la MITAD en vez de repartirse el ancho.
   Hace falta porque .sl-asunto-info-col es "flex: 1 1 0": una columna sola en su fila
   se lleva el 100%, asi que envolver un bloque en row+col NO da media anchura por si
   solo. Lo usa el bloque del encargo comercial (modules/asunto_comercial.info.tpl),
   que va en su propia fila y de momento deja la otra mitad vacia a proposito.
   Por debajo de 768px la fila ya colapsa a una columna y --media deja de aplicar,
   igual que el resto del layout de la ficha. */
.sl-asunto-info-row > .sl-asunto-info-col--media {
  flex: 0 1 50%;
  max-width: 50%;
}
@media (max-width: 767px) {
  .sl-asunto-info-row > .sl-asunto-info-col--media {
    flex: 1 1 100%;
    max-width: none;
  }
}
/* --suelta: exime a la columna de las reglas de ":last-child" de mas abajo, que estiran
   el ultimo panel para que NOTAS llene el alto de su columna. Esas reglas casan por
   ESTRUCTURA y no por nombre, asi que sin esto estirarian tambien la ultima tabla del
   bloque del encargo comercial, que no lo quiere: sus tablas miden lo que miden.
   No declara nada por si misma; su unico trabajo es estar en el :not() de esas cinco
   reglas. Si anades una regla nueva de ":last-child" ahi abajo, anadele el :not(). */

/* Notas es la única sección de su columna: para que llene el alto que le da el stretch de
   arriba (en vez de quedarse con su alto de contenido y dejar hueco vacío debajo), toda la
   cadena hasta el <textarea> tiene que ser flex:1 — el panel, su cuerpo colapsable, cada fila
   ".sl-panel__body" (normalmente 2, hasta 3 con "Motivo de no venta") y la celda de cada nota.
   Con eso el hueco sobrante se reparte a partes iguales entre los textareas presentes. Solo se
   aplica al panel :last-child de la columna (aquí, Notas) para no forzar la misma altura extra
   en Cliente/Seguimiento, que ya llenan su columna por sí solos. */
/* ⚠️ ":has(> .sl-disclosure__body.in)" — o sea SOLO mientras Notas está desplegado. Sin esa
   condición, con el panel plegado el "flex:1" lo estiraba igual hasta el alto de la columna de
   enfrente (Cliente + Información + Seguimiento apilados) y quedaba una caja blanca vacía de
   más de 100px debajo de su cabecera: justo el estado que pasó a ser el de partida al aparecer
   la preferencia "Paneles de la ficha de asunto" en "Cerrados". Plegado tiene que medir lo que
   mide su cabecera, como cualquier otro panel.
   ":has()" ya se usa en otros 20 sitios de esta hoja, así que no estrena dependencia. */
.sl-asunto-info-row > .sl-asunto-info-col:not(.sl-asunto-info-col--suelta) > .sl-panel:last-child:has(> .sl-disclosure__body.in) {
  flex: 1;
  display: flex;
  flex-direction: column;
}
/* SOLO cuando está desplegado (".in", el estado con el que Bootstrap lo deja visible): sin este
   ".in", esta regla —con más especificidad que ".collapse{display:none}" de Bootstrap (0,1,0)—
   forzaba SIEMPRE display:flex, incluso plegado, y el propio "display:none" de Bootstrap nunca
   llegaba a ganar. Resultado (reportado 2026-09-08): los triggers de Seguimiento y Notas se veían
   "rotos" (el body no llegaba a ocultarse) porque los dos son ":last-child" de su columna
   (Seguimiento en la izquierda junto a Cliente, Notas sola en la derecha) — Cliente, al ser
   :first-child de la suya, nunca entraba por esta regla y por eso seguía funcionando bien. */
.sl-asunto-info-row > .sl-asunto-info-col:not(.sl-asunto-info-col--suelta) > .sl-panel:last-child > .sl-disclosure__body.in {
  flex: 1;
  display: flex;
  flex-direction: column;
}
.sl-asunto-info-row > .sl-asunto-info-col:not(.sl-asunto-info-col--suelta) > .sl-panel:last-child > .sl-disclosure__body > .sl-panel__body {
  flex: 1;
}
.sl-asunto-info-row > .sl-asunto-info-col:not(.sl-asunto-info-col--suelta) > .sl-panel:last-child .sl-ficha-field-group {
  display: flex;
  flex-direction: column;
}
.sl-asunto-info-row > .sl-asunto-info-col:not(.sl-asunto-info-col--suelta) > .sl-panel:last-child .sl-note__ta {
  flex: 1;
}
@media (max-width: 767px) {
  .sl-asunto-info-row {
    flex-direction: column;
  }
}
.resumen-inventario {
  display: flex;
  flex-wrap: wrap;
}
/* ——— 6d. Tabla ————————————————————————————————————————————————————————— */
.sl-table {
  width: 100%; border-collapse: separate; border-spacing: 0; font-size: .75rem;
  border: 1px solid var(--sl-border); border-radius: var(--sl-radius-md); overflow: hidden;
}
.sl-table thead th {   /* mismo look que .sl-panel__header: fondo + línea fina */
  font-size: .8125rem; font-weight: 700; color: var(--sl-blue);
  background: var(--sl-bg-soft);
  /* padding horizontal IGUAL al de tbody td (abajo): con .875rem aquí el texto de cabecera
     quedaba 4.5px más a la derecha que el del contenido — comprobado con getBoundingClientRect. */
  border-bottom: 1px solid var(--sl-border); padding: .625rem .625rem; text-align: left;
}
.sl-table tbody td {
  padding: .5rem .625rem; border-bottom: 1px solid var(--sl-border);
  color: var(--sl-fg-2); vertical-align: middle;
}
.sl-table tbody tr:last-child td { border-bottom: none; }
.sl-table tbody tr:hover td { background: var(--sl-blue-050); }

/* Contador de resultados */
.sl-count { font-size: .75rem; font-weight: 500; color: var(--sl-fg-3); }
.sl-count strong { color: var(--sl-blue); font-weight: 700; }

/* ——— 6e. Grid de tarjetas ——————————————————————————————————————————————
   Genérico y reutilizable para cualquier listado de tarjetas (clientes,
   asuntos, etc). Cada columna se ajusta con minmax() (sin ancho fijo), pero
   todas las tarjetas de una misma fila comparten alto y ancho porque
   comparten pista de grid (align-items:stretch es el valor por defecto de
   los items de grid). */
.sl-cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13.75rem, 1fr));
  gap: 1rem;
  padding: .25rem .125rem .5rem;
}

/* ——— 6f. Tarjeta de cliente (variante de .sl-card) ————————————————————— */
.sl-card--client {
  display: flex; flex-direction: column;
  margin-bottom: 0; /* el gap del grid ya gestiona el espaciado */
}
.sl-card__media {
  height: 4.375rem;
  background: var(--sl-bg-soft);
  display: flex; align-items: center; justify-content: center;
  border-bottom: 1px solid var(--sl-border);
  padding: .75rem .875rem;
  border-radius: var(--sl-radius-card) var(--sl-radius-card) 0 0;
}
.sl-card__media-img { max-height: 3.25rem; max-width: 11.875rem; object-fit: contain; }
/* Fallback de texto, oculto por defecto hasta que la imagen falle al cargar (ver onerror en el <img>) */
.sl-card__media-text {
  display: none;
  font-weight: 500; color: #7a8a99; letter-spacing: .04em;
  text-align: center; line-height: 1.25; word-break: break-word;
  font-size: .9375rem; /* nombre corto */
}
.sl-card__media-text--md { font-size: .8125rem; } /* nombre medio (13–18 caracteres) */
.sl-card__media-text--sm { font-size: .6875rem; } /* nombre largo (>18 caracteres) */

.sl-card__body--flex {
  padding: .625rem .75rem .5rem;
  flex: 1;
  display: flex; flex-direction: column; justify-content: space-between;
}
.sl-card__name { font-size: .75rem; font-weight: 600; color: #333; line-height: 1.3; margin-bottom: .375rem; }
.sl-clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

.sl-card__footer {
  display: flex; align-items: center; justify-content: space-between;
  padding: .5rem .75rem;
  border-top: 1px solid #f0f0f0;
}

/* Fila de píldoras informativas dentro de una tarjeta (genérica) */
.sl-pill-row { display: flex; gap: .3125rem; flex-wrap: wrap; font-size: .6875rem; color: #888; }

/* Botón-píldora reutilizable con variantes de color */
.sl-pill-btn {
  display: inline-flex; align-items: center;
  border: 1px solid transparent; border-radius: .625rem;
  padding: .125rem .625rem; font-size: .625rem;
  cursor: pointer; transition: background .15s;
}
.sl-pill-btn i { margin-right: .1875rem; }
.sl-pill-btn--info { background: #e8eef3; color: #5a7a8a; }
.sl-pill-btn--info:hover { background: #d0dce5; }
.sl-pill-btn--info.sl-pill-btn--bordered { border-color: #1980B6; }
.sl-pill-btn--muted { background: #f5e8e8; color: #a05a5a; }
.sl-pill-btn--muted:hover { background: #ebd4d4; }

/* ——— 6g. Popover flotante (genérico, posicionado por JS via top/left/width) ——— */
.sl-popover {
  display: none; position: fixed; z-index: 9999;
  background: #fff; border: 1px solid #e5e9ee; border-radius: var(--sl-radius-md);
  box-shadow: 0 4px 18px rgba(0,0,0,.15);
  padding: .625rem 0;
}
/* Variante que SIGUE al cursor en vez de anclarse a un elemento (panel de "Destacable" del
   listado de asuntos, asuntos.tpl). pointer-events:none no es cosmético: sin él, el propio
   panel queda bajo el puntero al moverse, dispara el mouseleave de la fila, se oculta, el
   puntero vuelve a estar sobre la fila, se muestra… y parpadea sin parar. Al ser inerte al
   ratón, los eventos siguen llegando siempre a la fila de debajo. */
.sl-popover--cursor { pointer-events: none; }
/* Icono de un .sl-popover-item cuyo color es un DATO, no decoración: en el panel de
   "Destacable" distingue bloqueo (rojo) de reclamación de cliente (--sl-state-urgent) y de
   reclamación interna (--sl-state-progress), y son los MISMOS colores que las pills de
   "Reclamado" de la columna Estado, para que se reconozcan sin leer. Viaja por puente igual
   que --sl-generic-pill-color en components/pill.tpl o --sl-icon-tag-color en las etiquetas. */
.sl-popover-item__icon {
  flex: none;
  width: 1rem;
  text-align: center;
  font-size: .75rem;
  color: var(--sl-popover-item-icon, var(--sl-fg-3));
}
.sl-popover__title {
  padding: .625rem;
  font-size: .75rem;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--sl-blue);
  border-bottom: 1px solid var(--sl-border-2);
  margin-bottom: .25rem;
  padding-top: 0;
}
.sl-popover-item { display: flex; align-items: center; gap: .5rem; padding: .375rem .875rem; }
.sl-popover-item__avatar {
  width: 1.75rem; height: 1.75rem; border-radius: 50%; flex-shrink: 0;
  background: #e8eef3; display: flex; align-items: center; justify-content: center;
}
.sl-popover-item__avatar i { font-size: .6875rem; color: #7a9ab0; }
.sl-popover-item__info { min-width: 0; overflow: hidden; }
.sl-popover-item__name {
  font-size: .700rem;
  font-weight: 500;
  color: var(--sl-fg-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--sl-font);
  -webkit-font-smoothing: antialiased;
}
.sl-popover-item__userid { font-size: .625rem; color: #888; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sl-popover-item__email { font-size: .625rem; color: #aaa; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Contador final de fila (ej. nº de llamadas por departamento/profesional), y sangría para
   listas de dos niveles (departamento > profesional) dentro del mismo popover genérico. */
.sl-popover-item__count { margin-left: auto; flex: none; font-size: .6875rem; font-weight: 600; color: var(--sl-fg-2); padding-left: .5rem; }
.sl-popover-item--nested { padding-left: 1.75rem; }

/* ——— 7. Formularios ———————————————————————————————————————————————————— */
.sl-input, .sl-select {
  height: 1.75rem; padding: 0 .5rem;
  font-family: var(--sl-font); font-size: .75rem; color: var(--sl-fg-2);
  background: #fff; border: 1px solid var(--sl-border); border-radius: var(--sl-radius-sm);
  transition: border-color .15s, box-shadow .15s;
}
.sl-input:focus, .sl-select:focus { outline: none; border-color: var(--sl-blue); box-shadow: var(--sl-focus); }
.sl-input::placeholder { color: var(--sl-fg-3); }
.sl-select { min-width: 11.25rem; }

.sl-input--on-dark {
  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.2);
  border-radius: var(--sl-radius-pill); color: #fff;
}
.sl-input--on-dark::placeholder { color: rgba(255,255,255,.85); }
.sl-input--on-dark:focus { background: rgba(255,255,255,.18); border-color: rgba(255,255,255,.4); box-shadow: none; }

/* Formulario en línea (input + botón en una fila) */
.sl-form-inline { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin: 0; }
.sl-form-inline .sl-input { min-width: 13.75rem; }

/* Switch/toggle accesible: checkbox real oculto (foco/estado nativos) + track+thumb visuales
   dibujados con ::before, sin JS ni markup extra más allá de un <span class="sl-switch__track">. */
.sl-switch {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: .8125rem; font-weight: 500; color: var(--sl-fg-2);
  cursor: pointer; user-select: none;
}
.sl-switch input[type="checkbox"] { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; }
.sl-switch__track {
  position: relative; flex: 0 0 auto;
  width: 2.25rem; height: 1.25rem;
  background: var(--sl-border-2); border-radius: var(--sl-radius-pill);
  transition: background .15s;
}
.sl-switch__track::before {
  content: ""; position: absolute; top: .125rem; left: .125rem;
  width: 1rem; height: 1rem; border-radius: 50%;
  background: #fff; box-shadow: var(--sl-shadow-sm);
  transition: transform .15s;
}
.sl-switch input:checked ~ .sl-switch__track { background: var(--sl-blue); }
.sl-switch input:checked ~ .sl-switch__track::before { transform: translateX(1rem); }
.sl-switch input:focus ~ .sl-switch__track { box-shadow: var(--sl-focus); }
.sl-switch input:disabled ~ .sl-switch__track { opacity: .5; }
.sl-switch:has(input:disabled) { cursor: not-allowed; }

/* ——— 8. Barras: topbar, toolbar y dropdowns ———————————————————————————— */
/* Cabecera tipo "barra de pantalla" (estilo kanban): título + acciones a lo ancho. */
#sl-app input[type="checkbox"] {
  accent-color: var(--sl-blue) !important;
  color: gray;
}
#sl-app .dropdown-menu {
  display: none;
  flex-direction: column;
  gap: 5px;
  padding: 0;
  padding-bottom: 5px;
  border-radius: var(--sl-radius-sm);
  border: 1px solid var(--sl-border);
  opacity: 0;
  box-shadow: var(--sl-shadow-card);
}
#sl-app .dropdown-menu .dropdown-header {
  background: var(--sl-blue);
  font-weight: 500;
  font-size: .75rem;
  border-top-left-radius: var(--sl-radius-sm);
  border-top-right-radius: var(--sl-radius-sm);
}
#sl-app .dropdown-menu li a label {
  font-weight: 500;
  color: var(--sl-fg-2);
}
#sl-app .open>.dropdown-menu {
  display: flex;
  opacity: .9;
}
#sl-app .dropdown-menu li a {
  padding: 0 5px;
}
#sl-app .dropdown-menu li {
  display: flex;
  align-items: center;
  padding-left: 5px;
  padding-right: 5px;
}
#sl-app .dropdown-menu li input ~ .checkmark, #sl-app .dropdown-menu li button {
  background: var(--sl-blue);
}
#sl-app .dropdown-menu li input, #sl-app .dropdown-menu li button {
  height: auto !important;
}
.mega-design .sl-topbar {
  display: flex; align-items: center; gap: var(--sl-space-2); flex-wrap: wrap;
  padding: 1rem;
  /*border-bottom: 1px solid var(--sl-border);*/
  height: 70px;
}
.mega-design .sl-fixed-top {
  /*top: 80px;*/
  top: 70px;
  transition: opacity .3s ease-in-out;
  box-shadow: 0 -10px 0 0 #fff;
}
.mega-design .sl-fixed-top:hover {
  opacity: 1;
}

/* ⚠️ CSS Scroll Anchoring (activo por defecto en Chrome, overflow-anchor:auto): cuando algo
   DENTRO del scroll cambia de tamaño (ej. el panel de filtros de asuntos.tpl colapsándose al
   compactarse por scroll, ver ".sl-fixed-top--auto-compact" más abajo), el navegador intenta
   "anclar" la posición visual eligiendo un nodo cercano al viewport y ajustando scrollTop para
   compensar el cambio de tamaño — pero el nodo que elige aquí NO es descendiente del propio
   panel que colapsa, así que el ajuste podía llevarse el scroll de vuelta hasta scrollTop=0 de
   golpe. Confirmado en vivo con un MutationObserver: scroll a 300px → colapsa el panel → ~40ms
   después el scroll ya estaba en 0 otra vez, sin que ningún JS tocara scrollTop. Poner
   "overflow-anchor:none" SOLO en ".sl-fixed-top" no bastaba (el nodo elegido como ancla no era
   descendiente suyo) — hay que desactivarlo en el propio contenedor de scroll. Regla movida aquí
   (no a mega-design.css, donde vive el resto de ".wrapper") porque ese archivo se sirve solo
   dentro de "css/crunch/compiled.css" y este SÍ se carga directo — sin rebuild de por medio, un
   cambio ahí no se vería reflejado hasta ejecutar crunch-css-js.bat. Ver asuntos.tpl.js para el
   disparador del compactado y el debounce de 80ms que ya amortiguaba el "rebote" de scrollTop de
   la rueda (bug relacionado, no el mismo: aquel era ruido de scroll nativo de <60ms; este es el
   propio navegador corrigiendo el scroll por el cambio de tamaño, con un salto de cientos de px). */
.mega-design #main-content > .wrapper {
  overflow-anchor: none;
}

/* ——— Compactado del panel de filtros al hacer scroll (asuntos.tpl, llamadas.tpl) ————
   ".panel-body" (el <div> con la rejilla de filtros — #asuntos en asuntos.tpl, #llamadas
   en llamadas.tpl) es el MISMO elemento que oculta/muestra #my-hideshow-filters-button a
   mano (display:none por JS/cookie appafpclosed / appllfpclosed) — eso NO se toca y sigue
   mandando siempre: si está cerrado a mano, el JS de scroll ni añade esta clase (ver
   asuntos.tpl.js / llamadas.tpl.js). Aquí solo se anima la vía "automática" con la misma
   técnica que ya usa .sl-disclosure__panel (max-height con un tope generoso, no la altura
   real: no hace falta medir el alto exacto de una rejilla de filtros tan variable).
   .sl-filtros-resumen-row__resumen (el bloque "Resumen" de asuntos.tpl, hermano de #asuntos
   vía .sl-filtros-resumen-row — llamadas.tpl no tiene un equivalente) se anima exactamente
   igual y a la vez, para que colapse y reaparezca EN SINCRONÍA con los filtros — mismas 3
   reglas, mismo disparador.
   Selector por CLASE (".panel-body") y no por ID: generalizado 2026-09-01 al migrar
   llamadas.tpl al mismo patrón, en vez de repetir "#asuntos, #llamadas, #partes..." cada
   vez que se migre una página más. Es seguro para las páginas que aún NO lo usan
   porque las tres reglas solo hacen algo cuando el propio JS de esa página llega a añadir
   ".sl-fixed-top--auto-compact".
   A fecha 2026-09-15 lo hacen: asuntos.tpl.js, llamadas.tpl.js, partes.tpl.js,
   carga_llamadas.tpl.js, carga_trabajo.tpl.js, extracto_horas.tpl.js y proyectos.tpl.js. Antes
   esta nota decía "solo asuntos y llamadas" y citaba Partes y Carga de trabajo como ejemplos de
   las que NO lo tenían. */
.mega-design .sl-fixed-top .panel-body,
.mega-design .sl-fixed-top .sl-filtros-resumen-row__resumen {
  overflow: hidden;
  transition: max-height .3s ease, opacity .25s ease, padding-top .3s ease, padding-bottom .3s ease;
  padding: 15px;
  border: 0 !important;
}
/* Los dropdown "Elegir mes"/"Elegir año" se recortan contra el overflow:hidden de arriba.
   Permitir overflow solo mientras están abiertos. Por CLASE y no por "#asuntos" (hasta
   2026-09-16): ese ID solo cubría asuntos.tpl, recortando el menú en cualquier otra pantalla. */
.mega-design .sl-fixed-top .panel-body:has(.btn-group.open) {
  overflow: visible;
}
.mega-design .sl-fixed-top.sl-fixed-top--auto-compact .panel-body,
.mega-design .sl-fixed-top.sl-fixed-top--auto-compact .sl-filtros-resumen-row__resumen {
  max-height: 0;
  opacity: 0;
  padding-top: 0;
  padding-bottom: 0;
}
/* Peek: en compactado-por-scroll (nunca en cerrado a mano, esa clase no llega a
   añadirse en ese caso) el hover reabre el filtro con la misma transition.

   El disparador es la CABECERA o el OVERLAY ya abierto — los hijos ".panel-heading",
   ".sl-filtros-resumen-row" o ".panel-body" de ".sl-panel-filtros", clase genérica que
   llevan los 8 paneles de filtros de la app (asuntos, asuntos comerciales, llamadas,
   partes, partes comerciales, proyectos, visitas, extracto de horas). Una sola regla
   para todos, en vez de repetir el selector pantalla por pantalla.

   La franja de filtros activos (".sl-filtros-activos-scroll", también hija de la
   section) queda FUERA a propósito (2026-09-25, a petición del usuario): con la
   section entera como disparador, acercar el ratón a la "×" de una pill abría el
   peek y no había forma de quitar un filtro con el listado scrolleado.

   Que cuente el overlay no hace que se abra al pasar por él: compactado mide
   max-height:0 y no se puede alcanzar con el ratón, así que solo se ENTRA por la
   cabecera; una vez abierto, el overlay lo MANTIENE abierto mientras el cursor esté
   dentro.

   ⚠️ Antes de 2026-09-15 el disparador era SOLO "header.panel-heading", y eso era un BUG: el peek
   revela ".sl-filtros-resumen-row", que es HERMANA del header y no descendiente
   suya, así que en cuanto el cursor cruzaba de la cabecera a la rejilla recién
   abierta el ":has()" dejaba de casar y el panel se cerraba DEBAJO del cursor —
   imposible llegar a tocar un filtro con el listado scrolleado. Reproducido en vivo
   (2026-09-15): cursor sobre un ".sl-fcell" → header:hover=false, section:hover=true,
   altura de la rejilla = 0. El disparador tiene que cubrir todo lo que el peek
   revela, no un trozo de ello.

   ⚠️ Aquí hubo un ":not(:has(.sl-filtros-activos-scroll:hover))" y se retiró el
   2026-09-16, al pasar el peek a pintarse SUPERPUESTO (ver el bloque siguiente).
   Protegía de que acercarse a pulsar la "×" de una pill disparase el peek, que ocultaba
   esa misma franja debajo del cursor. Ahora la franja ya NO se oculta durante el peek
   —si se ocultara, la barra compactada encogería y el listado volvería a moverse, que es
   justo lo que el overlay viene a evitar—, así que el guardián no protege de nada y en
   cambio estorbaba: la franja queda entre la cabecera y el overlay, de modo que bajar el
   ratón hacia los filtros la cruza y cerraba el panel a mitad de camino.
   (Nótese que la franja CON título ".sl-filtros-activos-bar" es un elemento
   DISTINTO, fuera de .sl-fixed-top — no le afecta este peek en absoluto.) */
.mega-design .sl-fixed-top.sl-fixed-top--auto-compact:has(.sl-panel-filtros > :is(.panel-heading, .sl-filtros-resumen-row, .panel-body):hover) .panel-body,
.mega-design .sl-fixed-top.sl-fixed-top--auto-compact:has(.sl-panel-filtros > :is(.panel-heading, .sl-filtros-resumen-row, .panel-body):hover) .sl-filtros-resumen-row__resumen {
  max-height: 100rem;
  opacity: 1;
  padding-top: 15px;
  padding-bottom: 15px;
}

/* ——— El peek se pinta SUPERPUESTO, sin mover el listado ———————————————————————
   ".sl-fixed-top" es "position:sticky", NO "fixed": se queda pegada arriba pero sigue
   ocupando su hueco en el flujo, así que al abrirse el peek crecía de 101px a 549px y
   empujaba la tabla 448px hacia abajo (medido en vivo en /asuntos, 2026-09-16). El panel
   se pintaba encima, sí, pero solo DESPUÉS de haber desplazado todo lo de debajo.

   Aquí lo que se despliega sale del flujo mientras el panel está compactado: la barra se
   queda clavada en su alto compacto (cabecera + franja de pills) y el desplegable flota
   por encima de la tabla. Cero reflow al entrar y al salir el ratón.

   El hijo que sale del flujo tiene DOS formas según la pantalla — las mismas dos que ya
   contempla el "order" de filtros-grid.css: ".sl-filtros-resumen-row" donde hay sidebar
   "Resumen" (asuntos, asuntos comerciales, llamadas, partes, partes comerciales,
   proyectos y visitas) y ".panel-body" donde no lo hay (extracto de horas). El ">" las
   mantiene excluyentes: en las primeras, ".panel-body" va anidado dentro de
   ".sl-filtros-resumen-row__filtros" y NO es hijo directo de la section.

   ⚠️ "absolute" SIEMPRE que esté ".sl-fixed-top--auto-compact", y no solo en ":hover": si
   volviera a "static" al sacar el ratón, en ese instante la rejilla —todavía a media
   altura, animándose— reentraría en el flujo y daría un salto justo al cerrarse.

   ⚠️ Esto NO cambia nada del colapso al hacer scroll, que ya era instantáneo antes: la
   regla base deja "max-height:none" y la de compactado pone "0", y "none → 0" no es
   interpolable (comprobado en vivo: getAnimations() devuelve [] al añadir la clase). Lo
   único que anima ahí son "opacity" y "padding". Lo que SÍ anima es el peek (0 ↔ 100rem).

   Solo hace algo donde el JS de la pantalla llega a añadir ".sl-fixed-top--auto-compact":
   a fecha 2026-09-16, asuntos, llamadas, partes, proyectos, visitas y extracto de horas.
   Asuntos comerciales y partes comerciales llevan ".sl-panel-filtros" pero no compactan,
   así que estas reglas no llegan a aplicarse allí. */
.mega-design .sl-fixed-top .sl-panel-filtros {
  position: relative;
}
.mega-design .sl-fixed-top.sl-fixed-top--auto-compact > .sl-panel-filtros > .sl-filtros-resumen-row,
.mega-design .sl-fixed-top.sl-fixed-top--auto-compact > .sl-panel-filtros > .panel-body {
  position: absolute;
  top: 100%;
  /* -1px a cada lado: en un posicionado absoluto, "left/right:0" se alinean con la caja
     de PADDING del contenedor, o sea por dentro de su borde de 1px. Sin esto el overlay
     quedaría 2px más estrecho que el panel y se vería el escalón en los laterales. */
  left: -1px;
  right: -1px;
  /* Al salir del flujo, el overlay deja de estar dentro de la tarjeta del .panel y tiene
     que traerse su propia piel: sin fondo propio se vería la tabla a través de él. */
  background: #fff;
  border: 1px solid var(--sl-border);
  border-top: 0;
  border-bottom-left-radius: var(--sl-radius-card);
  border-bottom-right-radius: var(--sl-radius-card);
  box-shadow: var(--sl-shadow-md);
  /* Colapsado, el overlay sigue midiendo 1px (su propio borde) y arrastraría fondo
     blanco + sombra justo debajo de la barra compactada. Con opacity:0 desaparece del
     todo, y de paso el cierre del peek se funde en vez de cortarse en seco. */
  opacity: 0;
  transition: opacity .25s ease;
}
/* La opacidad va en regla APARTE y no junto al max-height de arriba: aquella lleva
   "padding: 15px", que es de la rejilla y del sidebar, no de la fila que los contiene —
   metida ahí, el overlay ganaba 30px de aire interior que nadie pidió. (En extracto de
   horas el overlay ES el ".panel-body", así que ahí el padding sí le toca y se lo sigue
   dando aquella regla.) */
.mega-design .sl-fixed-top.sl-fixed-top--auto-compact:has(.sl-panel-filtros > :is(.panel-heading, .sl-filtros-resumen-row, .panel-body):hover) > .sl-panel-filtros > .sl-filtros-resumen-row,
.mega-design .sl-fixed-top.sl-fixed-top--auto-compact:has(.sl-panel-filtros > :is(.panel-heading, .sl-filtros-resumen-row, .panel-body):hover) > .sl-panel-filtros > .panel-body {
  opacity: 1;
  /* El peek tiene que verse como el panel desplegado: cabecera y debajo la rejilla. Con
     "top:100%" arrancaba debajo del panel ENTERO, y entre la cabecera y la rejilla quedaba
     ".sl-filtros-activos-scroll", la franja de pastillas que solo existe estando compactado
     (desplegado esa franja vive DEBAJO de la rejilla, no encima).

     No se esconde, se TAPA: la franja forma parte del alto de la barra compactada, así que
     quitarla la encogería y el listado saltaría al pasar el ratón — justo lo que el overlay
     vino a evitar. Subiéndolo su alto, el overlay —que es opaco— la cubre.

     Se ancla al alto de la CABECERA y no al de la franja, aunque sea la franja lo que se
     quiere tapar: el alto de la franja depende del propio peek —78px compactado, 44px con el
     ratón encima, porque ahí se esconden los contadores—, así que la referencia se movía
     sola. La cabecera mide lo mismo en los dos estados.

     Lo publica el JS (modules/js/common.tpl.js, _sl_medir_cabecera_panel) en vez de escribir
     el número aquí porque ese alto lo decide el contenido de la cabecera, que cambia por
     pantalla y con el tamaño de letra del navegador. El respaldo a 100% deja el
     comportamiento anterior si la variable no llegara. */
  top: var(--sl-cabecera-panel, 100%);
}

/* Y la franja de pastillas se va DEBAJO del overlay, que es donde está cuando el panel se ve
   desplegado (allí lo hace con "order:3", ver filtros-grid.css). Compactado el order no puede
   colocarla, porque la rejilla ha salido del flujo y la franja se queda pegada a la cabecera.

   Se baja con "transform" y no con margin ni position a propósito: un transform NO toca el
   flujo, así que la barra compactada conserva su alto y el listado no salta al pasar el ratón
   — que es la razón de ser de este overlay. El alto de la rejilla lo publica el JS
   (modules/js/common.tpl.js, _sl_medir_panel); sin él, la franja se queda donde estaba.

   Al bajar queda fuera de la tarjeta del panel, así que se trae su propia piel — fondo, borde
   y sombra — y el overlay cede las esquinas de abajo: entre los dos forman UNA tarjeta, no
   dos pegadas. */
.mega-design .sl-fixed-top.sl-fixed-top--auto-compact:has(.sl-panel-filtros > :is(.panel-heading, .sl-filtros-resumen-row, .panel-body):hover) .sl-filtros-activos-scroll {
  transform: translateY(var(--sl-panel-rejilla, 0px));
  transition: transform .25s ease;
  position: relative;
  z-index: 2;
  background: #fff;
  border: 1px solid var(--sl-border);
  border-top: 0;
  border-bottom-left-radius: var(--sl-radius-card);
  border-bottom-right-radius: var(--sl-radius-card);
  box-shadow: var(--sl-shadow-md);
}
.mega-design .sl-fixed-top.sl-fixed-top--auto-compact:has(.sl-panel-filtros > :is(.panel-heading, .sl-filtros-resumen-row, .panel-body):hover) > .sl-panel-filtros > .sl-filtros-resumen-row,
.mega-design .sl-fixed-top.sl-fixed-top--auto-compact:has(.sl-panel-filtros > :is(.panel-heading, .sl-filtros-resumen-row, .panel-body):hover) > .sl-panel-filtros > .panel-body {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  box-shadow: none;
}

/* La franja de filtros activos, en UNA fila: las pastillas de filtro a la izquierda y el
   resumen de resultados a la derecha, repartidos con space-between. Antes caían en dos líneas
   —el resumen era un bloque debajo—, y en una barra que existe para ocupar poco eso era el
   doble de alto para la mitad de información.

   Vive aquí y no en filtros-grid.css, que es donde está el resto del estilo de esta franja,
   porque ese archivo es trabajo en curso ajeno. Con "#sl-app" delante (1-1-0 contra 0-1-0)
   gana por especificidad y no por orden de carga, igual que otras reglas de esta hoja.

   Aquí NO se toca el "display" del resumen: filtros-grid.css lo enciende y lo apaga según se
   vea o no la tarjeta "Resultados" del sidebar, que dice lo mismo. Cuando está apagado queda
   un solo hijo y space-between lo deja donde tiene que estar, a la izquierda. */
#sl-app .sl-filtros-activos-scroll {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sl-space-3);
}
/* Los filtros activos son los que ceden: se quedan con el sitio que sobre y siguen envolviendo
   (ya llevan "--wrap"). El "min-width:0" hace falta porque un hijo flex no baja de su ancho de
   contenido por defecto, y una lista larga de pastillas empujaría al resumen fuera de la barra. */
#sl-app .sl-filtros-activos-scroll .sl-filtros-activos-pills {
  flex: 1 1 auto;
  min-width: 0;
}
/* El resumen no encoge, y pierde el margen superior: lo tenía para caer en su propia línea
   debajo, y compartiendo fila solo lo descoloca. */
#sl-app .sl-filtros-activos-scroll .sl-resultados-pills {
  flex: 0 0 auto;
  margin-top: 0;
}
/* Esquinas de abajo del panel-heading dentro de .sl-fixed-top: por DEFECTO también
   redondeadas (no solo las de arriba, que ya pone mega-design.css), porque cuando el
   panel de filtros está colapsado —a mano O por scroll, da igual el motivo— #asuntos
   desaparece y el heading pasa a ser TODA la pieza visible; sin este radius de abajo
   se ve una esquina cuadrada colgando por debajo del radius del .panel.
   Se quita el radius de abajo SOLO cuando el panel está realmente abierto: la clase
   .sl-fixed-top--open (asuntos.tpl.js, se mantiene junto a --auto-compact) cubre el
   caso normal, y el :has(header:hover) de más arriba cubre el peek del
   compactado-por-scroll —en ambos el body reaparece debajo y es él quien debe llevar
   el radius de abajo, vía la regla :last-child de mega-design.css. */
.mega-design .sl-fixed-top .panel > .panel-heading:first-of-type,
.mega-design #sl-app .sl-fixed-top .panel > .panel-heading:first-of-type {
  border-bottom-left-radius: var(--sl-radius-card);
  border-bottom-right-radius: var(--sl-radius-card);
}
.mega-design .sl-fixed-top--open .panel > .panel-heading:first-of-type,
.mega-design #sl-app .sl-fixed-top--open .panel > .panel-heading:first-of-type,
.mega-design .sl-fixed-top.sl-fixed-top--auto-compact:has(.sl-panel-filtros > :is(.panel-heading, .sl-filtros-resumen-row, .panel-body):hover) .panel > .panel-heading:first-of-type,
.mega-design #sl-app .sl-fixed-top.sl-fixed-top--auto-compact:has(.sl-panel-filtros > :is(.panel-heading, .sl-filtros-resumen-row, .panel-body):hover) .panel > .panel-heading:first-of-type {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
.sl-topbar .sl-title { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: .5rem; }
/* Icono del título: chip cuadrado redondeado con fondo azul e icono blanco */
.sl-topbar .sl-title > i:first-child {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.85rem; height: 1.85rem;
  background: var(--sl-blue-100); color: var(--sl-blue);
  border-radius: var(--sl-radius-sm);
  font-size: .9375rem; line-height: 1;
}
.sl-topbar .sl-title small { font-size: .75rem; font-weight: 400; color: var(--sl-fg-3); }   /* contador / subtítulo / aclaración */

.sl-toolbar {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  background: #fff; border-bottom: 1px solid var(--sl-border); padding: .5rem 1rem;
}
.sl-toolbar__sep { color: var(--sl-border-2); margin: 0 .125rem; }
.sl-toolbar__summary { margin-left: auto; color: var(--sl-fg-3); font-size: .6875rem; font-weight: 500; }
/* Reparte los grupos a los extremos en vez de apilarlos a la izquierda. Lo usa la cabecera del
   bloque de encargos (asunto.encargos.tpl), que tiene tres grupos —contador+filtros+acciones a la
   izquierda, las pestañas del encargo en medio y Mover/Editar a la derecha—. Es un modificador de
   .sl-toolbar, no un componente nuevo: el resto (flex, gap, wrap, borde inferior) ya lo da la base.
   No se usa .sl-toolbar__summary para empujar el último grupo porque esa clase trae además su
   color y su tamaño de fuente, pensados para un resumen de texto, no para botones. */
.sl-toolbar--spread { justify-content: space-between; }
/* Cabecera del bloque de encargos PARTIDA EN DOS, alineada con el split de abajo: el grupo de la
   izquierda mide exactamente lo mismo que el listado (380px, ver .sl-enc-aside) y lleva la misma
   divisoria vertical, así que "Encargos / filtros / Nuevo / Imprimir" queda sobre el listado y las
   pestañas del encargo sobre su panel. Es la cabecera del artboard Encargos.dc.html, donde cada
   mitad tiene su propia barra.
   Se consigue solo con CSS: el marcado sigue siendo UNA <header> con sus tres grupos, sin mover
   nada de sitio — #encargo_abierto y #ul-encargos-tabs los localiza el JS por id y no conviene
   trasladarlos. Tampoco se usa flex-wrap aquí: si envolviera, la mitad izquierda dejaría de
   cuadrar con el listado, que es justo la gracia. */
#sl-app .sl-enc-toolbar {
  flex-wrap: nowrap;
  gap: .75rem;
  padding-left: 0;
  /* Un tono más que el resto de cabeceras de panel (--sl-blue-050). No es un capricho: esta
     cabecera lleva dentro las pestañas del encargo, y la activa se dibuja con un "papel" BLANCO
     (el ::before de .encargos-tabs … li.active, efecto archivador). Sobre --sl-blue-050 (#F3F7FB)
     ese blanco es casi invisible y la pestaña activa deja de distinguirse; sobre --sl-blue-100
     (#E6EEF7) se lee, que es el fondo que esta barra ya tenía antes de la fase 2. */
  background: var(--sl-blue-100);
}
#sl-app .sl-enc-toolbar > .sl-enc-toolbar__aside {
  flex: 0 0 380px;
  max-width: 42%; /* el mismo tope que .sl-enc-aside, para que no se descuadren en pantalla estrecha */
  align-self: stretch;
  box-sizing: border-box;
  padding: 0 .75rem 0 1rem;
  border-right: 1px solid var(--sl-border);
  /* DOS filas: arriba título + filtro + acciones, debajo el contador. Antes era una sola línea
     con flex-wrap que envolvía por donde le tocaba dentro de los 380px. */
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: .25rem;
  min-width: 0;
}
/* Fila de arriba: el título a la izquierda, el filtro pegado a él y las acciones al extremo
   derecho (margin-left:auto en .__acciones). */
#sl-app .sl-enc-toolbar__row {
  display: flex;
  align-items: center;
  gap: .5rem;
  min-width: 0;
  justify-content: space-between;
}
/* Título del bloque. Es un <span> y no el <button> de colapsar que llevan los paneles de la
   ficha: este apartado no se pliega. */
#sl-app .sl-enc-toolbar__title {
  flex: none;
  white-space: nowrap;
}
#sl-app .sl-enc-toolbar__acciones {
  display: flex;
  align-items: center;
  gap: .3125rem;
  flex: none;
}
/* Contador bajo el título, en gris y pequeño. Es el #filter-cant que reescribe
   encargos.tpl.js al filtrar ("2 de 3 encargos"). */
#sl-app .sl-enc-toolbar__count {
  font: 500 .6875rem/1.2 var(--sl-font);
  color: var(--sl-fg-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Grupo segmentado: pills pegadas entre sí, con un solo borde exterior — el aspecto del
   control "Todos / Rpte. asignado". Genérico a propósito (no lleva "enc" en el nombre): sirve
   para cualquier grupo de pills de components/pill.tpl que deba leerse como UN control.
   Las pills de dentro pierden su radio salvo en los extremos y comparten borde con la vecina. */
.sl-segmented {
  display: inline-flex;
  align-items: center;
  flex: none;
}
.sl-segmented > .sl-generic-pill {
  border-radius: 0;
  /* Sin el desplazamiento hacia arriba del :hover de la pill suelta: dentro de un segmentado
     rompería la línea del grupo. */
  transform: none !important;
}
.sl-segmented > .sl-generic-pill + .sl-generic-pill {
  margin-left: -1px; /* bordes compartidos, no dobles */
}
.sl-segmented > .sl-generic-pill:first-child {
  border-top-left-radius: var(--sl-radius-pill);
  border-bottom-left-radius: var(--sl-radius-pill);
}
.sl-segmented > .sl-generic-pill:last-child {
  border-top-right-radius: var(--sl-radius-pill);
  border-bottom-right-radius: var(--sl-radius-pill);
}
/* La activa se pone por encima para que su borde azul no quede tapado por el de la vecina. */
.sl-segmented > .sl-generic-pill.is-active { position: relative; z-index: 1; }

/* ——— Barra de estados: .sl-estado-bar (components/estado-bar.tpl) ————————————————
   Un .sl-segmented cuyas pastillas son los estados de un registro. Añade tres cosas
   sobre el segmentado genérico, y las tres tienen motivo:

   1) EL SELECCIONADO LO MARCA EL PROPIO RADIO, vía :has(). Esta barra no lleva
      data-toggle="buttons" — no puede: el manejador global de button.js de Bootstrap 3
      hace preventDefault() sobre el clic cuando el objetivo no es el <input>, y en una
      pastilla el input está oculto con clip, así que el radio no llegaría a marcarse
      (misma razón por la que no lo llevan los filtros; ver el aviso en
      modules/asuntos_comerciales.filtros.tpl). Sin Bootstrap no hay quien conmute
      .is-active, y como aquí el guardado es AJAX y la pantalla no se repinta, la clase
      tampoco vuelve a llegar desde el servidor: lo resuelve el CSS leyendo el radio.
      ⚠️ Va acotado a .sl-estado-bar A PROPÓSITO. Un .sl-segmented cualquiera NO puede
      llevar esta regla: el filtro de encargos (modules/js/encargos.tpl.js:203) pone
      .is-active a mano y de forma deliberadamente distinta de :checked — la primera
      pastilla sale activa SIN estar marcada cuando no hay filtros aplicados.

   2) EL BORDE VUELVE A SER NEUTRO. components/pill.tpl pinta el borde del color del
      estado cuando recibe $pill_estado, que es lo correcto en una pastilla suelta; pero
      pegadas en un segmentado, ocho bordes de ocho colores compartiendo 1px se leen como
      un error de pintado. El color del estado se reserva para el relleno del
      seleccionado, que es donde de verdad es información y no decoración.

   3) EL SELECCIONADO SE PONE POR ENCIMA, igual que hace .sl-segmented con .is-active,
      para que su borde no quede tapado por el de la pastilla vecina.
      (Se repite aquí porque la regla de arriba mira .is-active, que esta barra no usa.) */
/* 4) ENVUELVE POR PASTILLAS, NUNCA POR LETRAS. .sl-segmented nace sin flex-wrap porque se
      diseñó para el filtro de encargos, que son DOS opciones cortas; aquí son ocho y con
      etiquetas largas ("Confirmar fact."). Sin esto, flex las encoge hasta que el texto parte
      en dos líneas y la barra pasa de 27px de alto a 45px — medido en la ficha. Y desbordar
      tampoco vale: .sl-panel lleva overflow:hidden, así que los últimos estados se perderían
      recortados y sin aviso. La fila de abajo necesita su propia separación (row-gap), que el
      gap horizontal no existe en un segmentado: las pastillas comparten borde a propósito. */
.sl-estado-bar { flex-wrap: wrap; row-gap: .35rem; }
.sl-estado-bar > .sl-generic-pill { white-space: nowrap; }
.sl-estado-bar > .sl-generic-pill[data-estado] { border-color: var(--sl-border); }
.sl-estado-bar > .sl-generic-pill:has(input:checked) {
  position: relative; z-index: 1;
  color: #fff;
  background: var(--sl-state, var(--sl-blue));
  border-color: var(--sl-state, var(--sl-blue));
}
/* Rótulo del grupo, para quien no lo pinte por fuera (hoy solo el diálogo de horas).
   El rótulo va fuera del .sl-segmented porque un hijo que no sea una pastilla se llevaría
   el redondeo de :first-child y el grupo quedaría con la esquina izquierda en pico.

   ENCIMA y no al lado: en dialog.horas.edit.tpl TODOS los campos rotulan por arriba
   ("Fecha parte", "Tipo facturación", "Firma"…), así que un rótulo a la izquierda era el
   único de la pantalla que se leía en otra dirección. Y NO es una .sl-fieldrow: esa trae
   marco propio, que ahí no pinta nada.

   El rótulo NO trae clase fija: la elige quien llama ($eb_label_class), porque la correcta
   depende de si la pantalla está migrada o no. Por defecto usa la del sistema; una pantalla
   heredada pasa la suya y así se parece a sus vecinas en vez de a un diseño que ahí todavía
   no existe. */
.sl-estado-bar-field { display: flex; flex-direction: column; align-items: flex-start; gap: .375rem; }
.sl-estado-bar-field__label {
  margin: 0;
  font: 700 11px/1.2 var(--sl-font);
  text-transform: uppercase;
  color: var(--sl-fg-3);
}
/* Rótulo HEREDADO dentro del campo (hoy: dialog.horas.edit.tpl, que no está rediseñado).
   ".label-header-sup" es el rótulo propio de esos diálogos y se reutiliza TAL CUAL —no se
   imitan sus valores— para que comparta fuente, peso y color con los de al lado y no se
   desincronice si algún día se tocan. Lo único que estorba es su posicionamiento: nació
   absoluto (style.css: position:absolute, top:-13px, margin-top:-10px) para colgar por
   encima de un campo, y aquí el campo ya lo coloca el flex en columna. Se devuelve al flujo
   normal y en paz; era justo el apaño que esta plantilla se quitó de encima al migrarla.
   Los MÁRGENES no se tocan a propósito: los fija ".form-group.webapp-thin label.label-header-sup"
   (negrita + 6px de sangría), que es la regla que iguala este rótulo con los de al lado. Ponerle
   aquí un "margin:0" se la comería y volvería a desalinearse. */
.sl-estado-bar-field > .label-header-sup { position: static; top: auto; }
#sl-app #encargos .sl-enc-toolbar > .sl-enc-toolbar__aside {
  padding: .625rem .875rem;
  background: white;
  border-bottom: 1px solid var(--sl-border);
}
/* El cuerpo EXTERIOR del bloque de encargos (el que contiene el split listado + panel) no lleva
   divisoria: la línea ya la pone el borde inferior de la barra de herramientas. OJO: esta regla
   estuvo como "#sl-app #encargos .sl-panel__body" y alcanzaba también a los cuerpos de las
   tarjetas de DENTRO del encargo, que se quedaban sin la línea que separa sus filas de campos —
   justo lo que el usuario echó en falta en "Datos del encargo" (2026-09-10). Acotada al de
   fuera, que es el único que la necesitaba. */
#sl-app #encargos > #encargos-panel-body.sl-panel__body {
  border-top: 0;
}
#sl-app #encargos .nav-tabs {
  border-bottom: 0;
}
/*#sl-app #encargos .sl-panel__header i {
  margin: 0;
}*/
/* Las pestañas se quedan con el hueco restante y las acciones (Mover/Editar) pegadas a la derecha.
   min-width:0 para que un título de encargo largo no empuje la barra a lo ancho. */
#sl-app .sl-enc-toolbar > #encargo_abierto { flex: 1 1 auto; min-width: 0; }
#sl-app .sl-enc-toolbar > .encargo-acciones { flex: none; margin-left: auto; margin-right: 15px; }

.sl-menu {
  min-width: 6.25rem; font-size: .75rem;
  border-radius: var(--sl-radius-md); box-shadow: var(--sl-shadow-md); border: 1px solid var(--sl-border);
}
.sl-menu > li > a { display: flex; align-items: center; gap: .3125rem; padding: .3125rem 1.25rem; }
.sl-menu .text-danger { color: var(--sl-pink); }

/* ——— 9. Estados semánticos (puente data-estado) ———————————————————————— */
[data-estado="1"] { --sl-state: var(--sl-blue); }
[data-estado="2"] { --sl-state: #1E6BB8; }
[data-estado="3"] { --sl-state: var(--sl-state-progress); }
[data-estado="4"],
[data-estado="5"],
[data-estado="6"] { --sl-state: var(--sl-state-neutral); }
[data-estado="7"] { --sl-state: var(--sl-state-done); }
[data-estado="8"] { --sl-state: var(--sl-state-review); }

.sl-pill--status[data-estado] { background: var(--sl-state); }
.sl-card--accent[data-estado] { border-top-color: var(--sl-state); }

/* ——— 10. Superficie oscura (hero / sidebar de marca) ——————————————————— */
.sl-surface-dark {
  background: linear-gradient(135deg, var(--sl-blue), #022E5B);
  color: #fff; position: relative; overflow: hidden;
}
.sl-surface-dark .sl-eyebrow { color: rgba(255,255,255,.6); }
.sl-surface-dark__halo {
  position: absolute; top: -20px; right: -20px; width: 100px; height: 100px;
  border-radius: 50%; background: rgba(227,54,120,.4); filter: blur(30px); pointer-events: none;
}
.sl-surface-dark .sl-btn {
  border-color: rgba(255,255,255,.3); color: rgba(255,255,255,.85); background: rgba(255,255,255,.1);
}
.sl-surface-dark .sl-btn:hover { background: rgba(255,255,255,.2); color: #fff; }

/* ——— 11. Utilidades ———————————————————————————————————————————————————— */
.sl-progress { height: .25rem; background: #EEF1F5; border-radius: var(--sl-radius-pill); overflow: hidden; }
.sl-progress__fill { height: 100%; width: 0; border-radius: var(--sl-radius-pill);
  background: var(--sl-progress-color, var(--sl-blue)); transition: width .35s ease; }

.sl-scroll { overflow-y: auto; }
.sl-scroll::-webkit-scrollbar { width: 6px; background: transparent; }
.sl-scroll::-webkit-scrollbar-thumb { background: var(--sl-border-2); border-radius: 3px; }

.sl-shadow-sm { box-shadow: var(--sl-shadow-sm); }
.sl-shadow-md { box-shadow: var(--sl-shadow-md); }
.sl-radius-md { border-radius: var(--sl-radius-md); }
.sl-radius-pill { border-radius: var(--sl-radius-pill); }

.sl-mt-1 { margin-top: var(--sl-space-1); } .sl-mt-2 { margin-top: var(--sl-space-2); }
.sl-mx-1 { margin-inline: var(--sl-space-1); } .sl-mx-2 { margin-inline: var(--sl-space-2); }
.sl-p-2  { padding: var(--sl-space-2); }     .sl-p-3  { padding: var(--sl-space-3); }
.sl-gap-2 { gap: var(--sl-space-2); }        .sl-gap-3 { gap: var(--sl-space-3); }
.sl-margin-lr-15 { margin: 15px; }

/* Columna de tabla que se ajusta a su contenido en vez de estirarse a la fuerza. Nuestras tablas
   usan table-layout:auto (por defecto, no lo tocamos), donde el navegador YA reparte el ancho
   según contenido — el problema aparece cuando la tabla ocupa 100% del ancho (.sl-table-bordered)
   y sobra espacio: ese sobrante se reparte entre TODAS las columnas por igual, ensanchando
   también las cortas (Nivel, Activo, botones...). width:1% le dice al navegador "esta columna
   no necesita más que su contenido"; el sobrante lo absorben entonces las columnas sin esta
   clase (Nombre, Email...). Aplicar sobre el <th> de la columna a encoger; no hace falta
   repetirlo en cada <td> de esa columna (el ancho de columna es el mismo para toda la tabla). */
.sl-col-fit { width: 1%; white-space: nowrap; }

/* Envoltorio de tabla a ancho completo. Sustituye al style="width:100%" que los listados
   (asuntos, asuntos_comerciales, llamadas) llevaban inline en su .table-responsive: sin el
   ancho explicito ese div es un bloque normal, la tabla no se estira y el borde redondeado
   de .sl-table-bordered queda cortado a media pantalla. */
.sl-table-responsive { width: 100%; }

/* Celda de texto largo (comentarios, notas): acota el ancho para que un comentario largo no
   ensanche su columna y descuadre el resto de la tabla. La medida se puede afinar desde la
   propia celda con --sl-cell-clamp-w, sin escribir un style suelto. */
.sl-cell-clamp { max-width: var(--sl-cell-clamp-w, 300px); line-height: 1.35; }
/* El recorte a 3 lineas y su despliegue los hace ".no_romper_fkg_tabla" + ensenar_texto()
   (css/style.css). Aqui solo se le da la señal de que se puede pulsar, y acotado a las celdas
   .sl-cell-clamp para no cambiar el cursor en el listado de asuntos, que usa esa misma clase. */
.sl-cell-clamp .no_romper_fkg_tabla { cursor: pointer; }

/* Fila "apagada": el registro sigue ahi y se lee, pero ya no reclama atencion (p.ej. una
   llamada acabada). Antes era un style="opacity:.7" en el <tr>; se aplica a las <td> y no al
   <tr> a proposito, para atenuar el CONTENIDO sin lavar tambien el color de fondo de la fila
   (el zebra / el rosa de prioridad, que se pintan inline en el <tr> — ver asuntos.tpl). */
#sl-app .sl-row--muted > td { opacity: .65; }

.sl-focusable:focus { outline: none; box-shadow: var(--sl-focus); }

.sl-shake { animation: sl-shake 1.8s infinite; }
@keyframes sl-shake {
  0%,100% { transform: translate(1px,1px) rotate(0); }
  25% { transform: translate(-2px,-1px) rotate(-1deg); }
  50% { transform: translate(2px,2px) rotate(1deg); }
  75% { transform: translate(-1px,1px) rotate(0); }
}

/* ——— 12. Capa de compatibilidad Bootstrap 3 (scopeada a #sl-app) ————————
   Mapea los componentes heredados de Nice Admin a los tokens de marca SOLO
   dentro de #sl-app, para unificar pantallas con markup Bootstrap sin tocarlo.
   No afecta a ninguna pantalla que no envuelva su contenido en #sl-app.        */

/* Botones */
#sl-app .btn {
  border-radius: var(--sl-radius-sm); font-weight: 600; box-shadow: none; font-size: .6875rem;
  transition: background .15s, color .15s, border-color .15s, transform .1s;
}
#sl-app .btn:hover { transform: translateY(-1px); }
#sl-app .btn:focus { box-shadow: var(--sl-focus); }
#sl-app .btn-primary { background: var(--sl-blue); border-color: var(--sl-blue); color: #fff; }
#sl-app .btn-primary:hover, #sl-app .btn-primary:focus { background: var(--sl-blue-600); border-color: var(--sl-blue-600); color: #fff; }
#sl-app .btn-danger { background: var(--sl-pink); border-color: var(--sl-pink); color: #fff; }
#sl-app .btn-danger:hover, #sl-app .btn-danger:focus { background: var(--sl-pink-600); border-color: var(--sl-pink-600); color: #fff; }

/* Botones AGRUPADOS (.btn-group / .btn-group-vertical): el radio global de #sl-app .btn
   rompía el aspecto "unido" (cada botón salía redondeado y suelto). Restauramos el reset
   de Bootstrap: solo los extremos llevan radio, los interiores van a 0 y se solapan. */
#sl-app .btn-group > .btn,
#sl-app .btn-group-vertical > .btn { border-radius: 0; }
#sl-app .btn-group > .btn:hover { transform: none; }   /* no "saltar" fuera del grupo */

/* Horizontal: primero a la izquierda, último a la derecha */
#sl-app .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
  border-top-left-radius: var(--sl-radius-sm); border-bottom-left-radius: var(--sl-radius-sm);
}
#sl-app .btn-group > .btn:last-child:not(:first-child),
#sl-app .btn-group > .dropdown-toggle:not(:first-child) {
  border-top-right-radius: var(--sl-radius-sm); border-bottom-right-radius: var(--sl-radius-sm);
}
#sl-app .btn-group > .btn:only-child { border-radius: var(--sl-radius-sm); }

/* Vertical: primero arriba, último abajo */
#sl-app .btn-group-vertical > .btn:first-child:not(:last-child) {
  border-top-left-radius: var(--sl-radius-sm); border-top-right-radius: var(--sl-radius-sm);
}
#sl-app .btn-group-vertical > .btn:last-child:not(:first-child) {
  border-bottom-left-radius: var(--sl-radius-sm); border-bottom-right-radius: var(--sl-radius-sm);
}

/* Inputs */
#sl-app .form-control::placeholder {
  font-weight: 500;
}
#sl-app .form-control {
  border-radius: var(--sl-radius-sm); border-color: var(--sl-border);
  box-shadow: none; color: var(--sl-fg-2); font-size: .75rem;
  font-weight: 500;
}
#sl-app .form-control:focus { border-color: var(--sl-blue); box-shadow: var(--sl-focus); }
#sl-app .sl-filtros-grid > .sl-fcell {
  background: var(--sl-bg-card);
  border-radius: var(--sl-radius-card);
  margin: 0 !important;
  padding: 10px;
  justify-content: start;
}
#sl-app .sl-filtros-grid {
  gap: 15px !important;
  row-gap: 15px !important;
  column-gap: 15px !important;
}
.mb5 {
  margin-bottom: 5px;
}
.mb10 {
  margin-bottom: 10px;
}
.mtb10 {
  margin: 10px 0;
}
.w100 {
  width: 100%;
}
/* Toggle "Ocultar/Mostrar logos de cliente" (sección "Visualización" de <página>.resumen.actividad.tpl
   — asuntos.resumen.actividad.tpl, llamadas.resumen.actividad.tpl): oculta SOLO <img>, el <label> con
   el nombre del cliente se queda siempre visible. Clase aplicada a #sl-app por
   modules/js/common.tpl.js (toggle_cliente_logos) — genérico 2026-09-01: vivía solo en el <style>
   inline de asuntos.tpl porque toggle_cliente_logos() vivía solo en asuntos.tpl.js; al mover esa
   función a common.tpl.js para que la usen más páginas, esta regla se mueve con ella para no
   tener que repetirla en el <style> de cada página nueva. */
#sl-app.sl-hide-cliente-logos .flex_clientes_logos img { display: none; }
/* Misma preferencia, para el logo del componente nuevo (components/cliente-nombre.tpl, ver más
   abajo) en vez de para el <img> que pintaba get_cliente_logo_html_td(). */
#sl-app.sl-hide-cliente-logos .sl-cliente-nombre__logo { display: none; }

/* CLIENTE-NOMBRE — componente genérico para el nombre de un cliente en texto plano dentro de un
   listado (components/cliente-nombre.tpl, a petición del usuario 2026-09-23). Sustituye a la
   pastilla que este dato llevaba antes (una réplica de ".sl-generic-pill.sl-generic-pill--tag"
   aplicada por CSS sobre lo que pintaba $CI->mmaestras->get_cliente_logo_html_td(), escopada a
   "#list-table" — ver más abajo el resto de esa regla, que se queda como respaldo para los
   listados que aún no han migrado a este componente).

   El ancho límite (180px) es el mismo que ya usaba aquella pill para el caso "sin logo": así la
   columna no se ensancha más de lo razonable por un nombre de cliente largo. Rompe de línea en
   los espacios (white-space:normal) y solo parte una palabra por la mitad si esa palabra sola no
   cabe entera (overflow-wrap:break-word) — nunca a lo bruto por cualquier letra. */
.sl-cliente-nombre {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  max-width: 180px;
}
.sl-cliente-nombre--sin-logo,
.sl-cliente-nombre__label {
  display: block;
  max-width: 180px;
  white-space: normal;
  overflow-wrap: break-word;
  word-break: normal;
  font-family: var(--sl-font);
  font-size: .6875rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--sl-fg-2);
  margin: 0;
}
.sl-cliente-nombre__logo {
  height: 40px;
  padding-bottom: 2px;
}
/* Variante compacta ($cln_compact=true): columnas apretadas con varios nombres uno junto a otro,
   como la vista de "varios clientes" de asuntos_clientes.tpl — el mismo caso que antes cubría
   ".clientes_logos.vista_clientes" en css/style.css (80px, rompe también dentro de una palabra:
   con tan poco ancho, preferir partir una palabra a desbordar la columna). */
.sl-cliente-nombre--compact,
.sl-cliente-nombre--compact.sl-cliente-nombre--sin-logo,
.sl-cliente-nombre--compact .sl-cliente-nombre__label {
  max-width: 80px;
}
.sl-cliente-nombre--compact.sl-cliente-nombre--sin-logo,
.sl-cliente-nombre--compact .sl-cliente-nombre__label {
  overflow-wrap: anywhere;
}
.sl-cliente-nombre--compact .sl-cliente-nombre__logo,
.sl-cliente-nombre__logo--compact {
  height: 20px;
}

/* Nombre de cliente en TEXTO PLANO (no pill) — RESPALDO para los listados de #list-table que
   TODAVÍA no han migrado a components/cliente-nombre.tpl (arriba). A petición del usuario
   2026-09-23, generalizado el 2026-09-22 solo para /asuntos, y sustituyendo desde entonces la
   pill que este mismo <label>/<div> llevaba desde el 2026-08-28 (replicaba
   ".sl-generic-pill.sl-generic-pill--tag", ver css/filtros-grid.css — con "…" al cortar y un
   tooltip vía init_cliente_pill_tooltips() para el nombre completo).

   El <label>/<div> lo pinta $CI->mmaestras->get_cliente_logo_html_td(), un método compartido por
   medio proyecto (fichas de cliente, asunto, llamada, encargo, PDFs...) con un <label> distinto
   según el controller/method activos — NO se toca ese método: cambiar su forma de pintar el
   nombre afectaría también a esas otras pantallas, que no son listados y no llevan
   "#list-table". Por eso este respaldo vive escopado a #list-table.

   El tercer selector cubre al cliente SIN ficha de logo: get_cliente_logo_html_td() solo
   envuelve el nombre en un <label> cuando el cliente TIENE fila en la tabla de logos; si no
   la tiene cae en su rama else y escribe el nombre como texto pelado dentro de
   <div class="clientes_logos">, sin <label> que estilar. Se distingue por
   ":not(.flex_clientes_logos)" y NO por ":not(:has(label))" a propósito: la rama con logo y
   "cl_solo_logo" activo también sale sin <label> —solo la imagen— y ahí no hay ningún nombre
   que envolver. */
#list-table .flex_clientes_logos {
  max-width: 180px;
}
#list-table .clientes_logos label,
#list-table .flex_clientes_logos label,
#list-table .clientes_logos:not(.flex_clientes_logos) {
  display: block;
  max-width: 180px;
  white-space: normal;
  overflow: visible;
  overflow-wrap: break-word;
  word-break: normal;
  text-overflow: clip;
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  margin: 0;
}
/* El div sin logo arrastra "width:180px" de .clientes_logos (css/style.css): sin esto sería
   siempre una caja de 180px de ancho aunque el nombre sea corto, en vez de abrazar su texto. */
#list-table .clientes_logos:not(.flex_clientes_logos) {
  width: auto;
}
/* Reliquia de la pill anterior: la clase la ponía init_cliente_pill_tooltips() (modules/js/
   common.tpl.js) solo cuando el nombre se cortaba de verdad. Con el texto envolviendo en vez de
   cortar, el JS ya casi nunca la llega a poner, pero se deja: una palabra suelta más ancha que
   180px seguiría desbordando y ahí sigue teniendo sentido el tooltip + cursor de ayuda. */
#list-table .sl-cliente-pill--truncada { cursor: help; }
.separator {
  width: 100%;
  height: 1px;
  background: var(--sl-border-3);
  /*background: var(--sl-border);*/
  margin: 10px 0;
}
#sl-app form select.form-control {
  height: 34px;
  padding: 0 3px;
}

/* ============================================================================
   Talla de controles: DOS versiones (mini 24px / normal 34px) activables con
   una sola clase, para <input>, <select> normal o <select> con select2 — en
   cualquier pantalla, no exclusivo de los paneles de filtro. Autocontenidas
   (no dependen de qué altura tuviera el control antes), así que basta con
   poner UNA de las dos para que funcione igual en cualquier sitio.
   ============================================================================ */
.sl-ctrl--mini.form-control,
select.sl-ctrl--mini.form-control {
  height: 24px !important;
  padding-top: 1px !important; padding-bottom: 1px !important;
  font-size: .6875rem !important; /* 11px, igual que .sl-generic-pill */
}
.sl-ctrl--normal.form-control,
select.sl-ctrl--normal.form-control {
  height: 34px !important;
  padding-top: 6px !important; padding-bottom: 6px !important;
  font-size: .6875rem !important; /* 11px, igual que .sl-generic-pill */
}
/* Select2 no sustituye el <select>: lo oculta y pinta su widget como HERMANO
   inmediato (<span class="select2-container">). La clase de talla va en el
   <select> original, así que hay que engancharla con "+" para que le llegue
   al widget que realmente se ve. */
select.sl-ctrl--mini + .select2-container .select2-selection--single {
  height: 24px !important;
  border: 1px solid var(--sl-border) !important;
  border-radius: var(--sl-radius-sm) !important;
  background: #fff; box-shadow: none;
}
select.sl-ctrl--mini + .select2-container .select2-selection--single .select2-selection__rendered {
  line-height: 22px; padding-left: 8px;
  color: var(--sl-fg-2); font-size: 13px !important; font-weight: 500;
}
select.sl-ctrl--mini + .select2-container .select2-selection--single .select2-selection__arrow {
  height: 22px !important; top: 0 !important;
}
select.sl-ctrl--normal + .select2-container .select2-selection--single {
  height: 34px !important;
  border: 1px solid var(--sl-border) !important;
  border-radius: var(--sl-radius-sm) !important;
  background: #fff; box-shadow: none;
}
select.sl-ctrl--normal + .select2-container .select2-selection--single .select2-selection__rendered {
  line-height: 32px; padding-left: 12px;
  color: var(--sl-fg-2); font-size: .6875rem !important; font-weight: 500;
}
select.sl-ctrl--normal + .select2-container .select2-selection--single .select2-selection__arrow {
  height: 32px !important; top: 0 !important;
}
/* Foco/abierto: mismo anillo azul que #sl-app .form-control:focus, en las dos tallas */
select.sl-ctrl--mini + .select2-container--focus .select2-selection--single,
select.sl-ctrl--mini + .select2-container--open .select2-selection--single,
select.sl-ctrl--normal + .select2-container--focus .select2-selection--single,
select.sl-ctrl--normal + .select2-container--open .select2-selection--single {
  border-color: var(--sl-blue) !important;
  box-shadow: var(--sl-focus);
}

/* Select2 "filtro" genérico (components/select2.tpl): antes cada selector.*.tpl traía su
   propio <style> embebido con estas mismas reglas por ID (triplicado y desincronizable, que es
   justo lo que pasó). Ahora se marca vía containerCssClass/dropdownCssClass en el init de JS
   (modules/js/select2.filtro.tpl.js), así que una sola regla vale para todos los select2 de
   filtro presente o futuros, sin depender de su id. Tipografía grande a propósito para leer
   bien al buscar — igual que antes. */
.sl-select2-filtro-dropdown .select2-results__option {
  font-family: var(--sl-font);
  font-weight: 700;
  font-size: 15px;
}
.sl-select2-filtro-dropdown .select2-results__option[aria-disabled=true] {
  display: none;
}
#sl-app .panel-heading::after {
  display: none;
}
/* Paneles */
#sl-app .panel {
  border: 1px solid var(--sl-border); border-radius: var(--sl-radius-md);
  box-shadow: var(--sl-shadow-sm);
  margin-bottom: 0;
}
#sl-app .panel-heading {
  background: var(--sl-blue-100); border-bottom: 1px solid var(--sl-border);
  color: var(--sl-blue); font-weight: 700;
  box-shadow: none;
  padding: var(--sl-space-2) 1rem;
  padding-bottom: var(--sl-space-2) !important;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sl-space-2);
}
/* PANEL TABS INVENTARIO CLIENTES */
#inventario > header {
  background: var(--sl-blue) !important;
}
#sl-app .panel-heading i {
  border: none;
  /*font-size: inherit;*/
}
#sl-app div.panel-body {
  box-shadow: none;
}
#sl-app .panel-heading .panel-left,
#sl-app .panel-heading .panel-left .panel-left-form form,
#sl-app .panel-heading .panel-left .panel-left-form form .sl-sf,
#sl-app .panel-heading .panel-left .panel-left-form form .sl-sf .sl-sf-input,
#sl-app .panel-heading .panel-right {
  display: flex;
  align-items: center;
  gap: var(--sl-space-2);
}
/* Badges / labels */
#sl-app .label-primary { background: var(--sl-blue); border-radius: var(--sl-radius-pill); font-weight: 600; }

/* Alerts */
#sl-app .alert { border-radius: var(--sl-radius-md); }

/* Cabeceras de página heredadas */
#sl-app .page-header { border-bottom-color: var(--sl-border); }

/* Nombre de cliente: unificar tipografía venga en <label> (con logo) o en
   <div> de texto plano (sin logo). El helper get_cliente_logo_html_td() usa
   ambos caminos, por eso sin esto el peso de letra difiere entre clientes. */
#sl-app .clientes_logos,
#sl-app .clientes_logos label {
  font-family: var(--sl-font);
  font-size: .6875rem; font-weight: 600; color: var(--sl-fg-2);
  margin: 0;
}

/* Tablas legacy (.table.webapp / border-round-th) → look del sistema en
   pantallas migradas: cabecera tipo panel (fondo + línea fina), filas con
   separador fino y hover suave. Se respetan los fondos de fila inline
   (zebra / prioridad), que son semánticos. */
#sl-app .sl-table-bordered {
  border: 1px solid var(--sl-border);
  border-radius: var(--sl-radius-md);
}
/* Una tabla DENTRO de una tarjeta (.sl-panel): el borde y el radio los pone ya el panel, así que
   .sl-table-bordered se queda sin los suyos para no dibujar dos marcos concéntricos. Y como
   .sl-panel lleva overflow:hidden, una tabla más ancha que el panel se recortaría en vez de
   poder desplazarse: de ahí el overflow-x:auto, que es justo lo que hace el artboard
   Encargos.dc.html envolviendo cada tabla en un contenedor con scroll horizontal propio. */
/* Las tablas de las tarjetas del encargo (alertas, citas, llamadas, partes…) iban a ras del
   borde de la tarjeta, mientras que las filas de campos de las otras secciones sí llevaban su
   aire (.sl-fieldrow, 11px 14px). Se les da el mismo — a petición del usuario 2026-09-10.
   El selector cubre los dos sitios donde puede colgar la tabla: hija directa de la tarjeta
   (como estaba) o dentro del .sl-disclosure__body desde que las secciones se pliegan. */
#sl-app .sl-panel > .sl-table-bordered,
#sl-app .sl-panel > .sl-disclosure__body > .sl-table-bordered {
  border: 0;
  border-radius: 0;
  overflow-x: auto;
  /*padding: 11px 14px;*/
}
/* Las tablas que no traen el envoltorio .sl-table-bordered (la de reclamaciones) cuelgan
   directas del panel: necesitan el mismo scroll, y se lo damos al propio <table>. */
#sl-app .sl-panel > .table-responsive { border: 0; }
#sl-app .table-striped>tbody>tr:nth-child(odd)>td,
#sl-app .table-striped>tbody>tr:nth-child(odd)>th {
  background-color: var(--sl-bg-page);
}
#sl-app .table-striped>tbody>tr:nth-child(even)>td,
#sl-app .table-striped>tbody>tr:nth-child(even)>th {
  background-color: var(--sl-blue-100);
}
/* La celda de acciones no debe abrir un agujero blanco en la fila rayada.
   ".hide_from_print" (css/style.css:7281) hace DOS cosas a la vez: marca la celda para que
   jquery.printPage.js la oculte al imprimir —que es lo que queremos— y además le fuerza
   "background-color: transparent !important" en pantalla, pensado para las columnas
   espaciadoras vacías de los listados antiguos. En una columna de acciones dentro de una tabla
   rayada ese segundo efecto se ve como una celda blanca al final de una fila azul.
   Hace falta "!important" porque la regla de style.css también lo lleva; la especificidad de
   estos selectores (un id + tres clases) ya le gana de sobra. Escopado a "#sl-app" a propósito:
   fuera del rediseño la clase sigue comportándose como siempre. */
#sl-app .table-striped>tbody>tr:nth-child(odd)>td.hide_from_print,
#sl-app .table-striped>tbody>tr:nth-child(odd)>th.hide_from_print {
  background-color: var(--sl-bg-page) !important;
}
#sl-app .table-striped>tbody>tr:nth-child(even)>td.hide_from_print,
#sl-app .table-striped>tbody>tr:nth-child(even)>th.hide_from_print {
  background-color: var(--sl-blue-100) !important;
}
#sl-app .table-striped>tbody>tr:nth-child(odd):last-child>td:first-child,
#sl-app .table-striped>tbody>tr:nth-child(even):last-child>td:first-child {
  border-bottom-left-radius: var(--sl-radius-md);
}
#sl-app .table-striped>tbody>tr:nth-child(odd):last-child>td:last-child,
#sl-app .table-striped>tbody>tr:nth-child(even):last-child>td:last-child {
  border-bottom-right-radius: var(--sl-radius-md);
}
/* Fila de totales dentro de una tabla cebrada (la última del tbody en la tabla de partes
   del encargo). Sin esto entra en el ritmo del cebrado y, con un nº impar de filas de datos,
   se tiñe exactamente igual que una de ellas y deja de leerse como un resumen.
   No basta con sacarla a un <tfoot> —donde quedaría fuera del cebrado sin ninguna regla—:
   el ordenado por columna de modules/js/encargos.tpl.js la localiza con 'tbody tr:last' para
   reponerla al final, y desde un <tfoot> ese selector devolvería un parte cualquiera.
   ⚠️ Gana por ORDEN, no por especificidad: empata a (1,2,3) con la regla del cebrado de
   arriba, porque :nth-child() puntúa como una clase igual que .sl-row-total. Tiene que
   seguir DESPUÉS de ese bloque; subirla aquí arriba la deja sin efecto y sin ningún aviso. */
#sl-app .table-striped > tbody > tr.sl-row-total > td {
  background-color: var(--sl-bg-page);
}

/* --- Fila de PARTE URGENTE (tabla de partes del encargo) -------------------
   El listado /partes marca la urgencia tiñendo la FILA de rosa, sin columna propia; la tabla
   de partes del encargo hace ya lo mismo desde el 2026-09-15 (usuario), y su columna "Urg."
   desapareció con ello. Los dos tonos son los MISMOS literales que partes.tpl, a propósito:
   si uno cambia, que el otro cante.

   ⚠️ Dos motivos por los que esto es CSS aquí y no un style inline como en partes.tpl:
      · Esa tabla sí conserva ".table-striped" (partes.tpl tuvo que quitárselo), porque su
        cebrado tiene que sobrevivir al ordenado por columna de encargos.tpl.js, que reordena
        los <tr> en el cliente: un zebra escrito en el propio <tr> viajaría con la fila y se
        descolocaría al ordenar.
      · Y con ".table-striped" puesto el fondo lo pinta el <td>, que tapa cualquier color del
        <tr> — que es justo lo que obligó a partes.tpl a renunciar a la clase.

   ⚠️ El "!important" y el segundo selector de cada par NO sobran: las celdas ".hide_from_print"
      (la del checkbox y la de acciones) reciben su fondo con "!important" unas líneas más
      arriba, así que sin esto la fila urgente saldría rosa con dos huecos pálidos en los
      extremos.

   ⚠️ Y como .sl-row-total, gana por ORDEN: empata en especificidad con el cebrado, así que
      tiene que seguir DESPUÉS de aquel bloque. */
#sl-app .table-striped > tbody > tr.sl-row-urgente > td,
#sl-app .table-striped > tbody > tr.sl-row-urgente > td.hide_from_print {
  background-color: #ffe0e6 !important;
}
#sl-app .table-striped > tbody > tr.sl-row-urgente:nth-child(even) > td,
#sl-app .table-striped > tbody > tr.sl-row-urgente:nth-child(even) > td.hide_from_print {
  background-color: #ffc4cf !important;
}
#sl-app .table .border-right {
  border-right: 1px solid var(--sl-border);
}
#sl-app .table tbody:last-child {
  border-bottom: 0;
}
#sl-app td.footable-sortable>span.fooicon, #sl-app th.footable-sortable>span.fooicon {
  position: relative;
  right: -5px;
  top: unset;
  margin-top: unset;
  opacity: .2;
  transition: opacity .3s ease-in;
  font-size: 12px;
}
#sl-app td.footable-sortable:hover>span.fooicon, #sl-app th.footable-sortable:hover>span.fooicon {
  opacity: 1;
}
#sl-app .table.webapp {
  /*border: 1px solid var(--sl-border); border-radius: var(--sl-radius-md);*/
  margin-bottom: 0;
}

#sl-app .table.webapp th,
#sl-app .table.webapp.border-round-th th {
  color: var(--sl-blue);
  border: 0; border-bottom: 1px solid var(--sl-border);
  border-radius: 0; font-weight: 700; font-size: .8125rem;
  padding: .5rem .3rem !important;
  vertical-align: middle;
  position: relative;
}
#sl-app .table.webapp.border-round-th tr:not(.footable-filtering) th {
  background: transparent;
}
#sl-app .table.webapp th, #sl-app .table.webapp.border-round-th .footable-filtering th:first-child {
  padding: 15px !important;
}
#sl-app tr.footable-filtering th form.form-inline {
  margin-bottom: 0px !important;
  display: flex;
  align-items: center;
  gap: 10px;
}
/* Opt-in: separa el grupo de filtro y lo que venga después (p.ej. el botón "Nuevo X" que
   algunas pantallas — inventario.tpl.js — añaden tras el .input-group) llevándolos a los
   extremos opuestos de la fila. No se aplica por defecto en form.form-inline porque la
   mayoría de tablas (alertas, comunicados, config/*...) no añaden nada más ahí y no deben
   cambiar de comportamiento. */
#sl-app tr.footable-filtering th form.form-inline.sl-filter-toolbar--spread {
  justify-content: space-between;
  width: 100%;
}
#sl-app tr.footable-filtering .input-group input,
#sl-app tr.footable-filtering .input-group-btn button {
  height: 1.75rem;
}
#sl-app tr.footable-filtering .input-group {
  display: flex;
  gap: 5px;
}
#sl-app tr.footable-filtering .input-group .btn-primary > * {
  line-height: 0 !important;
  font-size: .75rem;
}
#sl-app .table.webapp td {
  /*border-top: 0;*/ border-bottom: 1px solid var(--sl-border); color: var(--sl-fg-2);
  padding: .45rem .3rem !important;
  font-size: .75rem;
  font-weight: 500;
}
#sl-app .table.webapp tbody tr:last-child td { border-bottom: 0; }
#sl-app .table-tr-hover > tbody > tr:hover { background-color: var(--sl-blue-050) !important; }
#sl-app #list-table-material th, #sl-app #list-table-material td { padding-left: .75rem !important; padding-right: .75rem !important; }

/* Paginador de FooTable (módulo "paging"): re-tokeniza el <ul class="pagination">
   estándar de Bootstrap 3 que genera la librería. */
#sl-app .pagination > li > a,
#sl-app .pagination > li > span {
  border-color: var(--sl-border);
  color: var(--sl-fg-2);
  font-size: .75rem;
  font-weight: 600;
}
#sl-app .pagination > li > a:hover,
#sl-app .pagination > li > a:focus {
  background: var(--sl-blue-050);
  border-color: var(--sl-border-2);
  color: var(--sl-blue);
}
#sl-app .pagination > li.active > a,
#sl-app .pagination > li.active > span,
#sl-app .pagination > li.active > a:hover {
  background: var(--sl-blue);
  border-color: var(--sl-blue);
  color: #fff;
}
#sl-app .pagination > li.disabled > a,
#sl-app .pagination > li.disabled > span { color: var(--sl-fg-3); }

/* Iconos .asunto-marcas-clientes (👁 / creado-por-cliente): son position:absolute SIN offsets.
   Con el scroll interno del shell (#sl-app/.wrapper) su bloque contenedor quedaba FUERA del
   scroll, así que al hacer scroll del listado los iconos se quedaban flotando fuera de sitio.
   Posicionamos su celda contenedora para que el anclaje sea local y acompañen a la fila. */
#sl-app td:has(> .asunto-marcas-clientes) { position: relative; }

/* Cabecera del asunto (modules/asunto.cabecera.tpl): el título no trae color
   propio y heredaba el gris-azulado de #sl-app (--sl-fg-2) que, con su
   opacity:.7 inline, quedaba lavado ("gris raro"). Color de marca + opacidad
   plena (!important bate el opacity inline). */
#sl-app .asunto_cabecera > div:first-child {
  color: var(--sl-blue);
  opacity: 1 !important;
}

/* Labels flotantes .label-header-sup (cabeceras de campo tipo "HORAS TOTALES"):
   son position:absolute con offset fijo pensado para UNA línea. Montserrat es
   más ancha que la fuente legacy, así que algunos labels envolvían a 2 líneas
   y la segunda se solapaba con el valor de abajo. nowrap restaura la línea
   única (intención original del patrón). */
#sl-app .label-header-sup { white-space: nowrap; }

/* ——— 14. Chrome legacy: barra superior + menú lateral —————————————————————
   La barra (header.megaheader) y el menú (#sidebar) son layout GLOBAL, fuera de
   #sl-app. Se tokenizan aquí por sus selectores propios. Como este CSS solo se
   carga en pantallas migradas, el restyle SOLO afecta a esas pantallas; el resto
   de la app conserva su aspecto. Sin tocar el markup de barra.tpl / menu.tpl.    */

/* --- Barra superior (ya es .white-bg) --- */
.header.megaheader.white-bg {
  background: #fff;
  /*border-bottom: 1px solid var(--sl-border);*/
  box-shadow: var(--sl-shadow-sm);
}
.megaheader .btn {
  border-radius: var(--sl-radius-sm); font-weight: 600; box-shadow: none;
  transition: background .15s, color .15s, border-color .15s, transform .1s;
}
.megaheader .btn:hover { transform: translateY(-1px); }
.megaheader .btn-primary { background: var(--sl-blue); border-color: var(--sl-blue); }
/* Hover de los botones del header: invierte a fondo blanco con icono/texto azul (mismo azul del botón normal) */
.megaheader .btn-primary:hover, .megaheader .btn-primary:focus,
.megaheader ul.top-menu-avisos a.avisos-citas:hover, .megaheader ul.top-menu-avisos a.avisos-citas:focus {
  background: #fff; color: var(--sl-blue); border-color: var(--sl-blue);
}
.megaheader .btn-primary:hover i, .megaheader .btn-primary:hover .fa,
.megaheader .btn-primary:focus i, .megaheader .btn-primary:focus .fa,
.megaheader ul.top-menu-avisos a.avisos-citas:hover i, .megaheader ul.top-menu-avisos a.avisos-citas:hover .fa,
.megaheader ul.top-menu-avisos a.avisos-citas:focus i, .megaheader ul.top-menu-avisos a.avisos-citas:focus .fa {
  color: var(--sl-blue);
}
/* Badge de notificación de los botones del header: círculo rosa con anillo blanco,
   asomando por la esquina (en vez del azul clavado que se confundía con el botón).
   El círculo/anillo/sombra/color en sí los aporta la clase genérica .sl-badge-count
   (aplicada en el HTML junto a .badge); aquí solo queda lo específico de este
   contexto: sacarlo de flujo y clavarlo en la esquina del botón. */
.megaheader ul.top-menu-avisos a.avisos-citas { position: relative; overflow: visible; }
.megaheader ul.top-menu-avisos a.avisos-citas .badge {
  position: absolute; top: -5px; right: -5px; left: auto;
}
.megaheader ul.top-menu-avisos a.avisos-citas .badge > small {
  top: 0; font-size: inherit; font-weight: 700;
}
/* En hover (botón blanco) el anillo blanco se mimetiza: usar azul para separarlo */
.megaheader ul.top-menu-avisos a.avisos-citas:hover .badge,
.megaheader ul.top-menu-avisos a.avisos-citas:focus .badge {
  border-color: var(--sl-blue);
}
.megaheader .form-control { border-radius: var(--sl-radius-sm); border-color: var(--sl-border); box-shadow: none; }
.megaheader .form-control:focus { border-color: var(--sl-blue); box-shadow: var(--sl-focus); }
.megaheader .fecha-calendar {
  background: var(--sl-blue-050); background-image: none;
  color: var(--sl-blue); font-weight: 600; font-size: .8125rem;
  border: 1px solid var(--sl-border); border-radius: var(--sl-radius-sm);
  padding: 5px 10px;
}
.megaheader a:hover .fecha-calendar { background: var(--sl-blue-100); }

/* --- Menú lateral ---
   El sidebar NO lleva la clase .white-bg (su fondo legacy es #1a2732 oscuro), así
   que forzamos el look claro del sistema de forma incondicional y consistente. */
#sidebar.nav-collapse { background: #fff; border-right: 1px solid var(--sl-border); }
ul.sidebar-menu li a {
  background: #fff;
  color: var(--sl-fg-2);
  /* !important para batir la regla legacy (font-size:14px!important; font-weight:bold!important) */
  font-weight: 400 !important; font-size: var(--sl-menu-fuente, 16px) !important;
  border-right: none; border-bottom: 1px solid var(--sl-border);
}
ul.sidebar-menu li a span { font-weight: 400 !important; font-size: var(--sl-menu-fuente, 16px) !important; }
/* line-height SOLO en el label de primer nivel: es el que produce las dos lineas de
   "Asuntos Comerciales" y por tanto quien decide el alto de fila del estado expandido.
   Fuera de aqui no se toca, para no alterar el interlineado de los submenus. */
#sidebar > ul.sidebar-menu > li > a > .sidebar-menu-extra { line-height: var(--sl-menu-lh, 20px); }
.mega-design.menu-vertical #sidebar>ul.sidebar-menu>li>a {
  padding: var(--sl-menu-pad-y, 15px) var(--sl-menu-pad-x, 15px);
}
.mega-design.menu-vertical .sidebar-menu li a i {
  font-size: var(--sl-menu-icono, 20px);
}
ul.sidebar-menu li a i.fofipol { color: var(--sl-blue); }
ul.sidebar-menu li.active a,
ul.sidebar-menu li a:hover,
ul.sidebar-menu li a:focus { background: var(--sl-blue); color: #fff !important; }
ul.sidebar-menu li.active a i.fofipol,
ul.sidebar-menu li a:hover i.fofipol,
ul.sidebar-menu li a:focus i.fofipol { color: #fff; }   /* contraste sobre azul */
/* Submenús */
ul.sidebar-menu li ul.sub li { background: #fff; }
ul.sidebar-menu li ul.sub li a { background: #fff; color: var(--sl-fg-2) !important; font-size: .8125rem !important; font-weight: 600 !important; }
ul.sidebar-menu li ul.sub li a:hover,
ul.sidebar-menu li ul.sub li.active a { background: var(--sl-blue); color: #fff !important; }
/* Contadores del menú vertical: el legacy small.alerta-small los pintaba como un círculo
   flotado y desplazado hacia abajo (top:12px). Aquí los normalizamos a píldora compacta,
   igual estilo que el badge del menú horizontal (.site-menu-badge). */
ul.sidebar-menu .alerta-small {
  float: none; position: static; top: auto; right: auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: auto; min-width: 18px; height: 18px; padding: 0 6px;
  border: 0; border-radius: 9px;
  background: #e74c3c; color: #fff;
  font-size: 11px; font-weight: 700; line-height: 1;
  vertical-align: middle;
}
/* En ítem activo/hover (fondo azul) el badge sigue legible (rojo sobre azul, texto blanco) */
ul.sidebar-menu li a:hover .alerta-small,
ul.sidebar-menu li.active > a .alerta-small { color: #fff; }

/* ——— 15. Diálogos (modales) y tooltips: chrome global FUERA de #sl-app ————
   Las modales de bootstrap-dialog y los tooltips de Bootstrap se inyectan al
   final del <body>, FUERA de #sl-app, así que no se les puede aplicar el ancla
   de especificidad del sistema: se tokenizan por sus selectores propios.
   Como softline-ui.css se carga DESPUÉS del bundle de Nice Admin y de
   bootstrap-dialog-theme.css, estas reglas ganan por orden de cascada (mismo
   peso de especificidad) salvo donde el legacy usa !important (cabecera).
   El CSS se carga en todas las pantallas, por lo que el restyle es global. */

/* --- Contenedor de la modal --- */
.bootstrap-dialog .modal-content,
.modal-dialog .modal-content {
  font-family: var(--sl-font);
  border: 1px solid var(--sl-border);
  border-radius: var(--sl-radius-lg);
  box-shadow: var(--sl-shadow-md);
  overflow: hidden;   /* recorta cabecera/footer a las esquinas redondeadas */
}

/* --- Cabecera: barra azul de marca --- */
/* !important para batir el legacy `div.bootstrap-dialog.type-primary .modal-header
   { background:#01209F !important }`. Solo afecta a la cabecera por defecto/primary;
   las modales semánticas (type-danger/success/warning del bundle) conservan su color. */
.bootstrap-dialog .modal-header,
.modal-dialog .modal-header,
div.bootstrap-dialog.type-primary .modal-header {
  background: var(--sl-blue) !important;
  border: 0;
  border-top-left-radius: var(--sl-radius-lg);
  border-top-right-radius: var(--sl-radius-lg);
  text-shadow: none;
  padding: .625rem 1rem;
}
.bootstrap-dialog .bootstrap-dialog-title,
.modal-dialog .modal-header .bootstrap-dialog-title {
  font-family: var(--sl-font);
  font-size: .9375rem; font-weight: 700;
  color: #fff; top: 0;
}
/* Botón de cierre: × rosa de marca sobre la barra azul (sin text-shadow legacy).
   Se replica el prefijo `div` del legacy para igualar especificidad (0,0,2,2 /
   0,0,3,3) y ganar por orden de carga; sin él, el `color:#E0007A` legacy vence. */
div.bootstrap-dialog-close-button button.close,
div.modal-dialog div.modal-header button.close {
  margin-top: 0;
  color: var(--sl-pink);
  opacity: 1;
  text-shadow: none;
  font-size: 1.625rem; font-weight: 400; line-height: 1;
  transition: color .15s, transform .1s;
}
.bootstrap-dialog .modal-header button.close:hover,
.bootstrap-dialog .modal-header button.close:focus,
.modal-dialog .modal-header button.close:hover,
.modal-dialog .modal-header button.close:focus {
  color: #FF7AAA !important;   /* rosa más claro al pasar; !important bate el legacy `color:red!important` */
  transform: scale(1.1);
}

/* --- Cuerpo --- */
.bootstrap-dialog .modal-body,
.modal-dialog .modal-body {
  font-family: var(--sl-font);
  color: var(--sl-fg-2);
  background: #fff;   /* shorthand: neutraliza las sombras-gradiente de scroll del legacy */
}
.bootstrap-dialog .modal-body .form-control,
.modal-dialog .modal-body .form-control {
  border-radius: var(--sl-radius-sm); border-color: var(--sl-border);
  box-shadow: none; color: var(--sl-fg-2); font-size: .75rem;
}
.bootstrap-dialog .modal-body .form-control:focus,
.modal-dialog .modal-body .form-control:focus {
  border-color: var(--sl-blue); box-shadow: var(--sl-focus);
}

/* --- Toggle "mini" de bootstrap-toggle dentro de un diálogo ----------------
   Separa el interruptor de su <label>, que va SIEMPRE a su izquierda y como
   hermano (no envolviéndolo). "mini" es el tamaño que usa toda la aplicación:
   bootstrap-toggle traduce data-size="mini" a .btn-xs, de ahí el selector.

   Hasta el 2026-09-15 esta regla estaba COPIADA en el <style> inline de VEINTE
   diálogos (todos los .tpl de modules/dialog/ con un toggle), idéntica en los
   veinte: .toggle.btn-xs { margin-left: 5px; }

   Dos decisiones que conviene no deshacer:

   1) Va acotada a .modal, y no global. Un <style> que llega dentro de un
      cuerpo de diálogo cargado por AJAX se inyecta en el DOCUMENTO y no tiene
      ámbito: mientras el diálogo estaba abierto, la regla se escapaba y
      desplazaba 5px los toggles de la pantalla de debajo. Medido en
      /asunto/ver: sus 6 toggles pasaban de margin-left 0px a 5px al abrir
      "Editar asunto", y volvían al cerrarlo. Acotarla arregla ese salto y deja
      las pantallas exactamente como estaban.

   2) El .modal va dentro de :where() para que la regla siga valiendo 0-2-0,
      la misma especificidad que tenía suelta en los diálogos. Así no cambia
      ningún desempate: en el bundle (compiled.css) el plugin declara
      ".checkbox label .toggle, .checkbox-inline .toggle { margin-left:-20px }",
      que es 0-2-1 y por tanto GANA a esta regla. Hoy eso no afecta a nadie
      porque ningún toggle del proyecto vive dentro de un ".checkbox label",
      pero si algún día lo hace, seguirá comportándose como hasta ahora en vez
      de cambiar en silencio. Escribir ".modal .toggle.btn-xs" (0-3-0) le daría
      la vuelta a ese desempate.

   NO lleva prefijo #sl-app a propósito: las modales de bootstrap-dialog se
   cuelgan del <body>, FUERA de #sl-app, así que ese prefijo no las alcanzaría.
   ---------------------------------------------------------------------------- */
:where(.modal) .toggle.btn-xs { margin-left: 5px; }

/* --- Pie: fondo suave + hairline (sin bordes negros / sombras / text-shadow legacy) --- */
.bootstrap-dialog .modal-footer,
.modal-dialog .modal-footer {
  background: var(--sl-bg-soft);
  border: 0;
  border-top: 1px solid var(--sl-border);
  border-bottom-left-radius: var(--sl-radius-lg);
  border-bottom-right-radius: var(--sl-radius-lg);
  box-shadow: none;
  text-shadow: none;
  padding: .625rem 1rem;
}
/* Botones del pie: la capa de compat de #sl-app no llega aquí, así que se
   re-tokenizan explícitamente (matando el degradado de .btn-default). */
.bootstrap-dialog .modal-footer .btn,
.modal-dialog .modal-footer .btn {
  border-radius: var(--sl-radius-sm);
  font-weight: 600; font-size: .75rem;
  box-shadow: none; background-image: none;
  transition: background .15s, color .15s, border-color .15s, transform .1s;
}
.bootstrap-dialog .modal-footer .btn:hover,
.modal-dialog .modal-footer .btn:hover { transform: translateY(-1px); }
.bootstrap-dialog .modal-footer .btn:focus,
.modal-dialog .modal-footer .btn:focus { box-shadow: var(--sl-focus); outline: none; }

.bootstrap-dialog .modal-footer .btn-primary,
.modal-dialog .modal-footer .btn-primary {
  background: var(--sl-blue); border-color: var(--sl-blue); color: #fff;
}
.bootstrap-dialog .modal-footer .btn-primary:hover,
.bootstrap-dialog .modal-footer .btn-primary:focus,
.modal-dialog .modal-footer .btn-primary:hover,
.modal-dialog .modal-footer .btn-primary:focus {
  background: var(--sl-blue-600); border-color: var(--sl-blue-600); color: #fff;
}
.bootstrap-dialog .modal-footer .btn-default,
.modal-dialog .modal-footer .btn-default {
  background: #fff; background-image: none;
  border-color: var(--sl-border); color: var(--sl-fg-2);
}
.bootstrap-dialog .modal-footer .btn-default:hover,
.bootstrap-dialog .modal-footer .btn-default:focus,
.modal-dialog .modal-footer .btn-default:hover,
.modal-dialog .modal-footer .btn-default:focus {
  background: var(--sl-blue-050); border-color: var(--sl-border-2); color: var(--sl-blue);
}

/* --- Tooltips: azul de marca (en vez del #007aff iOS del bundle Nice Admin) ---
   Se igualan los selectores del bundle (misma especificidad) y ganan por orden
   de carga. NO se tocan .danger-tooltip / .success-tooltip (mayor especificidad
   en style.css): conservan su color semántico (rojo / verde). */
.tooltip { font-family: var(--sl-font); }
/* z-index: el bundle Nice Admin trae la escala de Bootstrap 3.0, donde .tooltip (1030)
   queda POR DEBAJO de .modal y .bootstrap-dialog (1050) — Bootstrap lo corrigió en 3.1
   subiendo el tooltip a 1070. Con 1030, cualquier tooltip inicializado con
   container:'body' —que es lo que hacen TODOS los componentes del sistema de diseño:
   components/pill.tpl, components/id-badge.tpl… ver la nota de pill.tpl sobre por qué
   llevan solo data-toggle y no la clase .tooltips— se pinta DETRÁS del diálogo y no se
   ve. Comprobado en vivo en la ficha (modules/dialog/dialog.ficha.tpl) con
   document.elementFromPoint: devolvía el contenido del diálogo, no el tooltip.
   1055 y no el 1070 de Bootstrap 3.1 a propósito: basta para quedar sobre el diálogo
   (1050) y se mantiene por debajo de .swal2-container y de los dropdown de
   bootstrap-select (1060), que sí deben tapar al tooltip. */
.tooltip { z-index: 1055; }
.tooltip.in { opacity: 1; filter: alpha(opacity=100); }
.tooltip-inner {
  background-color: var(--sl-blue);
  color: #fff;
  font-size: .6875rem; font-weight: 500;
  padding: .25rem .5rem;
  border-radius: var(--sl-radius-sm);
  box-shadow: var(--sl-shadow-md);
}
.tooltip.top .tooltip-arrow,
.tooltip.top-left .tooltip-arrow,
.tooltip.top-right .tooltip-arrow   { border-top-color: var(--sl-blue); }
.tooltip.right .tooltip-arrow       { border-right-color: var(--sl-blue); }
.tooltip.left .tooltip-arrow        { border-left-color: var(--sl-blue); }
.tooltip.bottom .tooltip-arrow,
.tooltip.bottom-left .tooltip-arrow,
.tooltip.bottom-right .tooltip-arrow { border-bottom-color: var(--sl-blue); }

/* POPOVERS JS PANTALLA ASUNTOS */
.popover-title {
  background-color: var(--sl-blue);
  color: #ffffff;
}

.popover-content {
  font-size: 14px;
  font-weight: normal;
  padding: 2px 5px;
}
/* FIN POPOVERS JS PANTALLA ASUNTOS */

/* ETIQUETAS del selector "Elegir etiquetas": centrado del icono dentro del círculo.
   ".etiqueta-lista" (css/style.css) centra su icono con "padding-top:3px; padding-left:1px",
   un apaño pre-flex que NO centra: el <i> es inline, así que su posición depende del line box
   —y por tanto del line-height heredado— y no solo del padding. Medido en vivo (2026-09-02, el
   usuario lo reportó con una captura): el icono caía a 7px del borde superior de una caja de
   20px siendo el propio icono de 14px de alto, o sea sobresaliendo 1px por ABAJO del círculo.
   Esta regla, sin prefijo, lo arregla en cualquier contenedor.
   ⚠️ Ojo antes de tocar esto: ".etiqueta-lista" ya NO la emite ninguna plantilla. Su único
   emisor vivo es PHP — Etiquetas_Model::get_texto_html() con $tipo='encargo'
   (php/phastard/app/models/etiquetas_model.php), que se pinta desde
   modules/elegir_etiquetas.tpl dentro de los diálogos de edición de asunto y de encargo
   (comprobado en vivo: GET /asunto/get/encargo_edit/update devuelve 4 divs
   class="tooltips etiqueta-lista"). Los LISTADOS y la ficha usan components/etiquetas.tpl →
   components/pill.tpl, con marcado ".sl-generic-pill" que no tiene nada que ver con esto.
   Por eso se purgaron (2026-09-11) la regla "#list-table .etiqueta-lista" que vivía aquí y
   ".height-forced" de style.css: sin plantillas que las emitan, no quedaba nada que activarlas. */
.etiqueta-lista {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

/* ETIQUETA EN ENCARGO */
.etiqueta-encargo {
  border: 1px solid;
  border-radius: 50%;
  width: fit-content;
  height: 22px;
  display: flex;
  align-items: center;
  align-content: center;
  justify-content: center;
}
/* FIN ETIQUETA EN ENCARGO */

/* ============================================================================
   ASUNTO.TPL — CABECERA E INFO (rediseño "divulgación progresiva")
   ----------------------------------------------------------------------------
   Piezas nuevas para el rediseño de smarty/templates/asunto.tpl (cabecera) y
   modules/asunto.info.tpl (ficha de datos). Sustituyen a .label-header-sup /
   .info.no-editable / los badges sueltos SOLO en las zonas rediseñadas; el
   resto de la app sigue usando los patrones legacy hasta que se migren.
   ============================================================================ */

/* ——— Desbordamiento de valores dentro de .sl-fcell (filtros-grid.css) ————
   .span-u-etiq / .span-usu-fecha-etiq (etiqueta de usuario y "usuario+fecha")
   llevan white-space:nowrap global (style.css) pensado para listados anchos.
   Dentro de una celda .sl-fcell de ancho fijo (avatar+nombre largo, o
   avatar+nombre+fecha en "Creado por") ese nowrap se salía de la celda en
   vez de partir línea. Se permite el wrap SOLO dentro de .sl-fcell. */
.sl-filtros-grid .sl-fcell { overflow: visible; }
.sl-filtros-grid .sl-fcell .span-u-etiq,
.sl-filtros-grid .sl-fcell .span-usu-fecha-etiq {
  /*white-space: normal !important;*/
  display: inline-flex; align-items: center; flex-wrap: wrap; /*gap: .2rem;*/
  justify-content: center; max-width: 100%;
}
.sl-filtros-grid .sl-fcell .sl-meta-value { max-width: 100%; overflow-wrap: break-word; }

/* ——— Modificador columna: avatar (NxN) encima del nombre ——————————————————
   modules/usuario.etiqueta.tpl añade esta clase cuando se usa el parámetro
   force_width_img_user=N (ancho/alto en px del avatar), para celdas
   .sl-fcell donde interesa un layout vertical (avatar grande + nombre
   debajo) en vez de la fila avatar+nombre por defecto (.span-u-etiq
   de arriba). */
.span-u-etiq--column,
.sl-filtros-grid .sl-fcell .span-u-etiq.span-u-etiq--column {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .35rem;
  white-space: normal;
  text-align: center;
}

/* Modificadores de .sl-meta-value para el estado semántico del DATO (no de
   la acción): valor de alerta (ej. "NADIE" asignado) / valor vacío-placeholder. */
.sl-meta-value--warn  { color: var(--sl-state-urgent); }
.sl-meta-value--muted { color: var(--sl-fg-3); font-weight: 500; font-style: italic; }

/* ——— Checklist de estado (Sí/No en línea) ————————————————————————————————
   Sustituye a los 7 bloques sueltos "Contactado/Visitado/D.Captados/
   Presu. preparado/revisado/enviado/Venta" del flujo comercial
   (asunto.info.tpl) por una fila compacta de chips — misma información,
   una sola línea de lectura en vez de 7 cajas con label flotante propio. */
.sl-check {
  display: inline-flex; align-items: center; gap: .3rem;
  font-size: .6875rem; font-weight: 600; line-height: 1;
  padding: .3rem .6rem; border-radius: var(--sl-radius-pill);
  border: 1px solid var(--sl-border); background: #fff; color: var(--sl-fg-3);
  white-space: nowrap;
}
.sl-check::before { font-weight: 800; }
.sl-check--yes { background: var(--sl-blue-050); border-color: var(--sl-blue-100); color: var(--sl-blue); }
.sl-check--yes::before { content: "✓"; }
.sl-check--no::before { content: "–"; color: var(--sl-fg-3); }
/* Tercer estado del checklist: el dato falta Y eso es un problema — no es lo mismo "no esta"
   que "no esta y deberia estar". Nace para la columna "Parte" del listado de llamadas, donde
   una llamada YA acabada sin parte de trabajo es un aviso, mientras que una llamada aun
   abierta sin parte es simplemente algo pendiente (--no). */
.sl-check--warn { background: var(--sl-pink-050); border-color: var(--sl-state-urgent); color: var(--sl-state-urgent); }
.sl-check--warn::before { content: "!"; }

/* ——— Pipeline comercial: barra de 7 segmentos ————————————————————————————
   La MISMA barra que pinta la app (crmline, _FunnelHeroCard en
   lib/views/asunto/asunto_tab_general.dart): 7 segmentos de posición fija
   donde la POSICIÓN identifica el paso y el COLOR dice su estado.

   Sustituye a las 7 columnas "Contactado/Visitado/Captados/Preparado/
   Revisado/Enviado/Venta" del listado /comerciales, que gastaban 554px de
   cabecera para pintar 7 iconos de 20px: el 64% de los 860px que se salían
   de la pantalla a 1600px de ventana.

   NO lleva letras a propósito. Un código de iniciales (C V D P R E) obliga
   a aprenderse una leyenda, y además "Visitado" y "Venta" chocarían en la
   misma inicial. La forma de la barra se lee de un golpe y el nombre de
   cada paso vive en el tooltip (components/pipeline.tpl).

   Todo en rem para que escale con up_ui_scale: quien tiene la escala
   "mayor" es justo quien peor tenía el desbordamiento (1177px). */
/* min-width 5rem = 80px en escala normal para 7 segmentos (~9px cada uno más el
   hueco), que es lo mínimo en lo que la forma de la barra sigue leyéndose de un
   vistazo. Estuvo en 7rem y se bajó midiendo: esos 2rem valían 44px de
   desbordamiento en escala "mayor" y no aportaban legibilidad. Al ir en rem,
   sigue creciendo con up_ui_scale. */
.sl-pipeline { display: flex; gap: .15rem; align-items: center; min-width: 5rem; }
/* Resets de <button> incluidos aquí, en la regla BASE, para que sirvan igual a un <span>
   (no-op, no tienen esas propiedades por defecto) y a un <button> (.sl-pipeline--click,
   más abajo): sin esto un botón real trae borde, relleno y tipografía de la UA por encima
   de lo que pinta esta clase. */
.sl-pipeline__seg {
  flex: 1 1 0; height: .45rem; border-radius: var(--sl-radius-pill);
  background: var(--sl-border);
  border: 0; margin: 0; padding: 0; font: inherit; color: inherit;
  -webkit-appearance: none; appearance: none;
}
/* Azul lo conseguido; rosa el paso SIGUIENTE AL ÚLTIMO AZUL, que es el que
   toca ahora. Rosa y no verde por dos motivos: es el idioma de la app, y en
   este sistema el verde ya significa "cerrado/ok", que no es lo que dice el
   rosa.

   La barra se lee de izquierda a derecha: azul hasta donde has llegado, rosa
   lo que viene después. Los grises ANTERIORES al último azul son pasos que se
   saltaron —historia, no deuda— y por eso el rosa nunca señala hacia atrás.
   Sin rosa = vendido: después de "Venta" no hay paso siguiente.

   ⚠️ NO es "la casilla nº de hechos", como hace hoy la app (crmline). Allí el
   rosa desaparece en el 55,4% de los asuntos (3.076 de 5.551): los 7 campos
   son casillas independientes y no un embudo, así que en cuanto se salta un
   paso la casilla nº-de-hechos ya está marcada, gana el azul y el rosa no
   llega a pintarse. La regla vive en components/pipeline.tpl. */
.sl-pipeline__seg--ok  { background: var(--sl-blue); }
.sl-pipeline__seg--now { background: var(--sl-pink); }
/* ——— Variante con inicial dentro de cada segmento ——————————————————————————
   Se activa pasando $pipe_letras=true al componente; sin ese parámetro la barra
   sigue siendo la de líneas finas, que es la que usan los sitios con menos sitio.

   El segmento deja de ser una barra fina y pasa a ser una celda con letra:
   necesita alto y ~1,15rem de ancho mínimo. Medido en /comerciales: la barra
   pasa de 98px a 155px y lo paga la columna del título, que es la elástica
   (229 → 173px), lo que a su vez alarga la tabla ~310px. En escala normal cabe;
   en "grande" se salen 11px y en "mayor" 77px. Es una compra consciente: a
   cambio se sabe QUÉ paso es cada uno sin pasar el ratón.

   Los pendientes van en caja CLARA con borde y texto gris, no en gris relleno:
   sobre var(--sl-border) (#babcbf) ni el blanco ni el gris de texto dan
   contraste suficiente para un glifo de 10px.

   Se lee como UN control y no como 7 cajitas sueltas, siguiendo el mismo patrón que
   .sl-segmented (el grupo "Todos / Rpte. asignado" y la barra de estado del encargo):
   sin hueco entre celdas, radio solo en los dos extremos, borde COMPARTIDO con la
   vecina vía margin-left:-1px, y el z-index para que el borde de color no lo tape el
   gris de al lado. Que sea un solo objeto es además lo honesto: los 7 pasos son un
   recorrido, no siete datos independientes que casualmente van seguidos. */
.sl-pipeline--letras { gap: 0; }
/* NO ES PULSABLE en su forma de solo lectura, aunque tenga la forma de un
   .sl-segmented — que en el resto de la app SÍ lo es (los filtros "Todos / Rpte.
   asignado", la barra de estado). Tomada la forma prestada, hay que desmentir la
   promesa: cursor "help" (correcto además porque lo que hay al pasar por encima
   es el tooltip de ESE paso, uno por segmento desde 2026-09-16) y ningún efecto
   de hover — no hay ninguna regla ":hover" para esta variante, así que pasar el
   ratón no cambia nada salvo sacar el tooltip.
   ⚠️ El "pointer-events:none" que llevaba este comentario se QUITÓ el mismo día:
   con el tooltip antes en el CONTENEDOR daba igual —el contenedor seguía
   recibiendo el hover—, pero al pasar a un tooltip POR SEGMENTO, "pointer-events:
   none" en el propio <span> le impedía recibir el 'mouseenter' que dispara su
   tooltip: en modo de solo lectura, ningún paso enseñaba nada al pasar el ratón.
   Sigue sin ser pulsable (es un <span>, sin onclick) — lo único que cambia es que
   ahora SÍ recibe eventos de ratón, que es lo que el tooltip necesita. Ver
   .sl-pipeline--click más abajo para la densidad que además de tooltip, guarda. */
/* TOPE DE ANCHO. Los segmentos son "flex:1 1 0", así que la barra llena lo que le
   den: perfecto en una celda de tabla (~139px), absurdo en la ficha del asunto,
   donde el grupo de campos es a todo lo ancho y salían celdas de 87px con una
   letra bailando en medio. Con el tope, la barra se comporta igual en los dos
   sitios y no hace falta una variante por pantalla. */
.sl-pipeline--letras { cursor: help; max-width: 16rem; }
.sl-pipeline--letras .sl-pipeline__seg { transform: none !important; }
.sl-pipeline--letras .sl-pipeline__seg {
  height: auto; min-width: 1.15rem; padding: .1rem 0;
  border-radius: 0;
  font-size: .625rem; font-weight: 700; line-height: 1.45;
  text-align: center; letter-spacing: 0;
  background: var(--sl-bg-soft); border: 1px solid var(--sl-border); color: var(--sl-fg-3);
}
.sl-pipeline--letras .sl-pipeline__seg + .sl-pipeline__seg { margin-left: -1px; }
.sl-pipeline--letras .sl-pipeline__seg:first-child {
  border-top-left-radius: var(--sl-radius-pill); border-bottom-left-radius: var(--sl-radius-pill);
}
.sl-pipeline--letras .sl-pipeline__seg:last-child {
  border-top-right-radius: var(--sl-radius-pill); border-bottom-right-radius: var(--sl-radius-pill);
}
/* Los de color se ponen por encima del gris del vecino. El rosa por encima del azul
   porque siempre se tocan —el rosa es el paso siguiente al último azul— y el borde que
   debe quedar limpio es el del paso que toca ahora. */
.sl-pipeline--letras .sl-pipeline__seg--ok  { background: var(--sl-blue); border-color: var(--sl-blue); color: #fff; position: relative; z-index: 1; }
.sl-pipeline--letras .sl-pipeline__seg--now { background: var(--sl-pink); border-color: var(--sl-pink); color: #fff; position: relative; z-index: 2; }

/* ——— Variante con el NOMBRE COMPLETO dentro de cada segmento (.sl-pipeline--texto) ————————
   Misma idea que --letras (control segmentado, sin hueco, radio solo en los extremos, borde
   compartido) pero para una fila PROPIA de la ficha comercial en vez de una columna de tabla:
   por eso no lleva el max-width de --letras (esa barra tiene que caber en ~139px de celda;
   esta ocupa una .sl-ficha-field-group--full a todo lo ancho del panel).
   $pipe_texto GANA sobre $pipe_letras si el llamador pasa los dos (components/pipeline.tpl):
   por eso esta variante no necesita "desmentir" nada de --letras, son excluyentes en el HTML.

   ⚠️ NUNCA envuelve en dos líneas (2026-09-16, reportado con captura). Con "white-space:
   normal" el texto envolvía SOLO al pasar el ratón por un paso largo ("Presupuesto
   preparado/revisado/enviado"): en reposo los 7 cabían de canto, pero cualquier reflow —el
   propio :hover, o simplemente el navegador recalculando tras la carga— lo hacía envolver, el
   segmento crecía de alto y se salía del contorno redondeado de la barra por arriba y por
   abajo. "white-space: nowrap" cierra la puerta de raíz: ya no hay un segundo estado de altura
   que alcanzar.
   Que los 7 QUEPAN sin partir se consigue con dos cosas, en este orden de preferencia:
     1) "flex: 1 1 auto" (no el "flex: 1 1 0" de la regla base): cada segmento pide su ANCHO DE
        CONTENIDO como flex-basis, así que "Venta" no se lleva el mismo hueco que "Presupuesto
        preparado" — reparto proporcional, no a partes iguales.
     2) Si aun así no caben (ventanas ~900-1200px con escala "normal" 18px de base, o cualquier
        ancho con "mayor"), las 3 etiquetas largas llegan YA ABREVIADAS desde el llamador
        ("Presup. preparado/revisado/enviado" en vez de "Presupuesto ..." — components/
        pipeline.tpl acepta 'corto' además de 'txt'): el nombre completo lo sigue diciendo el
        tooltip, así que no se pierde información, solo espacio.
   El tamaño de fuente NO se toca para ganar hueco: la escala accesible (up_ui_scale) puede
   llevar el font-size raíz a 18-22px, y encoger aquí lo rompería justo para quien más la
   necesita. "overflow:hidden" + "text-overflow:ellipsis" quedan como red de seguridad para un
   ancho todavía más extremo, no como estrategia principal — con las abreviaturas no debería
   llegar a usarse en un layout real.
   Comprobado a ~900/1200/1600px de ventana y con font-size raíz normal (18px) y "mayor" (22px,
   data-ui-scale) con Chrome DevTools: los 7 caben en una línea en los cuatro casos. */
.sl-pipeline--texto { gap: 0; }
.sl-pipeline--texto .sl-pipeline__seg {
  flex: 1 1 auto;
  height: 1.7rem; min-width: 0; padding: 0 .3rem;
  border-radius: 0; box-sizing: border-box;
  font-size: .6875rem; font-weight: 600; line-height: 1.7rem;
  text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  background: var(--sl-bg-soft); border: 1px solid var(--sl-border); color: var(--sl-fg-3);
}
.sl-pipeline--texto .sl-pipeline__seg + .sl-pipeline__seg { margin-left: -1px; }
.sl-pipeline--texto .sl-pipeline__seg:first-child {
  border-top-left-radius: var(--sl-radius-pill); border-bottom-left-radius: var(--sl-radius-pill);
}
.sl-pipeline--texto .sl-pipeline__seg:last-child {
  border-top-right-radius: var(--sl-radius-pill); border-bottom-right-radius: var(--sl-radius-pill);
}
.sl-pipeline--texto .sl-pipeline__seg--ok  { background: var(--sl-blue); border-color: var(--sl-blue); color: #fff; position: relative; z-index: 1; }
.sl-pipeline--texto .sl-pipeline__seg--now { background: var(--sl-pink); border-color: var(--sl-pink); color: #fff; position: relative; z-index: 2; }

/* ——— Densidades CLICABLES (.sl-pipeline--click) ——————————————————————————————————————————
   $pipe_click convierte los segmentos en <button>: hay que DESMENTIR el "cursor:help" que
   --letras pone para la barra de solo lectura (misma especificidad, 2 clases combinadas —
   gana por venir DESPUÉS en la hoja) y dar affordance real de clic con cursor "pointer" y un
   hover propio. (El "pointer-events:none" que --letras llevaba antes ya no existe — se quitó
   al mover el tooltip al segmento, ver el aviso junto a esa regla — así que aquí no hay nada
   que desmentir en ese punto.) */
.sl-pipeline--click.sl-pipeline--letras { cursor: default; }
.sl-pipeline--click .sl-pipeline__seg { pointer-events: auto; cursor: pointer; transform: none !important; }
.sl-pipeline--click .sl-pipeline__seg:hover { filter: brightness(.92); }
.sl-pipeline--click .sl-pipeline__seg:focus-visible { outline: none; box-shadow: var(--sl-focus); }

/* Aquí vivió .sl-pipeline-ends, los rótulos "Contact. … Venta" bajo la cabecera
   de la columna. Orientaban una barra de líneas anónimas; con la inicial dentro de
   cada celda cada paso se identifica solo, así que la leyenda sobraba y su ancho
   hacía falta. Si algún día se usa la barra SIN letras en una cabecera, es aquí
   donde volver a mirar. */

/* ——— Disclosure / sección plegable ("Más detalles", "Ver más campos") ———
   Progressive disclosure genérico y reutilizable. El JS SOLO alterna
   aria-expanded en el trigger y data-open en el panel: toda la animación
   (altura + rotación del chevron) vive aquí, cero JS de estilos.
   .sl-disclosure__badge avisa de contenido importante (alertas de cliente,
   reclamaciones pendientes...) aunque el panel esté colapsado, para no
   esconder por diseño un estado que requiere atención. */
.sl-disclosure__trigger {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .6875rem;
  font-weight: 700;
  color: var(--sl-blue);
  background: none;
  border: 1px solid var(--sl-border);
  border-top: 0;
  border-left: 0;
  border-bottom: 0;
  padding: .3rem .75rem;
  cursor: pointer;
  user-select: none;
  transition: background .15s, border-color .15s;
}
/*.sl-disclosure__body {
  border-top: 1px solid var(--sl-border);
}*/
.sl-disclosure__trigger:hover { background: var(--sl-blue-100); }
.sl-disclosure__trigger:focus { outline: none; box-shadow: var(--sl-focus); }
/* ⚠️ El chevron ya NO LO PINTA NADIE. Se quitó de la ficha de asunto y del encargo, y después
   también de la vista reducida del cliente (modules/asunto_reducido.*), a petición del usuario
   el 2026-09-14: la cabecera entera es pulsable y cada panel lleva su icono, así que la flecha
   sobraba. Las dos reglas se conservan a propósito —son la primitiva del sistema de diseño y
   dos líneas— por si vuelve a hacer falta en otro disclosure; quien las borre, que compruebe
   antes con un grep que sigue sin usarlas nadie. */
.sl-disclosure__chevron { display: inline-flex; transition: transform .15s; }
.sl-disclosure__trigger[aria-expanded="true"] .sl-disclosure__chevron { transform: rotate(180deg); }
/* Toda la cabecera abre y cierra (el handler está en modules/js/common.tpl.js), así que tiene
   que parecerlo. Con :has() para no marcar como pulsables las cabeceras que NO son plegables,
   como la barra de herramientas del bloque de encargos. */
.sl-panel__header--row:has(> .sl-disclosure__trigger) { cursor: pointer; }
.sl-panel__header--row:has(> .sl-disclosure__trigger):hover { background: var(--sl-blue-100); }
/* El trigger ya no necesita su propio hover: lo pinta la cabecera entera, y los dos a la vez
   dejaban un rectángulo más oscuro sobre el título. */
.sl-panel__header--row > .sl-disclosure__trigger:hover { background: none; }
/* Resumen en la cabecera de un panel plegable: una pista de lo que hay dentro, para no tener
   que abrirlo solo para descubrir que está vacío. Se ve SOLO PLEGADO — desplegado sería ruido,
   porque el mismo dato queda justo debajo.
   Cuelga del mismo [aria-expanded] que ya rota el chevron, así que no necesita NI UNA línea de
   JS propia: sl_disclosure_toggle_aria() (modules/js/common.tpl.js) lo mantiene al día en cada
   click, y el estado inicial lo pinta ya el servidor según la preferencia del usuario.
   ⚠️ min-width:0 no es cosmético. El trigger es un flex container y, por defecto, un hijo flex
   no encoge por debajo del tamaño de su contenido: sin esto, un nombre de cliente largo empuja
   al chevron fuera y, en la cabecera de Seguimiento —que comparte fila con el botón
   "Reclamar"—, lo saca del panel. Con min-width:0 el ellipsis puede hacer su trabajo. */
.sl-disclosure__summary {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--sl-grey);
  font-size: 13px;
}
.sl-disclosure__trigger[aria-expanded="true"] .sl-disclosure__summary { display: none; }
/* "Sin notas", "Sin resumen": está vacío y no hay nada que abrir. */
.sl-disclosure__summary--empty { font-style: italic; }
/* Mismo color que .sl-meta-value--warn, que es lo que ya colorea el dato dentro del panel:
   un cliente SIN/BJA/001 se sigue viendo en ámbar aunque "Cliente" esté plegado. */
.sl-disclosure__summary--warn { color: var(--sl-state-urgent); }
.sl-disclosure__badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.125rem; height: 1.125rem; padding: 0 .3rem;
  background: var(--sl-pink); color: #fff; font-size: .625rem; font-weight: 800;
  border-radius: var(--sl-radius-pill); line-height: 1;
}
.sl-disclosure__panel { overflow: hidden; max-height: 0; transition: max-height .2s ease; }
.sl-disclosure__panel[data-open="true"] { max-height: 60rem; }
.sl-disclosure__panel-inner { padding-top: .75rem; }

/* ——— Etiqueta de departamento (icon tag) ————————————————————————————————
   Sustituye a .etiqueta/.etiqueta-content (position:absolute, apiladas a
   +35px unas de otras, fuera del flujo normal) por chips en línea dentro
   del flujo del documento. El color sigue viniendo inline por etiqueta
   (--sl-icon-tag-color), igual que hoy viene el background inline. */
.sl-icon-tag {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.5rem; height: 1.5rem; border-radius: var(--sl-radius-sm);
  background: var(--sl-icon-tag-color, var(--sl-blue)); color: #fff; font-size: .75rem;
  flex-shrink: 0;
}

/* ——— Menú desplegable de la cabecera ————————————————————————————————————— */
.sl-menu {
  right: 0 !important;
  left: auto;
  opacity: 1;
}
/* Aquí estaba .sl-fav-wrap, el envoltorio que recortaba el sprite de "favorito" del ASUNTO
   (heart.png, 28 fotogramas animados con background-position) para que cupiese dentro de un
   <li> del menú "más". Se ha ido con él: desde 2026-09-10 el favorito del asunto es un botón
   más de la fila de acciones y usa el mismo corazón de Font Awesome que el del encargo
   (.sl-btn--fav, justo debajo). Ya no queda ningún usuario del sprite en las plantillas. */
/* Botón de "favorito" con icono: corazón outline si no lo es, relleno si sí, y en los dos casos
   en rosa de marca. Solo el ICONO va de color — el botón conserva el fondo y el borde de
   cualquier .sl-btn--icon, como sus vecinos de la fila de acciones. */
/* ⚠️ Vale para los DOS favoritos, el del encargo y el del asunto, y por eso apunta a
   ".sl-btn--fav i" y no a un id concreto. El <i> conserva su id —"encargo_favorito" o
   "asunto_favorito"— porque es el contrato con encargo_favorito()/asunto_favorito() en el JS,
   y esos ids arrastran css/style.css:8445 y :8459: `width:100px; height:100px;
   position:absolute; background:url(heart.png); animation: fave-heart 1s steps(28)`, todo
   del sprite anterior. Sin deshacerlo, el icono salía dentro de una caja de 100x100 tapada
   por la imagen del sprite — el botón se veía vacío. Comprobado en vivo: box [100,100].
   Hace falta el #sl-app para ganarle al id (1,0,0) sin recurrir a !important. */
/* Celda de rejilla cuyo contenido son BOTONES (la de "Acciones" de "Estado y acciones"):
   una sola fila, con el mismo hueco entre botones que el resto de la ficha.
   El :has(> .sl-btn) acota la regla a las celdas que de verdad llevan una botonera —
   .form-data-value es genérica y la usa media ficha para texto.
   Aquí hubo un "float: none" para desactivar el .pull-right con el que
   modules/asunto.encargo.botones.tpl agrupaba "Subir Docs./Subir fotos". Se ha quitado por
   dos motivos: el grupo ya no existe (los botones son hijos directos), y aquella regla NO
   podía ganar de todos modos — Bootstrap declara ".pull-right{float:right!important}", así
   que el float seguía computando "right"; solo pasaba desapercibido porque dentro de un
   contenedor flex el float se ignora para el reparto. */
#sl-app .sl-panel .form-data-value:has(> .sl-btn) {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .3125rem;
}
/* Un contador sin número y un hueco de botón sin botón siguen siendo FLEX ITEMS aunque no
   pinten nada, y cada uno se come su `gap`. Medido en la celda "Acciones" de un encargo:
   20px entre "Subir Docs." y "Subir fotos" —tres huecos en vez de uno— más 14px muertos al
   final de la fila. display:none sí los saca del reparto.
   No se pueden omitir en la plantilla: Asunto_Model los rellena POR ID vía update_elements
   tras cada subida o borrado (asunto_model.php:2340), así que tienen que existir de entrada.
   Y por eso modules/asunto.encargo.botones.tpl los emite en UNA sola línea: con un salto de
   línea dentro dejan de casar con :empty donde aún se interpreta al pie de la letra.
   ⚠️ El :not() no es decorativo: .span_texto_vacio (css/style.css:8086) es otro <span> vacío
   del MISMO partial, pero con "padding:10px !important" — ahí el hueco es el contenido. */
#sl-app .sl-panel .form-data-value > sup:empty,
#sl-app .sl-panel .form-data-value > span:empty:not(.span_texto_vacio) {
  display: none;
}
#sl-app .sl-btn--fav i {
  position: static;
  width: auto;
  height: auto;
  top: auto; right: auto; left: auto;
  background: none;
  animation: none;
  color: var(--sl-pink);
}

/* Botón "visible para el cliente" del encargo (el ojo): en rosa de marca cuando está
   encendido (.is-on, fa-eye), color por defecto del botón cuando está apagado
   (fa-eye-slash). encargo_visible_cliente() en asunto.tpl.js conmuta la clase .is-on
   al vuelo, sin esperar a la respuesta AJAX ni recargar la página. */
#sl-app .sl-btn--eye.is-on i {
  color: var(--sl-pink);
}

/* ============================================================================
   FIN ASUNTO.TPL — CABECERA E INFO
   ============================================================================ */

/* ============================================================================
   ASUNTO.ENCARGO.PANEL.INFO.TPL — panel de encargo (rediseño en línea con la
   cabecera/ficha del asunto: mismas cajas .sl-panel, mismo .sl-filtros-grid).
   ============================================================================ */

/* ——— Estado del encargo: de grupo de botones "pegados" a chips sueltos ———
   #eebar es un .btn-group de Bootstrap (radios como botones, sin tocar su
   lógica/JS). La capa de compatibilidad de #sl-app fuerza el look "unido"
   típico de btn-group (radio 0 en los botones interiores); aquí lo anulamos
   solo dentro de #eebar para que cada estado sea una píldora independiente. */
#sl-app #eebar.btn-group { display: flex; flex-wrap: wrap; gap: .35rem; }
#sl-app #eebar.btn-group > .btn {
  border-radius: var(--sl-radius-pill) !important;
  border: 1px solid var(--sl-border-2);
  background: #fff; color: var(--sl-fg-3); font-weight: 700;
}
#sl-app #eebar.btn-group > .btn.active {
  background: var(--sl-blue); border-color: var(--sl-blue); color: #fff;
}

/* ============================================================================
   FIN ASUNTO.ENCARGO.PANEL.INFO.TPL
   ============================================================================ */

/* ============================================================================
   EDICIÓN INLINE POR CAMPO (lápiz) — sustituye a los diálogos de "Editar
   asunto"/"Editar encargo" campo a campo. El JS (inline_edit_*) solo hace
   show/hide de .sl-inline-edit__display / .sl-inline-edit__input; el
   guardado real es un POST mínimo (solo el campo tocado) al mismo endpoint
   que ya usan los selects/checkboxes (asunto/autosave/<id>/<tipo>).
   Cubre inputs de texto/fecha/número, <select> simples (dpto, tipo
   facturación, representante) y <select multiple> (Departamentos y Rptes.
   asignados del asunto, que son muchos-a-muchos).
   ============================================================================ */
.sl-inline-edit { display: inline-flex; align-items: center; gap: .35rem; flex-wrap: wrap; }
.sl-inline-edit__pencil {
  font-size: .625rem; color: var(--sl-fg-3); cursor: pointer;
  opacity: .5; transition: opacity .15s, color .15s;
}
.sl-fcell:hover .sl-inline-edit__pencil { opacity: 1; }
.sl-inline-edit__pencil:hover { color: var(--sl-blue); }

/* El valor editable se pinta en azul (como un link) para que se note de un
   vistazo qué se puede tocar sin pasar por el diálogo grande; el estado
   vacío/"—" se queda en el gris apagado de siempre, no en azul. */
.sl-inline-edit__display { color: var(--sl-blue); font-weight: 600; cursor: pointer; }
.sl-inline-edit__display.sl-meta-value--muted,
.sl-inline-edit__display.sl-meta-value--warn { color: inherit; font-weight: inherit; }

.sl-inline-edit__input {
  height: 1.5rem !important; padding: 0 .35rem !important; font-size: .75rem !important;
  max-width: 8rem;
}
select.sl-inline-edit__input { max-width: 11rem; }
select.sl-inline-edit__input[multiple] {
  height: auto !important; min-height: 4.5rem; padding: .2rem !important; max-width: 14rem;
}

/* El wrapper que envuelve un <select class="select2"> necesita alto automático: select2
   dibuja su propio contenedor visual al lado del <select> nativo, y la regla de arriba
   (1.5rem fijo) lo recorta.
   Lo estrenó el Representante asignado del encargo, que desde el 2026-09-14 ya no usa select2
   —su <select> no se enseña nunca, así que no necesitaba adornarlo—. Se conserva por si vuelve
   a hacer falta en otro campo: es una regla condicionada a :has(), no cuesta nada donde no
   aplica. */
.sl-inline-edit__input:has(select.select2) { height: auto !important; padding: 0 !important; }

/* "Cambio Rápido de Representante". Desde el 2026-09-14 la lista de miembros del dpto. NO
   es una caja de botones sueltos que se enseña y se esconde, sino el <ul> de un
   components/dropdown.tpl, así que su aspecto lo pinta .sl-menu / .sl-menu__link y aquí no
   queda nada que decir.
   La clase sigue viva y NO se puede borrar: es el gancho por el que inline_dpto_changed()
   (modules/js/asunto.tpl.js) encuentra el menú para reconstruirlo cuando cambia el
   Departamento del encargo. */

/* ============================================================================
   FIN EDICIÓN INLINE POR CAMPO
   ============================================================================ */

.usuarioEtiquetaImg {
  border-radius:50%;
  object-fit:cover;
}
.usuarioEtiquetaSpan {
  font-size: .6875rem;
}

/* Avatar con inicial (modules/usuario.etiqueta.tpl): sustituye a img/user_empty.png cuando el
   usuario no tiene foto subida. Va junto a .usuarioEtiquetaImg (mismo border-radius:50% que la
   foto real) — solo añade el centrado del texto; el tamaño, borde y color de fondo se calculan
   en la plantilla porque dependen del usuario (color_user_id) y del tamaño pedido (force_width_img_user / force_mini_user_img). */
.usuarioEtiquetaInicial {
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 700; line-height: 1; user-select: none;
}
.form-control {
  padding: 6px;
}

.select2-container--open .select2-dropdown {
  top: -7px;
}
.select2-dropdown {
  border: 1px solid var(--sl-border);
}
.select2-container--default .select2-results__option--highlighted[aria-selected] {
  background-color: var(--sl-blue);
  color: #fff;
}
.sl-select2-filtro-dropdown .select2-results__option {
  font-family: inherit;
  font-weight: 500;
  font-size: 13px;
  line-height: 16px;
  color: var(--sl-blue)
}
.select2-results,
.select2-container--default .select2-results>.select2-results__options {
  border-bottom-left-radius: var(--sl-radius-card);
  border-bottom-right-radius: var(--sl-radius-card);
}
.select2-container--default .select2-results__option--highlighted span > span:first-child {
  background: #ffffff73;
  border-radius: 3px;
}
.select2-container--default .select2-results__option--highlighted i {
  color: #fff !important;
}
/*.mega-design #sl-app .sl-fixed-top {
  background: transparent;
}*/
.sl-flex-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .25rem;
}
.sl-cell-row {
  display: flex;
  align-items: center;
  gap: .25rem;
}
.relative {
  position: relative !important;
}
#list-table input[type=checkbox] {
  margin: 0;
  position: relative;
  vertical-align: middle;
}
/* El ID del asunto NO es clicable: se pulsa el badge (components/id-badge.tpl) o el boton
   de show_more(). Este !important existe para anular el "cursor: pointer" que los <style>
   de los listados declaran sobre esta misma celda — no lo quites pensando que sobra.
   2026-09-15: el selector estaba escrito DOS veces ("sel, sel"), colapsado a una. */
table.table.webapp tr td#data-a-id {
  cursor: initial !important;
}
div.modal-dialog div.modal-body {
  max-height: 100% !important;
}
.g-20 {
  gap: 20px;
}
.form-data-value {
  font-size: 14px;
  color: var(--sl-fg-1);
  font-weight: 500;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.color-pink {
  color: var(--sl-pink);
}
.color-grey {
  color: var(--sl-grey);
}
.color-blue {
  color: var(--sl-blue);
}
/* Nombre de cliente en pill, igual que en el listado de asuntos (asuntos.tpl, "Nombre de cliente
   en pill, como la de Ref.") — a petición del usuario 2026-09-08. Mismo método PHP compartido
   get_cliente_logo_html_td() (NO se toca: lo usan fichas de cliente/asunto/llamada/encargo con un
   <label> distinto según controller/method activos) y mismas declaraciones de
   ".sl-generic-pill.sl-generic-pill--tag" (css/filtros-grid.css) ya replicadas allí sobre ese
   <label> tal cual lo deja el método — aquí escopadas a "#asunto-info-cliente" en vez de
   "#list-table".

   .form-data-value pasa a fila flex (solo en esta celda) con DOS zonas — .client-info (botón "i",
   pill de ID y nombre) y .client-big-logo (el logo del cliente, grande y decorativo) — separadas
   a los extremos con justify-content:space-between, a petición del usuario 2026-09-15. Antes el
   logo salía pequeño dentro de la misma fila que el nombre (.flex_clientes_logos con
   flex-direction:column de css/style.css: imagen encima, <label> debajo); ahora ese <img> se
   oculta ahí (ver ".client-info .flex_clientes_logos img" más abajo) porque .client-big-logo pinta
   el mismo logo aparte, con una SEGUNDA llamada a get_cliente_logo_html_td() con $solo_logo=true
   (ver asunto.info.tpl) — así no hay que tocar el método compartido ni duplicar su lógica de
   fallback (cl_logo vs id_cliente.png). */
#asunto-info-cliente .form-data-value,
.form-data-value-inline-flex {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: .5rem;
}
#asunto-info-cliente .client-info {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
#asunto-info-cliente .client-info .flex_clientes_logos img {
  display: none;
}
/* Logo grande decorativo — a petición del usuario 2026-09-15. La caja mide MENOS que la imagen ya
   escalada (overflow:hidden), a propósito: el logo se ve grande y "cortado" por el borde de la
   fila en vez de flotar completo por encima del resto del contenido. Sin rotación ni cambio al
   pasar el ratón (segunda petición del usuario, revirtiendo el primer intento con
   ".sl-resumen-actividad__alert-bg" como referencia). flex-shrink:0 para que el nombre largo del
   cliente (que sí puede recortarse, ver ellipsis más abajo) ceda espacio antes que el logo se
   comprima. pointer-events:none porque es puramente decorativo: sin él, un <img> escalado
   invadiría visualmente el área de otros controles sin ser realmente clicable en ellos. */
#asunto-info-cliente .client-big-logo {
  flex-shrink: 0;
  pointer-events: none;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: end;
  object-fit: cover;
}

#asunto-info-cliente .flex_clientes_logos label,
#asunto-info-cliente .clientes_logos:not(.flex_clientes_logos) {
  display: inline-block;
  vertical-align: middle;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: .6875rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--sl-fg-2);
  background: color-mix(in srgb, var(--sl-fg-2) 12%, transparent);
  border: 1px solid var(--sl-border);
  border-radius: var(--sl-radius-pill);
  padding: .1875rem .4rem;
  margin: .25rem 0 0;
}
/* El margin-top de arriba compensaba la imagen que iba encima en .flex_clientes_logos
   (flex-direction:column). Con esa imagen oculta dentro de .client-info (ver más arriba), el
   <label> queda solo en la columna y el hueco de arriba desalinea la fila — se anula aquí. */
#asunto-info-cliente .client-info .flex_clientes_logos label {
  margin-top: 0;
}
.sl-panel .sl-ficha-field-group,
.sl-panel .sl-ficha-field-group-row {
  gap: .25rem;
  flex: 1;
  /* min-width:0 vence el min-width:auto por defecto de un flex item: SIN esto, un item de
     flex nunca encoge por debajo del ancho intrínseco de su contenido, así que aunque
     .form-data-value ya sepa partir palabras largas (overflow-wrap), este contenedor
     seguiría negándose a estrecharse para dejarle sitio — el texto se saldría igual del
     panel en vez de bajar de línea. Ver el mismo motivo en .sl-meta-block (softline-ui.css
     §6a) — a petición del usuario 2026-09-01. */
  min-width: 0;
  padding: var(--sl-space-2);
}
.sl-panel .sl-ficha-field-group-row {
  align-items: center;
}
.sl-panel .sl-ficha-field-group {
  border-right: 1px solid var(--sl-border-3);
}
.sl-panel .sl-ficha-field-group:last-child {
  border-right: none;
}
/* Celda que ocupa el doble que sus hermanas. Necesaria para la ficha de asunto, donde el diseño
   pide filas de 4 columnas en las que una celda vale por dos (Departamentos + Rptes. asignados
   parten la fila por la mitad; Proyecto ocupa media fila junto a las dos de horas). Como el
   reparto es flex:1, "el doble" es literalmente flex:2 — no hace falta una rejilla aparte ni
   clases de "span". */
.sl-panel .sl-ficha-field-group--wide {
  flex: 2;
}
/* Celda a ancho completo de la fila: para una fila con UNA sola celda, que con el motor flex de
   esta regla general llenaba la fila "gratis" por ser la única con flex:1. Bajo ".sl-panel--grid3"
   (ver más abajo) esa misma celda solo vale 1 de 3 pistas y se queda encogida a la izquierda, así
   que necesita este modificador explícito. Es la trampa que se llevó por delante las tres notas
   del asunto y el Resumen al migrar a la rejilla (2026-09-11). El flex:4 se conserva para los
   paneles que siguen con el motor flex, como modules/dialog/dialog.ficha.tpl. */
.sl-panel .sl-ficha-field-group--full {
  flex: 4;
}
/* Celda MUDA: reserva una pista de la rejilla y dibuja sus divisorias, pero sin rótulo ni valor.
   Desde el 2026-09-15 es SOLO el relleno de fin de fila: una fila de 2 campos necesita una tercera
   celda para que sus divisorias cuadren con las filas de arriba, y ahí no hay ningún campo detrás
   que enseñar. Los huecos que SÍ tienen un campo detrás ya no usan esta clase: usan --muted.
   No necesita ni alto ni fondo propios: hereda el padding y los bordes de .sl-ficha-field-group, y
   la rejilla ya estira todas las pistas de una fila a la misma altura. Lo único que sí necesita es
   no comportarse como un campo, de ahí el pointer-events.
   Ver _devel/claude/plan_rejilla_3_pistas_fichas.md. */
.sl-panel .sl-ficha-field-group--empty {
  pointer-events: none;
}
/* Celda ATENUADA: el campo existe, pero aquí no aporta nada — no aplica a este flujo (p.ej.
   "Proyecto" en un asunto comercial) o el usuario no tiene nivel para verlo ("Desviación").
   Se pinta el rótulo y el «—» como en cualquier campo sin dato, pero traslúcidos, para que el
   hueco se lea como "aquí hay un campo" y no como "a la ficha le falta algo" (2026-09-15).
   Antes de esa fecha estos dos casos eran celdas mudas: ver la nota de arriba.

   Solo opacity, a propósito: el marcado es exactamente el del campo vacío normal, así que los
   tres estados de una celda —con dato / vacío / no aplica— se distinguen por un único eje visual
   en vez de por tres colores que habría que aprenderse.

   NO lleva pointer-events:none, al revés que la celda muda: la variante "permiso" cuelga un
   tooltip de esta misma celda y sin eventos de ratón no se abriría nunca.

   ⚠️ La opacidad va en los HIJOS ("> *"), no en la celda, y eso no es un detalle: la
   divisoria vertical de la rejilla la pinta la propia celda con su border-right (ver
   .sl-panel .sl-ficha-field-group, arriba). Con opacity en la celda se atenuaba TAMBIÉN esa
   línea, así que una celda "no aplica" rompía el enrejado: su divisoria salía más clara que
   las de al lado y la fila parecía mal pintada. Atenuando rótulo y valor por separado, el
   campo se lee apagado y el marco sigue intacto (2026-09-15).
   Los dos hijos son exactamente los de cualquier campo — .sl-meta-label y .form-data-value,
   ver components/ficha-field-empty.tpl — así que no hace falta nombrarlos uno a uno. */
.sl-panel .sl-ficha-field-group--muted > * {
  opacity: .40;
}

/* ============================================================================
   ⚠️ ".sl-panel--grid4" YA NO EXISTE (retirada el 2026-09-11). Vivió tres días: nació el
   2026-09-08 para el panel "Seguimiento" del asunto y se retiró al unificar TODAS las fichas en
   una sola rejilla de 3 pistas. Si aparece en algún marcado, es código muerto: no pinta nada y
   la fila se queda repartida con el flex de la regla general.
   El motivo por el que se pasó de flex a rejilla sigue siendo válido, y se explica ahora en el
   bloque de --grid3, justo debajo.
   ============================================================================ */

/* Rejilla de 3 pistas — EL motor de todas las fichas de asunto y encargo desde el 2026-09-11:
   Cliente, Información, Seguimiento, Resumen y Notas del asunto; Estado y acciones, Datos del
   encargo, Notas y Temporizador del encargo; y las dos fichas de la vista reducida de cliente.
   Sale del artboard Encargos.dc.html, que pinta esos bloques como "repeat(3, minmax(0,1fr))" con
   separadores de 1px. Aquí los separadores NO se hacen con gap sobre un fondo de color como en el
   artboard: ya los pone el border-right/border-top por celda de la regla general de arriba, que
   además acierta con la última celda de cada fila.

   POR QUÉ UNA REJILLA Y NO FLEX: con flex:1/flex:2, el ancho real de cada celda depende de CUÁNTAS
   celdas y "gaps" tenga esa fila en concreto, así que dos filas con distinto nº de celdas no
   alinean sus divisorias verticales aunque las proporciones "parezcan" iguales. Con Grid las tres
   pistas son SIEMPRE las mismas, en todas las filas y en todos los paneles.

   Sigue siendo opt-in y NO se sube a .sl-panel: modules/dialog/dialog.ficha.tpl conserva a
   propósito el motor flex de la regla general.

   Una celda que valga por dos lleva --wide; una que ocupe la fila entera, --full — imprescindible
   cuando es hija única de su .sl-panel__body, porque con la rejilla ya no se come la fila "gratis"
   como hacía con flex. Un campo que no se pinta deja una celda --empty que reserva su pista.
   Ver _devel/claude/plan_rejilla_3_pistas_fichas.md. */
.sl-panel--grid3 .sl-panel__body:has(> .sl-ficha-field-group) {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.sl-panel--grid3 .sl-panel__body > .sl-ficha-field-group {
  grid-column: span 1;
}
.sl-panel--grid3 .sl-panel__body > .sl-ficha-field-group--wide {
  grid-column: span 2;
}
.sl-panel--grid3 .sl-panel__body > .sl-ficha-field-group--full {
  grid-column: span 3;
}

.sl-panel--grid4 .sl-panel__body:has(> .sl-ficha-field-group) {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.sl-panel--grid4 .sl-panel__body > .sl-ficha-field-group {
  grid-column: span 1;
}
.sl-panel--grid4 .sl-panel__body > .sl-ficha-field-group--wide {
  grid-column: span 2;
}
.sl-panel--grid4 .sl-panel__body > .sl-ficha-field-group--full {
  grid-column: span 4;
}

/* Fila con un numero de pistas DISTINTO al del panel — modificador de FILA, no de panel.
   La rejilla se declara en la <section> (.sl-panel--gridN) y cada .sl-panel__body la hereda, de
   modo que todas las filas alinean sus divisorias verticales. Eso es lo normal y lo deseable,
   pero "Datos del encargo" del encargo pide desde el 2026-09-21 CUATRO columnas en la fila de
   arriba (Creado por · Tipo facturacion · Departamento · Representante) y CINCO en la de abajo
   (Horas previstas · Fecha prevista · Horas partes · Fact./Desc. · Kanban): son dos grupos de
   campos sin relacion entre si, y forzarles el mismo reparto obligaba a rellenar la fila corta
   con celdas mudas o a dejar un campo huerfano en una tercera fila. Usuario 2026-09-21, con
   captura.
   Se sobrescribe SOLO grid-template-columns: cuantas pistas ocupa cada celda lo sigue diciendo
   el panel (span 1 / --wide / --full), asi que el modificador es aditivo y no duplica reglas.
   Va aqui, detras del bloque de --grid4, PORQUE GANA POR ORDEN: las dos reglas empatan a 0-3-0
   de especificidad (una clase + una clase + el :has() de una clase), asi que moverlo mas arriba
   en el fichero lo dejaria sin efecto y sin dar ningun error. */
.sl-panel .sl-panel__body--cols5:has(> .sl-ficha-field-group) {
  grid-template-columns: repeat(5, minmax(0, 1fr));
}
.sl-panel .sl-panel__body--cols5 > .sl-ficha-field-group--full {
  grid-column: span 5;
}

/* Divisoria HORIZONTAL entre las filas de una rejilla.
   Las verticales las pone el border-right de cada celda (regla general de más arriba), pero las
   horizontales venían "gratis" del border-top que separa dos .sl-panel__body consecutivos: en
   "Seguimiento" del asunto cada fila ES su propio body, así que salían solas. En "Datos del
   encargo" y "Notas" del encargo todas las celdas viven en UN body y la rejilla las reparte en
   varias filas, así que no había ningún border-top entre ellas y los campos quedaban sin
   delimitar — a petición del usuario 2026-09-10.
   La línea va en la CELDA, y por eso hay que quitarle al body la suya: si no, la primera fila
   llevaría las dos y se vería un filo de 2px. Hacerlo con `gap:1px` sobre un fondo de color
   (como el artboard) se descartó: con filas incompletas —la última de "Datos del encargo" tiene
   una sola celda de tres— las pistas vacías pintarían el gris del fondo. */
.sl-panel--grid3 .sl-panel__body > .sl-ficha-field-group {
  border-top: 1px solid var(--sl-border-3);
}
.sl-panel--grid3 .sl-panel__body:has(> .sl-ficha-field-group) {
  border-top: 0;
  /* El `gap: 0` que habia aqui se subio a ".sl-panel__body:has(> .sl-ficha-field-group)" (mas
     abajo) el 2026-09-18: la condicion para no querer hueco no es ser grid3, es estar hecho de
     celdas -y asi lo heredan tambien --grid4 y los dialogos de modules/dialog/ficha/. Alli esta
     la explicacion completa y el porque original (usuario 2026-09-10, con captura). */
}

/* Celda con un control editable a la vista (ver .form-data-ctrl abajo). El hover anuncia que se
   puede pinchar en CUALQUIER punto de la celda para enfocar su control, no solo en el control:
   lo hace el manejador delegado de .sl-ficha-field-group--edit en asunto.tpl.js. */
.sl-panel .sl-ficha-field-group--edit {
  cursor: pointer;
  transition: background .15s ease;
}
.sl-panel .sl-ficha-field-group--edit:hover {
  background: var(--sl-blue-050);
}

/* Hermano editable de .form-data-value: mismo papel (el VALOR del campo) pero como control a la
   vista en vez de texto. dialog.ficha.tpl no lo necesitaba porque esa ficha es de solo lectura.
   Va scopeado a #sl-app para ganar a .form-control de Bootstrap 3 (0,1,0) sin !important — los
   controles conservan .form-control porque lo necesitan el datepicker jsdtp y select2. */
#sl-app .form-data-ctrl {
  width: 100%;
  box-sizing: border-box;
  height: auto;
  padding: 6px 8px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .05em;
  color: var(--sl-fg-1);
  background: var(--sl-bg-card);
  border: 1px solid var(--sl-border-2);
  border-radius: var(--sl-radius-sm);
  box-shadow: none;
  outline: none;
}
#sl-app .form-data-ctrl:focus {
  border-color: var(--sl-blue);
  box-shadow: var(--sl-focus);
}
/* Fecha prevista en rosa cuando tiene valor (Seguimiento) — a petición del usuario 2026-09-08.
   Necesita esta regla más específica y no basta con la clase suelta ".color-pink": el
   "#sl-app .form-data-ctrl { color:... }" de arriba tiene más especificidad (1 ID + 1 clase) que
   ".color-pink" sola (1 clase) y ganaría, dejando el input siempre en el color por defecto. */
#sl-app .form-data-ctrl.color-pink {
  color: var(--sl-pink);
}
#sl-app .form-data-ctrl--narrow { max-width: 13.75rem; }
/* Mismo problema de especificidad que ".form-data-ctrl.color-pink" de arriba, pero para los
   controles que YA NO llevan ".form-data-ctrl" (ver ".sl-ctrl--normal/--mini" más abajo): el
   "#sl-app .form-control { color:... }" de la sección de Inputs (arriba del todo) también gana a
   un ".color-pink" suelto por especificidad. */
#sl-app .form-control.color-pink {
  color: var(--sl-pink);
}
.sl-panel__body {
  display: flex;
  gap:.625rem;
  /* Padding general del body de un panel — a petición del usuario 2026-09-01: hasta ahora era
     "opt-in" caso por caso (una clase extra como ".sl-encargos-list" en dialog.ficha.tpl, o un
     style="padding:..." inline en asunto.encargo.panel.info.tpl), así que la mayoría de usos se
     quedaban sin padding y su contenido tocaba el borde del panel. Ahora es el comportamiento por
     defecto; esas clases/estilos concretos siguen pudiendo sobreescribirlo si necesitan otro valor. */
  padding: var(--sl-space-3);
}
/* Excepción: un body hecho de columnas ".sl-ficha-field-group" (dialog.ficha.tpl) ya reparte su
   propio padding + borde divisorio por columna (regla de arriba). Sumarle también el padding del
   body ensancharía SOLO el margen exterior (primera/última columna, arriba/abajo) sin tocar el
   hueco entre columnas, descuadrando ese diseño de varias columnas. */
.sl-panel__body:has(> .sl-ficha-field-group) {
  padding: 0;
  /* Y sin hueco entre celdas, por el mismo motivo que el padding: la celda ya trae lo suyo.
     El `gap:.625rem` de la regla de arriba viene de cuando .sl-panel__body era SIEMPRE una fila
     flex de elementos sueltos -una etiqueta y su valor, dos tablas-, donde es justo lo que los
     separa y sigue haciendo falta (modules/inventario.info.tpl: 13 de sus 20 bodies son de ese
     tipo). En un body hecho de CELDAS no separa nada que no estuviera ya separado: cada
     .sl-ficha-field-group trae su padding y su border-right, asi que el hueco solo consigue
     despegar esa divisoria de la celda vecina y, cuando la rejilla reparte en varias filas, abrir
     una banda blanca entre fila y fila.
     Esto vivia en ".sl-panel--grid3 ..." desde el 2026-09-10 (reportado con captura), y por eso
     dejaba fuera a los paneles --grid4 -Informacion y Seguimiento del asunto- y a los dialogos de
     modules/dialog/ficha/, que son flex y tambien estan hechos de celdas. La condicion real nunca
     fue "ser grid3" sino "estar hecho de celdas", que es exactamente lo que ya decia este :has()
     para el padding. Usuario 2026-09-18. */
  gap: 0;
}
.sl-panel .sl-panel__body:first-child {
  border-top: none;
}
.sl-panel .sl-panel__body {
  border-top: 1px solid var(--sl-border-3);
}
.flex-colum-start-gap {
  flex-direction: column;
  display: flex;
  align-items: flex-start;
  gap: 0.25rem;
}
/* ============================================================================
   TAB GLIDER — indicador deslizante para las tabs de asunto/ver
   ----------------------------------------------------------------------------
   Técnica inspirada en el "layoutId" de Framer Motion (Maxime Heckel): un
   único elemento absoluto (.sl-tab-glider) se desliza y redimensiona hacia la
   tab activa, en vez de que cada <li> pinte su propio fondo de golpe al
   cambiar. Las <li> de la ul.sl-tabs-glide dejan de aportar fondo propio: lo
   hace el glider, que vive por detrás del texto (z-index) y por delante del
   fondo azul de la cabecera. Posicionado vía JS (ver asunto.tpl.js,
   sl_position_tab_glider) con getBoundingClientRect, para no depender de qué
   ancestro resulte ser el offsetParent real.
   ============================================================================ */
/* display:flex (no solo position:relative): la <ul> de las tabs viene float:left
   (Bootstrap .nav-tabs > li y, en el caso del bloque de encargo, la propia <ul>
   vía ul.header-first-tab). Un wrap que no contenga ese float colapsa a
   height:0 — el glider entonces se posiciona con wrapRect.height=0 (top/height
   calculados en 0, invisible) aunque left/width salgan correctos. Antes se
   arreglaba con `display:flow-root` (contiene el float sin más), pero eso solo
   resuelve la ALTURA MÍNIMA del wrap, no que coincida con la altura VISIBLE de
   la barra de cabecera cuando el wrap está anidado dentro de otro contenedor
   flex más alto (ver más abajo, caso .encargos-tabs): flow-root deja el wrap
   con su altura intrínseca (la del texto de las tabs), más corto que la fila,
   y con flex+align-items:center como layout del padre eso deja el wrap
   "flotando" centrado verticalmente con hueco arriba Y abajo — rompiendo el
   "flush con el borde inferior" que exige el cálculo de sl_position_tab_glider.
   Con display:flex en el propio wrap: 1) el float dentro de él deja de aplicarse
   del todo (los flex items ignoran `float` por spec, ni falta hace clearlo) y
   2) de paso centra verticalmente su contenido (la <ul>), que es justo lo que
   ya hacía "gratis" el caso de las tabs principales del asunto (su wrap ES el
   .panel-heading real, que ya es flex+align-items:center vía softline-ui.css
   más abajo) y lo que le faltaba al caso anidado del encargo. Necesita además
   `height:100%` para poder efectivamente ocupar la altura de un ancestro
   estirado (ver regla `#encargo_abierto` bajo la sección ENCARGO ABIERTO); en
   el caso del asunto (wrap = la .panel-heading real, sin ancestro con altura
   fija) el 100% resuelve a 'auto' y no cambia nada. */
.sl-tabs-glide-wrap { position: relative; display: flex; align-items: center; height: 100%; }

.sl-tabs-glide-wrap > .sl-tab-glider {
  position: absolute;
  top: 25px; left: 0; width: 0; height: 0;
  background: #fff;
  border-radius: var(--sl-radius-sm) var(--sl-radius-sm) 0 0;
  z-index: 1;
  opacity: 0;
  pointer-events: none;
  transition: left .4s cubic-bezier(.34, 1.56, .64, 1),
  width .4s cubic-bezier(.34, 1.56, .64, 1),
  top .4s cubic-bezier(.34, 1.56, .64, 1),
  height .4s cubic-bezier(.34, 1.56, .64, 1),
  opacity .15s ease;
}
.sl-tabs-glide-wrap > .sl-tab-glider.sl-tab-glider--ready { opacity: 1; }
/* Sin transición mientras se coloca de golpe (primera carga / resize) */
.sl-tabs-glide-wrap > .sl-tab-glider.sl-tab-glider--jump { transition: none; }

/* Las <li> de esta ul ya no pintan fondo propio: lo aporta el glider de arriba */
.sl-tabs-glide.nav-tabs > li > a,
.sl-tabs-glide.nav-tabs > li > a:hover,
.sl-tabs-glide.nav-tabs > li > a:focus,
.sl-tabs-glide.nav-tabs > li.active > a,
.sl-tabs-glide.nav-tabs > li.active > a:hover,
.sl-tabs-glide.nav-tabs > li.active > a:focus {
  background-color: transparent;
  border-color: transparent;
  position: relative;
  z-index: 2;
}

/* La <a> debe ocupar TODO el ancho y alto de su <li> (no solo el contenido
   icono+texto): el área pintada por el glider debe coincidir exactamente con
   la zona clicable de la pestaña. mega-design.css fija
   ".panel-heading .nav-tabs > li > a { top:0 !important; height:24px !important }"
   para las <a> de CUALQUIER .panel-heading (ver comentario en asunto.tpl.js,
   sl_position_tab_glider) — para ganarle hace falta igual !important y más
   especificidad (mismo selector + .sl-tabs-glide); softline-ui.css además
   carga el último de los tres (ver head.tpl), así que un empate en
   especificidad también cae de nuestro lado. */
.mega-design #sl-app .panel-heading .sl-tabs-glide.nav-tabs > li > a {
  top: 0 !important;
  width: 100% !important;
  height: 100% !important;
}

/* ============================================================================
   PESTAÑAS (.sl-tabs-glide) — la caja del <li> y del <a>, y sus colores
   ----------------------------------------------------------------------------
   UNA sola definición para las dos barras de pestañas de la ficha:
     · la principal del asunto (Asunto/Gestiones/Reclamaciones/…), sobre fondo
       AZUL OSCURO, y
     · la del encargo abierto (Info/Checklist/Temporizador), sobre fondo
       AZUL CLARO,
   a petición del usuario 2026-09-10: "la misma estructura y diseño, que solo
   cambie el color de fondo, incluso en las animaciones de hover y al pulsarlas".

   Antes cada barra tenía su propio bloque. La del asunto sacaba las medidas de
   mega-design.css vía ".panel-heading .nav-tabs > li [> a]"; la del encargo, de
   una COPIA de esas mismas medidas colgada de ".encargos-tabs" — copia que hubo
   que escribir cuando la fase 2 le quitó la clase "panel-heading" a su cabecera.
   Como era de esperar de dos copias del mismo diseño, divergieron: la del
   encargo se quedó con el "efecto archivador" (papel blanco en un ::before y
   salto de 7px al pasar el ratón) que la del asunto ya no usa desde que existe
   el glider, y con otro color y otro peso de letra. Eso es justo lo que se pedía
   arreglar, así que la copia desaparece.

   El gancho ahora es ".sl-tabs-glide", que es lo que tienen las dos barras (y
   también /inventario), y NO depende de que la cabecera sea un .panel-heading.
   Las MEDIDAS son las de la barra del asunto, leídas en devtools sobre la página
   real, no copiadas a ojo: ul 13px; li 36px de alto, top 5, left 15; a 36px con
   padding 6px 13px 4px y radio 12px 12px 0 0; inactiva en 700 y activa en 600.

   Lo ÚNICO que cambia entre las dos es el color del texto inactivo, porque el
   fondo de la barra es distinto: viaja por --sl-tabs-fg y lo cambia el
   modificador .sl-tabs-glide--on-light. El texto de la pestaña ACTIVA es el
   mismo en las dos, porque se pinta sobre el papel blanco del glider, que sí es
   idéntico.

   Sobre los !important: no son capricho. Las reglas que hay que vencer también
   los llevan — mega-design.css (".panel-heading .nav-tabs > li > a {color:white
   !important}", y el rosa del hover genérico) y style.css (".panel-heading .nav >
   li > a:hover {color:#004d95 !important}"). A igualdad de peso decide la
   especificidad, y a igualdad de especificidad el orden de carga: softline-ui.css
   se carga la última de las tres (layout/head.tpl), así que empatar basta.
   ============================================================================ */
.sl-tabs-glide {
  /* Barra sobre fondo OSCURO (el azul de marca): es el caso por defecto. */
  --sl-tabs-fg: #fff;
  --sl-tabs-fg-active: var(--sl-pink);
}
/* Barra sobre fondo CLARO (--sl-blue-100, la del encargo abierto): el texto
   inactivo tiene que oscurecerse o no se lee. Única diferencia entre las dos. */
.sl-tabs-glide--on-light { --sl-tabs-fg: var(--sl-blue-600); }

/* Los 13px los daba "style.css:4261 .panel-heading .nav {font-size:13px}", que solo alcanza a
   las cabeceras que siguen siendo .panel-heading. Sin esto, la barra del encargo heredaba los
   14,6px del documento y cada pestaña crecía ~8px de ancho. */
.mega-design #sl-app .sl-tabs-glide.nav-tabs {
  font-size: 13px;
  /* Los <li> llevan left:15px, y en la barra del asunto ese desplazamiento lo compensa el
     margin lateral negativo de ".panel-heading .nav {margin:-9px -15px -11px}", de modo que la
     primera pestaña queda a ras del borde izquierdo. La barra del encargo ya no es un
     .panel-heading, así que no recibía esa compensación y arrancaba 15px más adentro que la
     del asunto. Solo se replica el eje horizontal: el vertical ya coincide (lo resuelve el
     align-items:center del wrap) y tocarlo movería el punto desde el que
     sl_position_tab_glider() calcula el "flush" con el borde inferior. */
  margin-left: -15px;
}

.mega-design #sl-app .sl-tabs-glide.nav-tabs > li {
  position: relative;
  height: 36px;
  top: 5px;
  left: 15px;
  margin-bottom: 0;
  border: none;
  /* El <li> NUNCA transiciona. sl_position_tab_glider() mide su getBoundingClientRect() en el
     instante de 'shown.bs.tab'; si además el <li> se está animando por su cuenta 300ms, el
     glider sale hacia una foto vieja y termina desalineado del texto. */
  transition: none !important;
}
/* Sin "efecto archivador": el papel blanco de la pestaña activa lo pinta el glider, uno solo
   que se desliza, no un ::before por pestaña. La barra del asunto ya lo tenía apagado
   (mega-design dejó su background comentado); aquí se apaga también en la del encargo, que era
   la única que lo conservaba y por eso pintaba DOS papeles superpuestos. */
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li.active::before { display: none; }
/* Sin salto al pasar el ratón: la única animación de estas pestañas es el deslizamiento del
   glider al cambiar de pestaña. Neutraliza el translateY(-7px) que mega-design le pone a las
   inactivas de #asunto y el que tenía la copia del encargo. */
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li:hover,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li:focus,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li:not(.active):hover,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li:not(.active):focus {
  transform: none !important;
}

/* La <a> ocupa TODO el <li>: el área que pinta el glider tiene que coincidir exactamente con
   la zona clicable de la pestaña. */
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li > a,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li > a:hover,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li > a:focus,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li > a:active,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li.active > a,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li.active > a:hover,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li.active > a:focus {
  display: flex;
  align-items: center;
  position: relative;
  top: 0 !important;
  width: 100% !important;
  height: 100% !important;
  box-sizing: border-box;
  /* El lado derecho sale de una variable para que la pestaña que lleva contador pueda
     reservarle hueco sin pelearse con este grupo. Ver "--sl-tab-pad-right" más abajo. */
  padding: 6px var(--sl-tab-pad-right, 13px) 4px 13px;
  margin: 0;
  background: transparent !important;
  border: none;
  border-radius: 12px 12px 0 0;
  /* Por encima del glider, que va en z-index:1 dentro del wrap. */
  z-index: 2;
}
/* Colores: mismos selectores en reposo y en hover/focus a propósito — estas pestañas NO
   reaccionan al ratón (comprobado sobre la barra del asunto: hover y reposo dan el mismo
   píxel), y repetir el color en :hover es lo que impide que se cuelen los de mega-design
   (rosa) o style.css (#004d95, que sobre el azul oscuro deja el texto invisible). */
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li > a,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li > a:hover,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li > a:focus,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li > a:active {
  color: var(--sl-tabs-fg) !important;
  font-weight: 500;
}
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li.active > a,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li.active > a:hover,
.mega-design #sl-app .sl-tabs-glide.nav-tabs > li.active > a:focus {
  color: var(--sl-tabs-fg-active) !important;
  font-weight: 500;
}

/* Contador de una pestaña (.sl-badge-count dentro de .sl-tabs-glide): NO va en línea con el
   rótulo, va flotando en diagonal sobre su esquina superior derecha, como el badge de aviso
   de un icono. Es el look que ya tenía la pestaña "Accesos" de la ficha de asunto y el que
   se ha elegido para todas — antes era un override atado por #id a esa única pestaña
   (mega-design.css), y por eso era el único badge distinto de la fila.

   ⚠️ NO añadir aquí un margin para "separarlo" del texto. En un elemento absoluto con
   left:auto y right fijado, el margen izquierdo entra en la ecuación de posicionamiento
   (left = CB − marginL − width − right), así que no separa: DESPLAZA el badge hacia la
   izquierda. La separación ya la da la geometría (top/right sobre el padding derecho de la
   pestaña, que es de 13px).

   ⚠️ Tampoco vale un espacio en la plantilla, ni ahora ni si algún día esto volviera a ir en
   línea: el <a> es display:flex (regla de arriba) y en un contenedor flex el espacio en
   blanco suelto entre items no se renderiza. Las 8 pestañas de la ficha de asunto llevaban
   ese espacio escrito de tres maneras distintas —dentro del <%if%>, fuera, y ausente— y las
   tres daban exactamente el mismo resultado pegado. Por eso el markup ya no lleva ninguno.

   El badge queda FUERA DEL FLUJO, así que no aporta ancho a la pestaña: la tira es más
   estrecha que con el contador en línea, y sl_position_tab_glider() —que mide el <li> en
   tiempo de ejecución— se adapta sin tocar nada.

   overflow:visible es obligatorio: sin él la pestaña recorta el trozo de badge que asoma por
   encima (top:-2px) y por la derecha (right:-3px), que es justo lo que le da el aire. */
#sl-app .sl-tabs-glide.nav-tabs > li > a {
  overflow: visible;
}
#sl-app .sl-tabs-glide.nav-tabs > li > a > .sl-badge-count {
  position: absolute;
  top: 3px;
  right: 0;
  margin: 0;
}
/* El hueco para el badge se reserva ensanchando el padding derecho de la pestaña que lo lleva,
   y se hace DEFINIENDO UNA VARIABLE, no declarando "padding-right". El motivo es de
   especificidad, y es la trampa central de este bloque:

   El grupo de arriba fija el padding de la pestaña con SIETE selectores —a, a:hover, a:focus,
   a:active, .active > a, .active > a:hover, .active > a:focus— todos con especificidad 142.
   Un "padding-right" aquí vale 132 (:has() pesa lo que su argumento más específico, o sea una
   clase), así que PIERDE en cada uno de esos estados. Medido en vivo: el hueco se aplicaba en
   reposo y se perdía al pasar el ratón por encima o al activar la pestaña, y el badge daba un
   salto de 7px hacia la izquierda montándose sobre el rótulo.

   Repetir la regla para cada estado es una carrera que se pierde sola: el día que alguien añada
   un octavo estado al grupo, el salto vuelve. Definiendo una custom property no hay competencia
   —nadie más escribe "--sl-tab-pad-right"— y cualquier estado presente o futuro hereda el hueco,
   porque todos leen el mismo var().

   ⚠️ El var() del grupo lleva fallback (13px) a propósito. Un var() sin fallback dentro de un
   shorthand invalida la declaración ENTERA allí donde la variable no está definida: las
   pestañas sin contador se quedarían sin padding ninguno.

   ⚠️ El badge se ancla a "right: 0", NO a un valor negativo. El wrap de la tira es
   .panel-heading con overflow:hidden, así que lo que sobresalga por la derecha se RECORTA. El
   override original de "Accesos" usaba right:-3px, inofensivo solo porque esa pestaña es la
   última de la fila. Al generalizar el estilo, cualquier pestaña puede quedar la última: medido,
   con el panel a 992px el badge de "Albaranes" se salía 5,6px y se cortaba por la mitad.

   :has() decide qué pestañas pagan el hueco: si el navegador no lo soporta (Chrome <105) no se
   aplica y el badge se monta un poco sobre la última letra — se degrada feo, no roto. */
#sl-app .sl-tabs-glide.nav-tabs > li > a:has(> .sl-badge-count) {
  --sl-tab-pad-right: 20px;
}
/* Altura del wrap del encargo abierto: `#encargo_abierto` (columna
   .col-md-7 que envuelve el <header class="encargos-tabs sl-tabs-glide-wrap">)
   es un hijo del `<header class="panel-heading tab-bd-secondary">` real, que
   es flex + align-items:center (regla genérica #sl-app .panel-heading más
   arriba en este archivo). Sin `align-self:stretch`, esa columna se queda con
   su altura intrínseca (la de la barra de tabs) CENTRADA dentro de la fila,
   que es más alta por la columna vecina (botones "Nuevo"/"Imprimir"). El
   .sl-tabs-glide-wrap de dentro —aun con su `height:100%`— hereda esa altura
   corta, así que sl_position_tab_glider() calcula el glider "flush" contra un
   borde inferior que NO es el borde inferior real de la barra: queda un hueco
   claro + la línea de `border-bottom` de la fila por debajo del glider en vez
   de justo debajo de él. Confirmado en vivo (captura): el blanco del glider
   no llega al fondo real de la cabecera. Estirar esta columna a la altura de
   la fila hace que `.sl-tabs-glide-wrap` (100% de esta columna) SÍ coincida
   con la altura visible completa. */
#encargo_abierto { align-self: stretch; }

/* El propio <li> NO debe transicionar nada. mega-design.css pone
   "transition: all .3s ease" en CUALQUIER <li> de .panel-heading .nav-tabs
   (pensado para el desplazamiento de color/top al activarse). Si además el
   ancho del <li> cambia al activarse —como en .bigtabs, que sube el
   font-size del texto activo y por tanto ensancha el <li>— ese "all" anima
   también el ancho. sl_position_tab_glider() mide getBoundingClientRect()
   del <li> en el instante de 'shown.bs.tab', así que el glider parte hacia
   una foto del <li> que TODAVÍA se está ensanchando/desplazando por su
   cuenta 300ms más: las dos animaciones (glider y <li>) divergen y el
   glider termina desalineado del texto. Confirmado en vivo con las tabs
   Info/Checklist/Temporizador del encargo abierto (.bigtabs). Sin
   transición en el <li>, su layout queda asentado en el mismo frame en que
   cambia 'active', y la única animación visible vuelve a ser la del propio
   glider. */
.mega-design #sl-app .panel-heading .sl-tabs-glide.nav-tabs > li {
  transition: none !important;
}

/* El bloque que había aquí neutralizaba el hover SOLO para las pestañas dentro de un
   .panel-heading, es decir solo para la barra del asunto. Lo hace ahora el bloque compartido
   .sl-tabs-glide de más arriba, que alcanza también a la del encargo — a petición del usuario
   2026-09-10 (mismas animaciones en las dos). */
/* cabecera filtros avisos */
.top-menu-avisos > li.tooltips > a.sl-btn.sl-btn--primary.sl-btn--icon {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
}
.item-cita {
  border-bottom: 1px dashed var(--sl-border, #e6eef7);
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: 5px;
  margin-bottom: 10px;
  padding-bottom: 10px;
}
.item-cita:last-child {
  border-bottom: none;
  padding-bottom: 0px;
  margin-bottom: 0px;
}
.item-cita p {
  margin: 0;
}
.ultimo_visitado {
  outline: 3px dashed var(--sl-pink);
  border: 3px solid white;
  position: relative;
}
.ultimo_visitado>td:first-child, .ultimo_encargo_inner>td:first-child,
.ultimo_visitado>td, .ultimo_encargo_inner>td {
  box-shadow: none;
}
.ultimo_visitado:after {
  content: "Último visitado";
  position: absolute;
  bottom: 0;
  left: 0;
  background: var(--sl-pink-050);
  padding: 3px;
  color: var(--sl-pink);
  font-weight: 600;
  border: 1px solid;
  border-radius: var(--sl-radius-xxs);
}
.align-items-self-start {
  align-items: self-start;
}

/* ============================================================================
   §15 — FICHA DE ASUNTO / ENCARGO
   ----------------------------------------------------------------------------
   Piezas del rediseño de la ficha de asunto (Claude Design, 09/2026) que NO
   existían ya en el proyecto.

   ⚠️ LO QUE NO DEBE ESTAR AQUÍ. Una primera versión de esta sección traía un
   componente propio de "celdas con borde que contienen datos"
   (.sl-cellgrid / .sl-cell / .sl-cell__label / .sl-cell__value), otro de
   tabla (.sl-dtable*), otro de barra (.sl-enc-toolbar*) y otro de notas
   (.sl-notes-grid / .sl-note). Los cuatro eran REINVENCIONES de componentes
   que ya estaban escritos y probados. El equivalente real:

     · Celdas con datos → <section class="sl-panel"> + .sl-panel__body (una
       FILA) + .sl-ficha-field-group (una CELDA) + .sl-meta-label +
       .form-data-value. Las divisorias las dan los border-right/border-top
       con :last-child/:first-child de las reglas de arriba (§ .sl-panel).
       Referencia: modules/dialog/dialog.ficha.tpl, modules/asunto.info.tpl.
     · Tablas → envoltorio .sl-table-bordered + las clases legacy
       "table webapp border-round-th table-tr-hover", que la capa de
       compatibilidad de #sl-app (líneas ~1047-1141) ya lleva al look del
       sistema. Referencia: alertas.tpl y otras 18 plantillas.
     · Barras → .sl-toolbar (+ .sl-toolbar--spread, .sl-toolbar__sep) y
       .sl-count para el contador de resultados.
     · Rótulo de sección → .sl-title / .sl-title--sm.

   Antes de añadir CUALQUIER cosa a esta sección: buscar primero si el
   resultado que se busca ya lo produce un componente existente.
   ============================================================================ */

/* --- Tokens que el diseño usa y no existían en el proyecto ---------------- */
:root {
  --sl-blue-400: #1E6BB8;    /* tinte azul claro (icono propio del encargo) */
  --sl-bg-well-2: #ECEFF3;   /* relleno neutro (candado sin permiso) */
  --sl-green: #1F9D55;       /* ok / cerrado (el diseño lo usa más saturado
                                que --sl-state-done, que se deja intacto
                                porque lo consumen otras pantallas) */
  --sl-amber: #E2A900;       /* en el circuito de facturación */
  --sl-red: #D5384C;         /* sin empezar / bloqueado */
  /* Fondo de "coincidencia de búsqueda resaltada": UN solo valor para que .highlight-search
     (softline-ui.css, más abajo) y la pill "Buscando" del resumen de búsqueda
     (asuntos.resumen.busqueda.tpl) no puedan desincronizarse — ver ambos usos. */
  --sl-highlight-bg: color-mix(in srgb, var(--sl-amber) 45%, transparent);
  /* Los tonos -600 de verde y ámbar, o sea sus versiones de :hover. Los demás colores sólidos
     del sistema ya los tenían (--sl-blue-600, --sl-pink-600, --sl-danger-600); verde y ámbar no,
     porque hasta el 2026-09-17 no existía ningún BOTÓN de esos dos colores — solo pills, donde
     el color es texto + borde sobre un tinte al 12% y el hover no repinta el fondo. Los estrenan
     .sl-btn--ok y .sl-btn--warn. */
  --sl-green-600: #17773F;
  --sl-amber-600: #C79500;
}

/* --- Tokenfield: pills + "Seleccionar" (campos multivalor) ---------------- */
/* Nuevo de verdad: dialog.ficha.tpl es de SOLO LECTURA, así que el sistema no
   tenía un control de "varios valores editables". Hace de
   .sl-inline-edit__display, así que inline_edit_start() lo oculta y muestra el
   <select multiple> sin cambios en JS. */
.sl-tokenfield {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  min-height: 34px;
  padding: 5px 6px;
  background: var(--sl-bg-card);
  border-radius: var(--sl-radius-sm);
  cursor: pointer;
  /* Sin borde — a petición del usuario 2026-09-08 (antes 1px solid var(--sl-border-2), con
     :hover coloreándolo de azul; los dos ya no aplican). */
}
/* Variante apilada de .sl-inline-edit para campos multivalor (Departamentos, Rptes.
   asignados): la base (arriba) es inline-flex EN FILA, pensada para "valor + lápiz" en línea;
   aquí hace falta columna para que la cabecera (título + botón "Seleccionar", ver .sl-note__head
   más abajo) quede ENCIMA del .sl-tokenfield con las pills, no al lado — a petición del usuario
   2026-09-08. Clase nueva y no un cambio en .sl-inline-edit: esa regla base la usan otros campos
   de un solo valor (Fecha prevista, Tipo facturación...) que sí quieren la fila. */
.sl-inline-edit--stack {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: 100%;
}

/* --- Cabecera de ficha (asunto y encargo) --------------------------------- */
/* Nacieron como .sl-asunto-header* (ganchos semánticos sin CSS que ya estaban en
   asunto.tpl) y se renombran a .sl-ficha-header* el 2026-09-10: la cabecera del
   encargo abierto (modules/asunto.encargo.cabecera.tpl) usa exactamente el mismo
   diseño y estructura, a petición del usuario. Una definición, dos cabeceras.
   El encargo omite la insignia de carpeta —no le hace falta, ya se identifica en
   el listado de la izquierda— y por lo demás el reparto es idéntico:
     __identity = candado + columna de título
     __titlecol = __titlerow (título + pills de estado) sobre __meta (ID copiable
                  + etiquetas)
     __actions  = fila de botones de solo icono, a la derecha. */
.sl-ficha-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.sl-ficha-header__identity {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  min-width: 0;
  flex: 1 1 30rem;
}
.sl-ficha-header__titlecol {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.sl-ficha-header__titlerow {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}
.sl-ficha-header__title {
  font: 800 22px/1.1 var(--sl-font);
  color: var(--sl-blue);
}
.sl-ficha-header__ref {
  font: 600 13px/1 var(--sl-font);
  letter-spacing: .04em;
  color: var(--sl-fg-3);
  white-space: nowrap;
}
.sl-ficha-header__meta {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.sl-ficha-header__actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
}
/* .sl-ficha-header__resumen / .sl-recl-link: eliminados el 2026-09-09. Eran la línea de texto
   "N reclamaciones" en rosa del bloque "Resumen" de la ficha; ese dato es ahora una pill genérica
   más (modules/resumen.asunto.pills.tpl), así que ningún marcado los usaba ya. */

/* ——— Pastilla de icono (icon tile) —————————————————————————————————————
   Cuadrado con fondo tintado y un glifo centrado dentro. Es la carpeta de la cabecera del
   asunto y, desde 2026-09-10, también la carpeta y el icono propio de cada encargo en el
   listado lateral. Historia del nombre: nació como .sl-asunto-icon (un solo uso), pasó por
   .sl-folder-icon y acaba con nombre neutro al dejar de llevar solo carpetas — a petición del
   usuario, que pidió meter también el icono opcional "dentro de la pastilla de color".

   NO confundir con .sl-icon-tag (redonda y RELLENA, glifo blanco sobre el color) ni con
   .sl-lock-btn (mismo cuadrado, pero relleno y clicable): esta es tintada, glifo de color
   sobre fondo claro, y no es un control.

   Cómo se colorea:
     · por defecto, el azul de marca sobre --sl-blue-100;
     · --done, el par verde (es un ESTADO, decisión de diseño);
     · --tinted, para cuando el color es un DATO y no hay par de tokens que elegir: se pasa
       solo --sl-icon-tile-color y el fondo se CALCULA a partir de él. Mismo puente de
       variable CSS que --sl-generic-pill-color en components/pill.tpl y --sl-icon-tag-color;
     · --spacer, hueco reservado invisible: ocupa lo mismo para que una columna de filas
       alinee igual tengan icono o no. */
.sl-icon-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: none;
  font-size: 16px;
  color: var(--sl-icon-tile-color, var(--sl-blue));
  background: var(--sl-icon-tile-bg, var(--sl-blue-100));
  border-radius: var(--sl-radius-xxs);
}
/* Variante pequeña, para filas densas. */
.sl-icon-tile--sm { width: 24px; height: 24px; font-size: 12px; }
.sl-icon-tile--done {
  --sl-icon-tile-color: var(--sl-green);
  --sl-icon-tile-bg: color-mix(in srgb, var(--sl-green) 14%, #fff);
}
.sl-icon-tile--tinted {
  background: color-mix(in srgb, var(--sl-icon-tile-color, var(--sl-blue)) 14%, #fff);
}
.sl-icon-tile--spacer { visibility: hidden; }

/* ⚠️ El candado se llama #lock y css/style.css:8400 le aplica
   `position:absolute; left:-7px; width:45px; height:45px` — en el diseño anterior flotaba suelto
   sobre la esquina de la tarjeta. Ahora va en línea dentro del flex de la cabecera, así que hay
   que deshacer ese posicionamiento; y como #lock es un selector de id (1,0,0), una clase suelta
   (0,1,0) no le gana: de ahí el #sl-app, que sube a (1,1,0).
   Lo mismo con `#lock .fa-lock { color:red }` (1,1,0), que dejaba el icono rojo sobre el fondo
   rojo del botón bloqueado, es decir invisible: se contrarresta con (1,2,0). */
#sl-app .sl-lock-btn {
  position: static;
  left: auto;
  /* El candado del ENCARGO se llama "lock_e{id}" (contrato con unlock_lock() en
     asunto.tpl.js:1032), y css/style.css:8420 tiene un `[id^="lock_e"]` con
     `position:relative; margin-top:30px; z-index:5` del diseño anterior, donde flotaba en
     su columna de iconos. Sin anular ese margen, el candado de la cabecera del encargo caía
     30px por debajo del título aunque .sl-ficha-header__identity sea align-items:flex-start.
     Comprobado: margin-top computado 30px hasta que se añadió esta línea. */
  margin: 0;
  z-index: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: none;
  font-size: 15px;
  color: #fff;
  background: var(--sl-blue);
  border: 1px solid var(--sl-blue);
  border-radius: var(--sl-radius-xxs);
  cursor: pointer;
  transition: background .2s ease;
}
#sl-app .sl-lock-btn .fa-lock,
#sl-app .sl-lock-btn .fa-lock-open { color: #fff; }
#sl-app .sl-lock-btn--muted .fa-lock,
#sl-app .sl-lock-btn--muted .fa-lock-open { color: var(--sl-fg-3); }
/* Todos los modificadores van scopeados igual que la base: si la base es (1,1,0) por el #sl-app
   de arriba, una variante en (0,1,0) no le ganaría el background y el candado bloqueado saldría
   azul en vez de rojo. */
#sl-app .sl-lock-btn:hover,
#sl-app .sl-lock-btn:focus { color: #fff; background: var(--sl-blue-600); }
#sl-app .sl-lock-btn--locked {
  background: var(--sl-red);
  border-color: var(--sl-red);
}
#sl-app .sl-lock-btn--locked:hover,
#sl-app .sl-lock-btn--locked:focus { background: #B32C3D; }
/* Candado sin permiso para accionarlo (nivel < 9) y asunto NO bloqueado: sigue informando del
   estado, pero en gris para no prometer una acción que ese usuario no puede ejecutar. */
#sl-app .sl-lock-btn--muted {
  color: var(--sl-fg-3);
  background: var(--sl-bg-well-2);
  border-color: var(--sl-border-2);
}
#sl-app .sl-lock-btn.is-static { cursor: default; }
#sl-app .sl-lock-btn.is-static:hover,
#sl-app .sl-lock-btn.is-static:focus { background: var(--sl-bg-well-2); color: var(--sl-fg-3); }
#sl-app .sl-lock-btn--locked.is-static:hover,
#sl-app .sl-lock-btn--locked.is-static:focus { background: var(--sl-red); color: #fff; }

/* Separación de la tarjeta del asunto respecto al topbar. Son 12px, no 10, para igualar el
   padding-right de 12px de #main-content > .wrapper: con 10 quedaba un desfase visible de 2px
   entre el margen superior y el derecho de la tarjeta. */
.sl-asunto-panel { margin-top: 12px; }

/* Entradas del dropdown "Más acciones" de la cabecera */
.sl-menu__item {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .35rem .9rem;
  cursor: pointer;
}
.sl-menu__label {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: 0;
  font-weight: 600;
  font-size: .75rem;
  cursor: pointer;
}
/* Aquí estaban las dos reglas que fijaban el fotograma inicial del sprite de favorito del
   asunto (.sl-fav-wrap > #asunto_favorito, con y sin .is-fav). Se han ido con el sprite:
   desde 2026-09-10 ese favorito es un corazón de Font Awesome y el estado se dice con
   far/fas, no con background-position. Ver .sl-btn--fav más arriba. */

/* Entrada de un menú desplegable: una FILA, no un botón de acción.
   Es el look de los menús del listado de asuntos (modules/asuntos.filtros.tpl, el desplegable
   "Ningún encargo marcado"), con las dos correcciones que pidió el usuario 2026-09-10:
     · el realce del hover ocupa la fila ENTERA y no solo el icono y el texto — de ahí el
       width:100%, porque un <button> se ajusta a su contenido y ahí estaba el recorte;
     · el fondo del hover es el azul corporativo (--sl-blue), no el azul heredado del tema.
   Genérica a propósito: vale igual sobre un <a> que sobre un <button>. Los del menú
   "Imprimir" de los encargos son <button> porque llevan dentro <input type="hidden"> que lee
   el JS (asunto.tpl.js:993 y siguientes), así que no pueden ser enlaces.
   El segundo selector hace falta para el día que se ponga sobre un <a> dentro de .sl-menu:
   ".sl-menu > li > a" es (0,2,1) y le ganaría a una clase suelta (0,1,0). */
.sl-menu__link,
.sl-menu > li > .sl-menu__link {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  margin: 0;
  padding: .375rem .625rem;
  font: 500 .75rem/1.35 var(--sl-font);
  color: var(--sl-fg-2);
  text-align: left;
  white-space: nowrap;
  background: none;
  border: 0;
  border-radius: var(--sl-radius-xxs);
  cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.sl-menu__link > i { flex: none; width: 1rem; font-size: .8125rem; text-align: center; color: var(--sl-blue-400); }
.sl-menu__link:hover,
.sl-menu__link:focus,
.sl-menu > li > .sl-menu__link:hover,
.sl-menu > li > .sl-menu__link:focus {
  color: #fff;
  background: var(--sl-blue);
  text-decoration: none;
  outline: none;
}
.sl-menu__link:hover > i,
.sl-menu__link:focus > i { color: #fff; }

/* Fila INFORMATIVA de un menú (2026-09-17). Misma rejilla, misma tipografía y mismo sangrado
   que .sl-menu__link, pero sin prometer un clic. La estrena el desglose de los desplegables del
   resumen de la ficha de asunto (modules/resumen.asunto.pills.tpl): ahí "153 Acabados" es un
   dato, no una acción, mientras que "9 Sin asignar" sí abre un diálogo y sigue siendo un
   <button class="sl-menu__link"> normal.

   ⚠️ Hace falta la clase; NO basta con cambiar la etiqueta a <span>. .sl-menu__link no está
      atada a <button> —el selector es de clase— así que un <span> con ella hereda también el
      cursor de mano y el realce azul de ancho completo del :hover. Un menú que se ilumina al
      pasar por encima y no hace nada al pulsar miente peor que uno sin estilo.

   Se anula el :hover en las dos formas del selector, la corta y la de ".sl-menu > li > …",
   porque esa segunda llega a (0,3,1) y sin su pareja aquí ganaría por especificidad. */
.sl-menu__link--static,
.sl-menu > li > .sl-menu__link--static { cursor: default; }
.sl-menu__link--static:hover,
.sl-menu__link--static:focus,
.sl-menu > li > .sl-menu__link--static:hover,
.sl-menu > li > .sl-menu__link--static:focus { color: var(--sl-fg-2); background: none; }
.sl-menu__link--static:hover > i,
.sl-menu__link--static:focus > i { color: var(--sl-blue-400); }
@media (prefers-reduced-motion: reduce) {
  .sl-menu__link { transition: none; }
}

/* ——— Submenú lateral dentro de un .sl-menu —————————————————————————————————
   Bootstrap 3 ELIMINÓ los submenús de .dropdown-menu respecto a la v2, así que esto no
   existía y hay que escribirlo. Se usa en el compositor de filtros "Seguimiento" de
   /comerciales (components/filtro.combo.tpl): cada fila del menú abre a su lado el juego
   de valores de ese filtro.

   Marcado esperado:
     <li class="sl-submenu">
       <button class="sl-menu__link">…<span class="sl-menu__right">…</span></button>
       <ul class="dropdown-menu sl-menu sl-menu--rows"> … </ul>
     </li>
   y se abre añadiendo la clase "open" AL <li>.

   ⚠️ La clase tiene que ser "open" y no una propia, y no es cosmético: en este mismo archivo
   "#sl-app .dropdown-menu { display:none; opacity:0 }" es (1,1,0) y se lleva por delante
   cualquier regla de clases que intente mostrar el submenú. La ÚNICA puerta de salida es
   "#sl-app .open > .dropdown-menu { display:flex; opacity:.9 }". Por eso aquí NO se toca el
   display: se reutiliza el mecanismo que ya existe. */
.sl-submenu { position: relative; }
.sl-submenu > .sl-menu {
  position: absolute;
  top: -.375rem;
  left: 100%;
  margin: 0;
  min-width: 7.375rem;
  /* ⚠️ ".sl-menu" lleva "right: 0 !important" (§ "Menú desplegable de la cabecera") para que
     TODOS los menús del sistema salgan pegados a la derecha de su botón; de hecho por eso
     components/dropdown.tpl documenta que no tiene parámetro de alineación. Un submenú
     necesita justo lo contrario. Esto es (0,2,0) con !important, así que gana a esa clase
     suelta sin tener que tocarla — y sin cambiarle la alineación a ningún otro menú. */
  right: auto !important;
}
.sl-submenu > .sl-menu > li { white-space: nowrap; }

/* Zona derecha de una fila de menú: el valor actual y la flecha del submenú.
   margin-left:auto y NO float:right — ".sl-menu__link" es flex (ver arriba), y un float
   dentro de un contenedor flex se ignora. */
.sl-menu__right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: .375rem;
  padding-left: .625rem;
}
.sl-menu__right > i { opacity: .5; }
/* El valor que tiene ahora mismo ese filtro. Gris = ya aplicado; rosa = tocado en esta
   sesión y todavía sin guardar. Es lo único que distingue "lo que ya filtra" de "lo que
   filtrará cuando pulses Guardar". */
.sl-menu__val { font-weight: 600; font-size: .6875rem; color: var(--sl-fg-3); }
.sl-menu__val--pend { font-weight: 700; color: var(--sl-pink); }
/* El hover pinta la fila entera de azul, así que el valor tiene que pasar a blanco con ella
   o desaparece (el gris y el rosa sobre --sl-blue no se leen). */
.sl-menu__link:hover .sl-menu__val,
.sl-menu__link:focus .sl-menu__val { color: #fff; }

/* Pie del menú: contador de cambios pendientes + botón de guardar.
   El !important del padding bate a "#sl-app .dropdown-menu li { padding-left/right: 5px }"
   (1,2,1), que aquí deja el pie descuadrado respecto a las filas. */
.sl-menu__foot {
  display: flex !important;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  margin-top: .25rem;
  padding: .4375rem .5625rem .1875rem !important;
  border-top: 1px solid var(--sl-border);
}
.sl-menu__foot-n { font: 600 .6875rem/1 var(--sl-font); color: var(--sl-pink); white-space: nowrap; }
.sl-menu__foot-n--none { font-weight: 400; color: var(--sl-fg-3); }


/* La capa de compatibilidad de #sl-app (§8 de este mismo archivo, ~línea 853) da por hecho que
   TODO <button> dentro de un .dropdown-menu es un botón de acción y le clava
   `background: var(--sl-blue)` con (1,2,1); también mete 5px de padding en cada <li> y deja el
   menú abierto en `opacity:.9`. Nada de eso vale para un menú de filas:
     · el fondo azul fijo se come el hover (todo azul, siempre),
     · el padding del <li> impide que el realce llegue al borde — justo el "hover de la fila
       completa" que se pidió,
     · y el 0.9 transparenta el menú sobre el listado que tiene debajo, que se lee fatal.
   Estas reglas lo deshacen SOLO donde hay un .sl-menu__link. El :has() es lo que las mantiene
   genéricas: no tocan los <li> de .sl-menu que no llevan una fila de estas (p.ej. los
   .sl-menu__item del menú "más acciones" de la cabecera del asunto). */
#sl-app .sl-menu > li:has(> .sl-menu__link) { padding: 0; }
#sl-app .sl-menu > li > .sl-menu__link {
  width: 100%;
  padding: .375rem .625rem;
  background: none;
}
#sl-app .sl-menu > li > .sl-menu__link:hover,
#sl-app .sl-menu > li > .sl-menu__link:focus { background: var(--sl-blue); }

/* …y la excepción de la fila INFORMATIVA (.sl-menu__link--static), que NO debe encenderse:
   si no es clicable, no se ilumina al pasar por encima; si lo es, mano y realce — usuario
   2026-09-17, que la vio iluminarse en "1 Esperando cliente".

   ⚠️ ESTA REGLA TIENE QUE ESTAR AQUÍ, justo detrás de la de arriba, y no junto al resto de
      .sl-menu__link--static (más arriba en este archivo). Dos motivos encadenados:
        · Sin el "#sl-app" se queda en (0,3,1) y la de arriba es (1,3,1): un ID vale más que
          cualquier número de clases, así que pierde siempre. Fue el fallo real.
        · Con el "#sl-app" empatan a (1,3,1), y en un empate gana la ÚLTIMA del archivo. Puesta
          en su bloque original (línea ~4318) seguiría perdiendo contra la 4415.
      Si algún día se reordena esta hoja, las dos tienen que seguir en este orden.

   El color y el del icono no hacían falta —(0,3,1) ya le ganaba a ".sl-menu__link:hover"
   (0,2,0)— pero van aquí igualmente para que la excepción se lea entera en un sitio. */
#sl-app .sl-menu > li > .sl-menu__link--static:hover,
#sl-app .sl-menu > li > .sl-menu__link--static:focus {
  background: none;
  color: var(--sl-fg-2);
  cursor: default;
}
#sl-app .sl-menu > li > .sl-menu__link--static:hover > i,
#sl-app .sl-menu > li > .sl-menu__link--static:focus > i { color: var(--sl-blue-400); }

/* Fila de menu en ROJO: una accion destructiva ("Eliminar los documentos marcados") o una que
   no esta disponible y explica por que ("Asignar Llamadas" cuando el cliente no tiene llamadas
   recientes, ver modules/boton.encargo.llamada.tpl). NO es decoracion: es la unica senal de que
   esa fila no es como las demas.
   Hace falta esta regla porque ".sl-menu .text-danger" (0,2,0) PIERDE contra
   ".sl-menu > li > .sl-menu__link" (0,3,1), que fija el color de todas las filas: sin ella la
   fila roja sale del mismo gris que el resto. Comprobado en vivo.
   El :hover va aparte y despues para que al pasar por encima gane el blanco sobre azul: si no,
   esta regla (1,4,1) le ganaria al ".sl-menu__link:hover { color:#fff }" (0,2,0) y quedaria
   rosa sobre azul, ilegible. */
#sl-app .sl-menu > li > .sl-menu__link.text-danger,
#sl-app .sl-menu > li > .sl-menu__link.text-danger > i { color: var(--sl-pink); }
#sl-app .sl-menu > li > .sl-menu__link.text-danger:hover,
#sl-app .sl-menu > li > .sl-menu__link.text-danger:focus,
#sl-app .sl-menu > li > .sl-menu__link.text-danger:hover > i,
#sl-app .sl-menu > li > .sl-menu__link.text-danger:focus > i { color: #fff; }
/* `.sl-menu { opacity: 1 }` (§ cabecera del asunto) YA quería esto, pero es (0,1,0) y pierde
   contra `#sl-app .open>.dropdown-menu { opacity:.9 }` (1,2,0). Aquí empata en especificidad y
   gana por orden, que es lo que se pretendía desde el principio. */
#sl-app .open > .sl-menu { opacity: 1; }

/* Menú de FILAS: el contenedor de los .sl-menu__link, lo que emite components/dropdown.tpl.
   Ancho al contenido (las entradas son nowrap); antes estaba clavado a 11rem y recortaba
   "Partes Encargos en curso" con puntos suspensivos. El `gap` a 0 porque
   #sl-app .dropdown-menu pone 5px pensando en botones sueltos, y entre filas de menú deja
   unos huecos que rompen la columna.
   Se llamaba .sl-menu--print cuando solo lo usaba el desplegable de imprimir de los encargos.
   El nombre viejo se conserva como alias por si queda alguna plantilla sin migrar: cuesta una
   palabra y evita que un menú aparezca con los huecos de 5px y sin padding. */
#sl-app .sl-menu--rows,
#sl-app .sl-menu--print { min-width: 12rem; gap: 0; padding: 4px; }

/* Envoltorio de components/dropdown.tpl.
   .dropdown de Bootstrap es un <div> pelado, o sea de BLOQUE: se estira a todo el ancho de
   su contenedor. Y como .sl-menu lleva "right: 0 !important", el menú se ancla al borde
   derecho del ENVOLTORIO y no al del botón: en la ficha comercial, donde el envoltorio mide
   723px, el menú de "Añadir" aparecía a 500px del botón que lo abre.
   inline-block lo ciñe al botón, que es lo único que contiene (el menú va absolute). En un
   contenedor flex no cambia nada: un flex item ya se ajusta a su contenido. */
.sl-dropdown { display: inline-block; }

/* Botón que abre un menú de "marcados" (los "Ningún parte marcado" / "Ninguno marcado" de las
   tablas con multiselect). Lo único que necesita aparte de ser un .sl-btn normal es no cambiar
   de ancho: su texto lo reescribe el JS en cada clic de casilla (tablas.multiselect.tpl.js y
   carpetas.tpl.js), y pasa de "Ninguno marcado" a "Acción para 12 marcados". Sin el min-width
   el botón salta de tamaño y arrastra a sus vecinos de la cabecera.
   Sustituye a los `style="font-size:13px; min-width:200px; text-align:left"` que llevaban
   inline los de documentos y fotos.

   El valor se bajó de 13rem a 11.5rem el 2026-09-15, a petición del usuario ("mucho margen a la
   derecha"): 13rem son 234px con la raíz a 18px, y la etiqueta MÁS LARGA que llega a pintarse
   —"Ningún parte marcado", la inicial del selector de partes— mide 203px, así que sobraban 31px
   de hueco muerto detrás del triángulo. Medido en vivo, no estimado.

   ⚠️ Al ajustarlo hay que mirar la etiqueta INICIAL, no la de "marcados". En los tres selectores
      que usan esta clase el texto solo se ACORTA al marcar casillas ("Ningún parte marcado" 203px
      -> "12 partes marcados" 177px; "Ninguno marcado" -> "12 marcados"), así que el ancho de
      partida es el que manda y el botón nunca necesita crecer. Si algún día un selector nuevo
      pasa a una etiqueta más larga que la inicial, este min-width deja de protegerlo.
      En rem y no en px porque toda la UI escala desde el font-size raíz (ver up_ui_scale). */
.sl-btn--selector { min-width: 11.5rem; justify-content: flex-start; }
.sl-btn--block { width: 100%; justify-content: flex-start; margin-bottom: 2px; }

/* --- Desplegable DENTRO de un campo de ficha ------------------------------
   Representante y Departamento (del encargo y del asunto) eligen su valor con un menu de
   components/dropdown.tpl en vez de con el <select> inline que se ensenaba al pulsar
   "Seleccionar" — a peticion del usuario 2026-09-14.

   ⚠️ LA TRAMPA, y es la que decide si esto se ve o no: ".sl-panel" lleva "overflow: hidden"
      (§ 6c, arriba). El menu de Bootstrap 3 es un hijo absolute del envoltorio, o sea que se
      dibuja DENTRO del panel y queda RECORTADO — invisible, sin un solo error en consola. Y no
      hay escapatoria por marcado: data-container="body" existe para tooltip y popover, no para
      el plugin dropdown de Bootstrap 3.
      La salida es dejar de recortar mientras hay uno abierto, que es exactamente lo que ya se
      hacia con los menus "Elegir mes"/"Elegir ano" de la barra de filtros (§ .sl-fixed-top).
      Bootstrap pone ".open" en el envoltorio, asi que el :has() se enciende y se apaga solo.
      Se listan los DOS niveles porque los paneles anidan: el menu de "Departamento" esta en el
      .sl-panel de "Datos del encargo", que a su vez vive dentro del .sl-panel #encargos. Con
      recortar uno cualquiera de la cadena ya no se ve. */
.sl-panel:has(.sl-dropdown.open),
.sl-panel__body:has(.sl-dropdown.open),
.sl-ficha-field-group:has(.sl-dropdown.open) { overflow: visible; }

/* Lista larga (los empleados de un departamento, los departamentos de la casa): el menu se
   queda con scroll propio en vez de estirarse mas que la pantalla. */
.sl-menu--scroll { max-height: 17rem; overflow-y: auto; }

/* Fila de menu que ELIGE un valor. La marca de seleccionado es un fa-check que ocupa sitio
   SIEMPRE (visibility, no display): asi las etiquetas quedan en columna en vez de bailar
   hacia la izquierda en cuanto una fila esta marcada.
   Hereda de .sl-menu__link todo lo demas, incluido el realce azul de ancho completo. */
.sl-menu__link--pick > i { visibility: hidden; }
.sl-menu__link--pick.is-on > i { visibility: visible; }
.sl-menu__link--pick.is-on { color: var(--sl-blue); font-weight: 600; }
#sl-app .sl-menu > li > .sl-menu__link--pick.is-on { color: var(--sl-blue); }
#sl-app .sl-menu > li > .sl-menu__link--pick.is-on:hover,
#sl-app .sl-menu > li > .sl-menu__link--pick.is-on:focus { color: #fff; }

/* Cabecera de "Departamento": cuando el campo solo lleva el desplegable, .sl-note__head
   reparte con space-between y el boton se va al extremo derecho de la celda. Es el mismo
   sitio en el que estaba "Seleccionar", asi que no hace falta nada mas.
   .sl-note__actions (dos botones: "Seleccionar" + el menu de cambio rapido) ya existe. */

/* --- Fila de campo enmarcada (Estado / Acciones del encargo) -------------- */
/* No es lo mismo que .sl-ficha-field-group-row: esa es una CELDA (flex:1) que
   debe vivir dentro de un .sl-panel__body. Esto es una fila suelta, con su
   propio marco, que se coloca entre bloques sin necesidad de un panel. */
.sl-fieldrow {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 11px 14px;
  border: 1px solid var(--sl-border);
  border-radius: var(--sl-radius-md);
}
.sl-fieldrow__label {
  flex: none;
  font: 700 11px/1.2 var(--sl-font);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--sl-fg-3);
}
.sl-fieldrow__items {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
}
/* Una .sl-fieldrow DENTRO de un .sl-panel deja de ser una caja suelta y pasa a ser una fila más
   del panel: el borde y el radio los pone ya el panel, y entre filas basta la misma divisoria de
   1px que usa .sl-panel__body. Es lo que pide el artboard Encargos.dc.html para "Estado y
   acciones" (dos filas rotuladas dentro de una tarjeta) y evita tener que duplicar el flex, el
   wrap y el padding que .sl-fieldrow ya trae. Solo aplica a hijas DIRECTAS: las .sl-fieldrow
   sueltas de modules/asunto.info.tpl y las de la lista de mensajes siguen igual. */
.sl-panel > .sl-fieldrow {
  border: 0;
  border-radius: 0;
}
.sl-panel > .sl-fieldrow + .sl-fieldrow {
  border-top: 1px solid var(--sl-border);
}

/* --- Notas ---------------------------------------------------------------- */
/* La rejilla de notas NO está aquí: son .sl-ficha-field-group dentro de un
   .sl-panel__body, como cualquier otra fila de campos. Solo queda el aspecto
   propio de la textarea y de su cabecera (rótulo + botón de insertar texto). */
.sl-note__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}

/* Celda "Departamento + Tipo" del encargo (modules/asunto.encargo.panel.info.tpl), a dos filas:

       Departamento                    [ Seleccionar dpto. v ]
       (COMERCIAL)                     [ Generico           v ]

   Etiqueta y valor en la columna izquierda, los dos desplegables alineados a la derecha. La
   dificultad es que la pastilla del DEPARTAMENTO y el boton del TIPO comparten fila siendo de
   campos distintos: cada uno vive en su propio .sl-inline-edit y no se pueden juntar en el HTML
   sin romper el aislamiento del que depende el JS (ver el comentario de la plantilla).

   Por eso la celda es una rejilla de dos columnas y los envoltorios se declaran
   "display: contents": desaparecen del LAYOUT -sus hijos pasan a ser items de esta rejilla- pero
   no del ARBOL, asi que closest('.sl-inline-edit') de sl_field_pick() sigue resolviendo igual.
   Los items caen en orden: etiqueta | boton dptos / valor dpto | boton tipo.

   Acotado a esta celda a proposito (clase --dpto-tipo): el mismo par de campos en el ASUNTO
   conserva el diseno de siempre, con etiqueta y valor en linea. Usuario 2026-09-18. */
#sl-app .sl-ficha-field-group--dpto-tipo {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  column-gap: .5rem;
  row-gap: .25rem;
}
#sl-app .sl-ficha-field-group--dpto-tipo > .sl-inline-edit,
#sl-app .sl-ficha-field-group--dpto-tipo > .sl-inline-edit > .sl-note__head {
  display: contents;
}
/* Los dos desplegables, pegados al extremo derecho. La columna de la derecha mide lo que el
   mas ancho de los dos ("Seleccionar dpto."), asi que sin esto el del Tipo -mas estrecho- se
   quedaba alineado al principio de esa columna y los dos botones no casaban por la derecha. */
#sl-app .sl-ficha-field-group--dpto-tipo .sl-dropdown {
  justify-self: end;
}
/* Cabecera de "Comentario"/"Notas internas": el botón que inserta el nombre del usuario logeado
   (modules/btn.add.texto.textarea.tpl) se quiere pegado al título en vez de empujado al extremo
   derecho por el space-between de arriba — ese space-between sigue haciendo falta tal cual para
   Departamentos/Rptes. asignados (título y "Seleccionar" en extremos opuestos) — a petición del
   usuario 2026-09-08. */
.sl-note__head--left {
  justify-content: space-between;
}
/* Dos o más acciones en la cabecera de un campo (Representante asignado del encargo:
   "Seleccionar" + el botón rosa de Cambio Rápido). Hace falta envolverlas porque
   .sl-note__head reparte con space-between: con tres hijos sueltos el botón de en medio
   se queda flotando en el centro en vez de pegado a su compañero. El gap es el mismo
   que el de .sl-note__head para que el conjunto se lea como un solo grupo. */
.sl-note__actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
#sl-app .sl-note__ta {
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
  padding: 10px 12px;
  font: 500 14px/1.55 var(--sl-font);
  color: var(--sl-blue);
  background: var(--sl-bg-card);
  border: 1px solid var(--sl-border);
  border-radius: var(--sl-radius-sm);
  box-shadow: none;
  outline: none;
}
#sl-app .sl-note__ta:focus {
  border-color: var(--sl-blue);
  box-shadow: var(--sl-focus);
}
/* (Aquí vivía .sl-inline-edit-nota__display, el <div> de lectura de las notas del encargo que
   se intercambiaba con el textarea al hacer doble click. Las notas se escriben directamente
   desde el 2026-09-14 y ese <div> ya no se pinta, así que la regla se retira: la altura mínima
   la pone ahora el propio textarea a través de data-adaptative.) */

/* --- Encargos: master-detail y lista lateral ------------------------------ */
/* El split es flex puro desde la fase 2 (2026-09-09): antes se montaba sobre las col-md-3 /
   col-md-9 de Bootstrap, que ya no maquetaban nada y solo seguían ahí porque el JS las buscaba
   por selector. Hecha la fase 1 (localizadores sl_enc_* por id, ver modules/js/encargos.tpl.js),
   el marcado quedó libre y las clases se han retirado.
   Ver _devel/claude/plan_encargos_estructura_sl_panel.md

   ⚠️ Los tres selectores de este bloque van acotados a "#encargos > ", igual que la regla del
   borde superior unos cientos de líneas más arriba y por el mismo motivo. Un selector de id NO
   para en el primer elemento: cae sobre TODOS los que lleven ese id. Hasta el 2026-09-10 el
   bloque de encargo del asunto comercial (modules/asunto.info.tpl) también se llamaba
   "encargos-panel-body", así que heredaba este display:flex —pensado para el reparto 380px +
   resto— y sus cinco secciones se pintaban una al lado de otra, desbordando por la derecha.
   Aquel bloque se llama ahora #encargo-comercial-panel, pero la acotación se queda: describe
   lo que la regla de verdad quiere decir, que es "el cuerpo del split maestro-detalle".
   Sirve para la ficha normal (modules/asunto.encargos.tpl) y para la reducida de cliente
   (modules/asunto_reducido.encargos.tpl); las dos cuelgan de un <section id="encargos">. */
#sl-app #encargos > #encargos-panel-body {
  display: flex;
  align-items: stretch;
  /* Suelo de altura del split. Sin él, un encargo de ficha corta dejaría la lista de 122 encargos
     metida en una ventanita de 300px: ahora la altura la manda el panel del encargo (ver el
     position:absolute del <ul> más abajo), así que hace falta un mínimo razonable. 480px son unas
     ocho filas visibles. Valor literal y no token porque esta hoja no tiene escala de alturas,
     igual que el padding:15px de .sl-enc-main. Usuario 2026-09-17. */
  min-height: 480px;
  /* .sl-panel__body trae padding y gap propios (pensados para filas de campos). Aquí el listado
     va a ras del borde de la tarjeta y la divisoria con el panel la pone el border-right de
     .sl-enc-side, así que ni padding ni hueco entre las dos columnas. */
  padding: 0;
  gap: 0;
}
/* Ancho FIJO del listado (380px), como pide el artboard Encargos.dc.html; antes era proporcional
   (col-md-3 = 25%), que en un monitor ancho deja el listado enorme y en uno estrecho sin sitio. */
#sl-app #encargos > #encargos-panel-body > .sl-enc-aside {
  flex: 0 0 380px;
  max-width: 42%; /* en pantallas estrechas el listado no puede comerse el panel */
  padding: 0;
  border-right: 1px solid var(--sl-border);
  min-width: 0;
  /* Ancla del <ul> de abajo, que va en position:absolute. El aside SÍ se sigue estirando a la
     altura de la línea, y eso es lo que mantiene la divisoria vertical entera de arriba abajo:
     si en vez de esto se le pusiera un max-height al propio aside, el border-right se cortaría a
     media altura y se vería roto. */
  position: relative;
}
/* EL LISTADO HACE SU PROPIO SCROLL, Y NO INFLA EL BLOQUE.
   Con 122 encargos la <ul> mide 7.156px, y como es un item estirado del flex arrastraba a TODO el
   split a esa altura: el panel del encargo quedaba estirado y casi todo vacío. Al sacarla del flujo
   con position:absolute, su contenido deja de contar para la altura de la línea, que pasa a mandarla
   .sl-enc-main — que es lo que se ve. La lista se queda dentro con su scroll.
   ⚠️ NO se ha usado position:sticky, que es lo primero que uno probaría: #encargos es un .sl-panel
      con overflow:hidden, y el contenedor de scroll real de la página es section.wrapper, así que
      un sticky aquí dentro se queda sin efecto. Comprobado en vivo antes de escribir esto.
   ⚠️ La <ul> conserva sus clases "nav nav-tabs tabs-left" y su id: el tab keeper y el buscador del
      lateral la localizan por ahí. Aquí solo cambia cómo se posiciona. */
#sl-app #encargos > #encargos-panel-body > .sl-enc-aside > #encargos-sidebar {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overflow-x: hidden;
}
#sl-app #encargos > #encargos-panel-body > .sl-enc-main {
  flex: 1 1 auto;
  /* Sin min-width:0 una tabla ancha (la de partes) estira su columna flex por encima del hueco
     disponible y se lleva por delante el ancho fijo del listado. */
  min-width: 0;
  /* El aire alrededor del encargo abierto. Estaba llegando de rebote: el <div> de dentro llevaba
     la clase "panel-body" de Bootstrap SOLO para heredar su padding de 15px — y, de paso, un
     borde que había que anular aquí mismo con un !important. Al aplicar el mismo diseño a la
     vista reducida de cliente (usuario 2026-09-10) se vio el problema de depender de eso: aquel
     marcado no llevaba "panel-body" y el contenido salía pegado al borde. Ahora el padding es de
     .sl-enc-main, que es de quien tiene que ser, y las dos vistas lo heredan del mismo sitio.
     15px y no una variable de espaciado: es el valor exacto que tenía, y esto es una corrección
     de dónde vive la regla, no un cambio de diseño. */
  padding: 15px;
}
/* Indicador mientras se pide el panel de un encargo (modules/js/encargos.tpl.js).
   ⚠️ --sl-text-muted y --sl-font-sm NO existen en esta hoja: no hay ninguna escala de tamaños
   de fuente tokenizada (--sl-font es la familia tipográfica, no un tamaño), así que se usa
   var(--sl-fg-3) —el color ya establecido para texto secundario/muted en toda la hoja
   (.sl-text--muted, .sl-meta-value--muted, .sl-lock-btn--muted...)— y el tamaño literal
   .8125rem, el mismo que usa .sl-text para texto secundario (línea 165). */
#sl-app .sl-enc-cargando {
  padding: var(--sl-space-5);
  color: var(--sl-fg-3);
  font-size: .8125rem;
  text-align: center;
}
/* El GIF de carga es el mismo de las modales. Se centra y el texto cae debajo; los mensajes de
   error reutilizan el contenedor SIN imagen, que para eso el <img> no es obligatorio. */
#sl-app .sl-enc-cargando img { display: block; margin: 0 auto var(--sl-space-2); }
#sl-app .sl-enc-cargando span { display: block; }
/* Lista de encargos del aside.
   ⚠️ La <ul> está OBLIGADA a conservar las clases "nav nav-tabs tabs-left": el tab-keeper
   (asunto.tabs.keeper.tpl.js:97-101) y asunto.tpl.js:241 la seleccionan por
   ul.nav.nav-tabs.tabs-left / .hasClass('tabs-left'). Eso arrastra dos capas de CSS heredado
   —.nav-tabs>li.active>a de Bootstrap (0,3,1) y .tabs-left>li>a de css/style.css:6763 (0,2,1)—
   con más especificidad que una clase suelta. De ahí el prefijo #sl-app en todo el bloque:
   sube a (1,3,1) y gana sin necesidad de !important. */
#sl-app .sl-enc-side {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding-top: 0;
  border-right: 1px solid var(--sl-border); /* .tabs-left lo pone en #ddd */
  border-bottom: none;
}
#sl-app .sl-enc-side > li {
  float: none;
  margin: 0; /* .tabs-left>li mete margin-bottom:2px y margin-right:-1px */
}
#sl-app .sl-enc-side > li > .sl-enc-side__row {
  display: flex;
  align-items: center;
  gap: 5px;
  margin: 0;
  padding: 10px 14px !important;
  cursor: pointer;
  color: var(--sl-blue);
  background: var(--sl-bg-card);
  border: 0;
  border-bottom: 1px solid var(--sl-border);
  border-left: 0 solid var(--sl-blue);
  border-radius: 0; /* .tabs-left>li>a redondea la esquina izquierda */
  transition: background .15s ease;
  position: relative;
}
#sl-app .sl-enc-side > li > .sl-enc-side__row:hover,
#sl-app .sl-enc-side > li > .sl-enc-side__row:focus {
  background: var(--sl-blue-050);
  border-color: var(--sl-border);
  border-left-color: var(--sl-blue);
}
/* Encargo seleccionado: relleno azul claro + barra azul de 3px a la izquierda. El padding-left
   baja a 11px para compensar exactamente esos 3px y que el contenido no se desplace al elegir. */
#sl-app .sl-enc-side > li.active > .sl-enc-side__row,
#sl-app .sl-enc-side > li.active > .sl-enc-side__row:hover,
#sl-app .sl-enc-side > li.active > .sl-enc-side__row:focus {
  background: var(--sl-blue-100);
  border-bottom-color: var(--sl-border);
  border-left-width: 3px;
  padding-left: 11px !important; /* ver la nota del !important en la regla de arriba */
}
/* .sl-enc-side__prio (insignia cuadrada con el número/✓, la que salía primero en la fila) se ha
   quitado del todo del markup (asunto.encargo.sidebar.tab.tpl) — a petición del usuario
   2026-09-08 — así que sus reglas de color por estado (--alta/--curso/--media/--ok) también se
   retiran de aquí: no queda ningún elemento que las use. */
/* Ni la carpeta ni el icono propio del encargo son ya un <i> suelto de color: los dos son la
   pastilla genérica .sl-icon-tile (ver más arriba) — a petición del usuario 2026-09-10. Por eso
   .sl-enc-side__state, --done y .sl-enc-side__icon desaparecen de aquí: no queda ningún
   elemento que las use. El color del icono propio viaja ahora por --sl-icon-tile-color, la
   variable de la pastilla, en vez de por el puente propio --sl-enc-side-icon. */
/* Las pills de reclamaciones (contador.reclamaciones.tpl con $pill_mode) van pegadas entre sí
   y como un solo bloque dentro de la fila, sin robarle sitio al nombre. */
#sl-app .sl-enc-side__row > .reclamaciones {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: none;
}
/* css/style.css:6848 (`.tabs-left > li a i`, (0,2,2)) le clava a CUALQUIER <i> de la fila
   font-size:19px y margin-right:4px. Le gana un id, sin !important: el glifo tiene que medir
   lo que diga su pastilla, no 19px dentro de una caja de 34, y la separación entre pastillas
   ya la pone el `gap` de la fila. */
#sl-app .sl-enc-side .sl-icon-tile > i { font-size: inherit; margin-right: 0; }
/* Sin recorte: el nombre nunca se corta con "…" — a petición del usuario 2026-09-08 ("no se
   puede quedar cortado el nombre del encargo"). flex:1/min-width:0 se quedan: siguen haciendo
   falta para que el nombre pueda ENCOGER (y así envolver en vez de empujar el número/las
   reclamaciones fuera de la fila) cuando no cabe entero en una línea. */
.sl-enc-side__name {
  flex: 1;
  min-width: 0;
  overflow-wrap: break-word;
  font: 600 13.5px/1.3 var(--sl-font);
  color: var(--sl-blue);
}
#sl-app .sl-enc-side > li.active .sl-enc-side__name { font-weight: 700; }
.sl-enc-side__num {
  flex: none;
  font: 700 12px/1 var(--sl-font);
  color: var(--sl-fg-3);
}
/* ⚠️ El número NO se centraba, y no era culpa del flex: css/style.css:7874 pinta
   .numero-encargo con `position:absolute; right:1px; bottom:0`, del diseño anterior en el que
   flotaba pegado a la esquina inferior de la fila. Al estar fuera del flujo, el
   align-items:center de .sl-enc-side__row nunca llegaba a tocarlo y quedaba abajo del todo,
   por debajo de las pills de reclamaciones. Aquí se devuelve al flujo — a petición del
   usuario 2026-09-10.
   El margin sobrante lo mete css/style.css:9422 con
   ".mega-design #sl-app #asunto span.numero-encargo", que es (2,2,1); de ahí que este
   selector lleve dos ids y tres clases (2,3,0) — con menos NO gana. */
#sl-app #asunto .sl-enc-side .sl-enc-side__row > .sl-enc-side__num {
  position: static;
  right: auto;
  bottom: auto;
  margin: 0;
  position: absolute;
  right: 2px;
  font-size: 25px;
  opacity: 0.1;
  z-index: 1;
  bottom: 2px;
}

/* --- Checklist del encargo (modules/asunto.encargo.panel.tarea.tpl) -------- */
/* Una fila por subtarea dentro de la tarjeta, con la misma divisoria de 1px que separa los
   .sl-panel__body. Antes cada fila era un .col-md-12 con márgenes inline y el <li> convivía con
   <div> sueltos colgando del <ul> (marcado inválido). */
.sl-tarea-lista {
  list-style: none;
  margin: 0;
  padding: 0;
}
.sl-tarea-fila {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .5rem .875rem;
  border-top: 1px solid var(--sl-border);
}
/* .tarea trae de css/style.css un "width:90%" pensado para cuando era el <li> de la rejilla de
   Bootstrap; aquí es un <span> dentro de un flex y el ancho lo reparte el propio flex. */
#sl-app .sl-tarea-fila > .tarea,
#sl-app .sl-tarea-fila > .tarea-no-hover {
  flex: 1;
  width: auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: .5rem;
  font: 600 .8125rem/1.4 var(--sl-font);
  color: var(--sl-blue);
}
#sl-app .sl-tarea-fila > .tarea:hover { text-decoration: line-through; }
/* Subtarea hecha. Sustituye al "text-decoration:line-through;opacity:50%" que tarea_completada()
   escribía en el style del <li> — y que además usaba como bandera de estado, comparando la cadena
   del atributo. Ahora el estado es esta clase y el JS solo la conmuta. */
#sl-app .sl-tarea-fila > .tarea.is-done {
  color: var(--sl-fg-3);
  text-decoration: line-through;
}
#sl-app .sl-tarea-fila > .tarea.is-done > i { color: var(--sl-green); }

/* --- Restos de ".sl-tsection" --------------------------------------------- */
/* Aquella "sección con tabla" (.sl-tsection + __head + __title + __title > i) desapareció
   cuando las tablas del encargo y del asunto comercial pasaron a ser tarjetas .sl-panel con
   cabecera plegable. Sus cuatro reglas se retiraron el 2026-09-11 tras comprobar 0 usos en
   marcado; si alguna vuelve a hacer falta, está en el historial de SVN.
   Sobreviven las dos piezas que NO eran de aquella sección sino genéricas de cabecera, y que
   valen igual dentro de un .sl-panel__header--row: __note (la nota de "Tipo por defecto") y
   __tools (el grupo de la derecha), definida más abajo. */
.sl-tsection__note {
  font: 500 12px/1.3 var(--sl-font);
  color: var(--sl-fg-2);
}
.sl-tsection__note strong { color: var(--sl-blue); }

/* Gráfico circular de "% de éxito" dentro de una celda de ficha (asunto comercial).
   Único uso en toda la app: asunto.info.tpl -> include de modules/porc_operacion.tpl.

   Aquí se fijan TAMAÑO y colocación, y hace falta hacerlo así porque el gráfico viene de
   style.css (2016), donde está maquetado con porcentajes encadenados pensados para tres
   gráficos en fila dentro de una caja ancha: .single-chart{width:33%} y
   .circular-chart{max-width:80%}. Dentro de una celda de ficha esos porcentajes se
   MULTIPLICAN entre sí, y encima la plantilla anida dos .single-chart (uno lo pone la celda
   de asunto.info.tpl y otro el propio include), así que el donut acababa midiendo
   39,6px (los 2.2rem que tenía esta regla) x 0,33 x 0,80 = 10,4px: un punto ilegible caído
   contra el borde izquierdo. Por eso se anulan los porcentajes y se da medida explícita.

   La celda ya no se estrangula a 2.2rem: ocupa su pista del grid de la ficha y es el donut
   el que se alinea a la derecha, centrado en vertical. */
#sl-app .sl-cell-chart {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  width: auto;
  padding-right: .5rem;
}
#sl-app .sl-cell-chart .single-chart {
  width: auto;
  flex: none;
}
#sl-app .sl-cell-chart .circular-chart {
  width: 2.5rem;
  height: 2.5rem;
  max-width: none;
  max-height: none;
  margin: 0;
}

/* Acciones de cierre de la ficha, alineadas a la derecha al final de la página */
.sl-asunto-footer-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--sl-space-4);
}
.date-muted {
  font-size: 11px;
  color: var(--sl-grey);
}

/* Grupo de la derecha en la cabecera de una tarjeta (el botón de "Nueva alerta"/"Nueva cita"…,
   la nota de "tipo por defecto", los avisos y el desplegable de acciones sobre partes marcados).

   Esta regla estaba DUPLICADA: existía otra ".sl-tsection__tools" con el mismo selector unos
   cientos de líneas más arriba, y las dos se pisaban propiedad a propiedad. Fusionadas el
   2026-09-11 conservando el resultado computado EXACTO que había, verificado en el navegador.

   EN UNA SOLA LÍNEA, sin envolver — decisión del usuario 2026-09-11.
   Hasta ese día este grupo sí envolvía, pero por accidente: la declaración duplicada de más
   arriba traía "flex-wrap: wrap" y la de aquí nunca lo anuló. Al fusionarlas se conservó para no
   cambiar nada, y después se retiró a propósito. No volver a añadirlo sin mirar antes la cabecera
   de "N partes de trabajo", que es la más cargada: nota de "Tipo por defecto" + aviso de encargo
   finalizado + desplegable de partes marcados. Si ahí llegara a desbordar, la salida NO es
   reponer el wrap sino acortar o esconder la nota, que es lo prescindible.

   "inline-flex" es inerte en el uso actual: el padre (.sl-panel__header--row) es un contenedor
   flex y CSS blockifica a sus hijos, así que computa "flex". Se deja por si algún día este grupo
   cuelga de un padre que no lo sea. */
.sl-tsection__tools {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  flex: none;
  flex-wrap: nowrap;
}
/* Botonera de acciones de cada fila de las tablas del encargo (citas, partes, llamadas…):
   siempre en horizontal y pegada a la derecha. Con .text-right a secas los botones son
   inline-flex y, en una celda estrecha, envolvían en columna — pasaba en "Citas", cuya fila
   lleva cuatro y salían apilados, estirando la fila a cuatro veces su alto.
   El :has(> .sl-btn) es lo que acota la regla a los contenedores que REALMENTE son una
   botonera: ".text-right" a secas es una clase de utilidad de Bootstrap que hay por toda la
   app y que no siempre envuelve botones. */
#sl-app .sl-panel .text-right:has(> .sl-btn),
#sl-app .sl-panel [data-encargo-id].text-right {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: .25rem;
  flex-wrap: nowrap;
}
.etiquetas-encargo {
  display: inline-flex;
  gap: 5px;
  width: fit-content;
}
/* Contenedor de components/etiquetas.tpl — mismo layout que ".etiquetas-encargo" de arriba
   (que se deja tal cual: la siguen usando modules/asuntos.encargos_mode.tpl y
   asuntos_comerciales.tpl con su propio marcado suelto, sin pasar por el componente). Nombre
   neutro porque este componente pinta etiquetas tanto de asunto como de encargo. */
.sl-etiquetas-lista {
  display: inline-flex;
  gap: 5px;
  width: fit-content;
}
div[onclick] {
  cursor: pointer;
}
/* --- Responsive ---------------------------------------------------------- */
/* La ficha ya es responsive por sí sola: .sl-panel__body es flex con wrap y
   .sl-ficha-field-group lleva min-width:0, así que las filas de celdas se
   reparten y envuelven sin media queries. Solo el título necesita bajar de
   tamaño en pantalla estrecha. */
@media (max-width: 767px) {
  .sl-ficha-header__title { font-size: 18px; }
}

/* ——— 17. Footer de aplicación (barra inferior del cuerpo) ——————————————
   Última fila de #main-content, justo debajo de la tarjeta que scrollea
   (section.wrapper): se ve siempre porque el cuerpo es una columna flex donde
   la .wrapper se queda con el espacio libre y esta barra con su altura fija
   (ver mega-design.css). Logo centrado y, a la derecha, versión + carga.

   Sin position:fixed y sin z-index a propósito: al vivir DENTRO del flujo del
   cuerpo no puede tapar contenido ni ser tapada por el sidebar, que es otra
   columna del grid del shell. Ese era justo el problema de la primera versión,
   fija al viewport: obligaba a encoger el shell a mano para reservarle sitio.

   Solo la pinta el layout principal (layout/base.tpl pasa sticky=true al
   include de modules/debug.footer.tpl). El login, la vista de impresión y
   base_clean.tpl siguen con el footer antiguo, dentro de su contenido.        */
.sl-appfooter {
  flex: 0 0 auto;
  box-sizing: border-box;
  height: var(--sl-appfooter-h);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--sl-space-3);
  padding: 0 14px;
  background: white;
  border-top: 1px solid var(--sl-border);
  font-family: var(--sl-font);
  color: var(--sl-fg-3);
  border-bottom-left-radius: var(--sl-radius-card);
  border-bottom-right-radius: var(--sl-radius-card);
}
.sl-appfooter__logo { grid-column: 2; display: flex; align-items: center; }
.sl-appfooter__logo img { display: block; height: 24px; width: auto; }
.sl-appfooter__info {
  grid-column: 3;
  justify-self: end;
  text-align: right;
  line-height: 1.3;
}
/* nowrap: son dos líneas de una sola línea cada una; si envolvieran, no
   cabrían en los 40px de la barra y se saldrían por abajo. */
/* font-weight explícito y no heredado: sin esto las dos líneas salían igual de
   gruesas que el dato resaltado y se perdía la jerarquía. */
.sl-appfooter__line { font-size: .6875rem; font-weight: 500; color: var(--sl-fg-2); white-space: nowrap; }
.sl-appfooter__line--soft { font-size: .625rem; color: var(--sl-fg-3); }
.sl-appfooter__hl { color: var(--sl-fg-1); font-weight: 700; }
.mega-design #main-content>.wrapper {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
/* Pantallas estrechas: el bloque de la derecha se queda sin sitio antes que
   el logo, así que se esconde el detalle técnico (la línea "Carga: ...") y
   se conserva la versión, que es el dato que se pide en soporte. */
@media (max-width: 767px) {
  .sl-appfooter__line--soft { display: none; }
}
/* --- Contrato de layout que necesita la barra --------------------------------
   .sl-appfooter es la última fila de #main-content, así que el cuerpo tiene que
   ser una columna flex: la .wrapper (la tarjeta blanca, que es quien scrollea)
   se queda con el espacio libre y la barra con su altura fija.

   Estas dos reglas son de app-shell y "deberían" vivir en mega-design.css, pero
   ESE ARCHIVO VA DENTRO DE css/crunch/compiled.css (ver crunch-css-js.bat): un
   cambio allí no llega al navegador hasta rebuildear el bundle. softline-ui.css
   se carga por <link> propio y DESPUÉS de compiled.css, así que aquí ganan por
   orden de cascada sin build. De paso quedan pegadas al componente que las
   necesita: si algún día se quita la barra, se van con ella.

   Los dos selectores de layout se repiten enteros para EMPATAR en especificidad
   con las reglas de .wrapper de mega-design.css (1 id + 3 clases) y ganar por
   orden; con un selector más corto perdería y el height:100% dejaría al footer
   fuera del overflow:hidden del cuerpo. */
.mega-design > #main-content {
  display: flex;
  flex-direction: column;
}
.mega-design.menu-vertical #main-content > .wrapper,
.mega-design.menu-horizontal #main-content > .wrapper {
  flex: 1 1 auto;
  height: auto;     /* anula el height:100% de mega-design.css */
  min-height: 0;    /* deja que scrollee dentro del flex en vez de crecer */

  /* El canal de la barra de scroll se reserva SIEMPRE, haya barra o no.
     ----------------------------------------------------------------------
     La .wrapper es quien scrollea (overflow-y:auto, arriba), así que su barra
     aparece o no según lo ALTO que sea el contenido — o sea, en un listado,
     según CUÁNTOS RESULTADOS devuelva el filtro. Eso le quita 15px de ancho a
     todo lo de dentro, incluido el panel de filtros.

     Y el panel de filtros es una rejilla `repeat(auto-fit, minmax(140px,1fr))`
     con las celdas auto-colocadas (filtros-grid.css), de modo que su número de
     columnas se deriva del ancho: 15px de menos pueden significar una columna
     de menos y, con ella, que el último filtro de la primera fila se vaya a la
     segunda. Resultado: el NÚMERO DE RESULTADOS decidía la maquetación de los
     filtros, y cambiar de representante movía de sitio el filtro de Naturaleza.

     Medido en /comerciales con una ventana de 2415px (r7106): sin barra la
     rejilla mide 1388px -> 9 columnas -> Naturaleza en la 1ª fila; con barra
     mide 1373 -> 8 columnas -> Naturaleza baja a la 2ª. El umbral está en 1380,
     o sea justo dentro de los 15px que mueve la barra.

     Reservando el canal, el ancho es el mismo en ambos casos y la rejilla deja
     de depender del resultado de la consulta. Aplica a los seis listados.

     OJO: esto NO garantiza que un filtro concreto caiga en una fila concreta —
     eso sigue dependiendo del ancho de la ventana, como en cualquier rejilla
     responsive. Lo que garantiza es que no se MUEVA solo al filtrar.

     Va aquí y no en mega-design.css por el mismo motivo que las dos reglas de
     arriba: ese archivo viaja dentro de css/crunch/compiled.css y un cambio
     allí no llega al navegador sin rebuildear el bundle. */
  scrollbar-gutter: stable;
}
ul.sidebar-menu li.user-dropdown a, .white-bg {
  border-bottom: 0;
}
.mega-design #sl-app #asunto section#encargos {
  width: 100%;
  margin: 0;
}
#encargos-sidebar.tabs-left {
  border-right: 0;
}
.encargo-acciones>#encargo-edit, .encargo-acciones .boton-mover-encargo>button {
  min-width: auto;
}
/* ——— 18. Ficha (dialog.ficha.tpl) como panel lateral ——————————————————————
   La ficha de cualquiera de los cinco tipos (asunto, encargo, parte, parte comercial, llamada)
   se abre como un panel flotando a la derecha, con overlay más claro que el habitual — a
   petición del usuario 2026-08-31.

   ⚠️ Estas reglas vivían en el <style> de smarty/templates/asuntos.tpl y se movieron aquí el
   2026-09-11, por el MISMO motivo por el que ver_ficha() se movió de asuntos.tpl.js a
   common.tpl.js: el id-badge que abre la ficha está ahora en seis listados, y en los otros
   cinco la ficha salía como una modal centrada corriente porque la regla no existía en esa
   página. softline-ui.css lo carga layout/head.tpl en todas.

   Lo que NO cambia: siguen sin poder vivir dentro de dialog.ficha.tpl. Ese archivo es el BODY
   que llega por AJAX, así que su <style> no está en el DOM hasta que la carga termina; la clase
   .sl-ficha-drawer se añade en el callback onDialogShow, que dispara ANTES de pedir el body, y
   de nada sirve poner la clase pronto si la regla que le da significado llega tarde (se veía
   como un parpadeo: el diálogo nacía centrado y con su tamaño por defecto, y luego saltaba). */
.sl-ficha-drawer.modal-dialog {
  position: fixed;
  top: 1rem; right: 1rem; bottom: 1rem;
  left: unset;
  margin: 0;
  width: 28rem;
  max-width: calc(100vw - 2rem);
  /* auto, NO un valor fijo (ej. 100vh): con top Y bottom fijados, "auto" hace que el navegador
     calcule la altura para que el panel encaje exactamente entre los dos (el mismo truco que
     "inset"), en vez de desbordar por debajo del viewport. */
  height: auto;
}
.sl-ficha-drawer.modal-dialog .bootstrap-dialog-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.sl-ficha-drawer.modal-dialog .modal-content {
  height: 100%;
  border-radius: var(--sl-radius-lg);
  display: flex;
  flex-direction: column;
  box-shadow: 0 8px 32px rgba(0, 0, 0, .18);
}
.sl-ficha-drawer.modal-dialog .modal-body {
  flex: 1 1 auto;
  overflow-y: auto;
  /* !important porque lib-bootstrap-dialog.generic.tpl.js pinta el gif de "cargando" como
     background INLINE (dBody.css(...)) mientras espera el AJAX del body — sin esto, ese gif
     sale centrado y solo en medio de un panel alto y casi vacío (se ve peor aquí que en un
     modal centrado pequeño, que es a lo que estaba pensado). Panel en blanco un instante en
     vez de un gif flotando: una vez llega el contenido, esto deja de importar. */
  background: #fff !important;
}
/* Contador (no bool) porque una ficha puede abrir otra encima (asunto → sus encargos → "Del
   asunto A..." de vuelta): el backdrop debe seguir claro mientras quede AL MENOS una ficha
   abierta, y solo devolver la oscuridad normal cuando se cierra la última. */
body.sl-ficha-open > .modal-backdrop.in {
  opacity: .18 !important;
}
.mega-design.menu-vertical #sidebar.menu-azul>ul.sidebar-menu>li>a {
  display: flex;
  align-items: center;
  gap: 10px;
}
/* ── Alto de fila del menú lateral: uniforme, y el MISMO en los dos estados ───────────────────
   Todas las filas miden lo que la más alta, tanto con el menú abierto como colapsado. Es lo que
   hace que contraer/expandir no mueva NADA en vertical: solo se desvanece el texto y cambia el
   ancho. Usuario 2026-09-21, con el efecto emulado y medido.

   Antes cada fila encogía una cantidad DISTINTA al colapsar, y ese era el salto:

       Clientes, Partes, Visitas…   51px -> 32px   (-19)
       Asuntos Comerciales           71px -> 32px   (-39)   <- dos líneas de texto
       Partes Comerciales            71px -> 32px   (-39)
       Usuarios y Rptes.             71px -> 32px   (-39)
       (logo)                      64,5px -> 52,4px (-12)   <- cambia de imagen

   Al encoger cada una lo suyo, todo lo que quedaba por debajo se recolocaba a velocidades
   distintas. La transición lo suavizaba, pero el recorrido seguía estando ahí.

   De dónde sale el 71: es el alto natural de una fila de DOS líneas — 2 x 20px de line-height
   más 15px+15px de padding, y 1px de redondeo del propio navegador. Va en px y no en rem porque
   es una medida de layout de este menú, como el 56px de su columna en el grid, no un tamaño
   tipográfico que deba escalar con la raíz.

   El logo entra en la misma regla a propósito: es la única fila que además cambia de imagen
   (wordmark de 44,5px -> marca compacta de 32,4px) y sin esto seguía dando un salto de 12px él
   solo, justo en la esquina donde más se mira.

   Medido después: el menú completo NO crece por esto (sigue en 1224px de alto) y el salto de las
   17 filas pasa a ser exactamente 0.

   ⚠️ Esto NO sustituye al max-height:0 del wrapper .sidebar-menu-extra (mega-design.css): aquel
      sigue haciendo falta para recortar el texto: lo que deja de importar es su efecto sobre el
      ALTO, que era el que producía el salto. */
.mega-design.menu-vertical #sidebar > ul.sidebar-menu > li > a {
  /* sl-sidebar-alto-fila */
  min-height: var(--sl-menu-fila, 71px);
}

/* Modo fluido (sidebar reducido a solo iconos, ver mega-design.css): más alto y con el
   icono centrado en horizontal. SOLO aquí — en el menú expandido el link sigue siendo
   icono+texto alineados a la izquierda con la regla de arriba, sin tocar.
   ⚠️ padding:27px (probado primero) desbordaba el sidebar con ~15 items: cada link pasa
   a medir ~27*2+icono ≈ 78px, y 15-16 de esos ya no caben en 100vh — el sobrante quedaba
   recortado por el overflow:hidden del grid (mega-design.css), es decir enlaces que
   seguían ahí pero ya no se podían ni ver ni pulsar. 16px encajaba mejor con la cantidad
   de items real, pero DEJAR que sea el padding+contenido quien decida el alto todavía
   deja un par de px de diferencia entre items con badge (.alerta-small mide 18px) y sin
   badge: el <a> es flex/align-items:center, así que se estira a la altura de su hijo más
   alto, y ese hijo varía según si hay badge o no aunque esté clipeado a 0 de ancho.
   Un height:56px fijo aquí "arreglaba" eso, pero a costa de crear un salto de alto al
   entrar o salir de este estado. Desde el 2026-09-21 la altura uniforme la da el
   min-height de fila de más arriba, que además vale para los DOS estados y es lo que
   hace que colapsar no mueva nada; el .sidebar-menu-extra { height:0 } de
   mega-design.css se queda para recortar el texto, no para decidir el alto. */
.mega-design.menu-vertical.sidebar-fluido #sidebar.menu-azul>ul.sidebar-menu>li>a {
  /* MISMO padding vertical que en expandido, y 0 en horizontal (el icono va centrado).
     Antes era 26px en las cuatro esquinas: con el icono dentro sumaba 72px, asi que el
     estado colapsado media 1px MAS que el expandido, que es justo lo que el min-height
     uniforme viene a evitar. Compartiendo la variable, los dos no pueden separarse. */
  padding: var(--sl-menu-pad-y, 15px) 0;
  justify-content: center;
  gap: 0;
}

/* Flecha de los items con desplegable, siempre pegada al borde derecho. Usuario 2026-09-23: cada
   una acababa donde acababa su label. style.css le pone float:right, pero dentro de
   .sidebar-menu-extra (inline-flex) un float no hace nada, así que se quedaba al lado del texto.
   El wrapper pasa a ocupar todo el ancho libre del <a> y la flecha se empuja al final con
   margin-left:auto; el margin-right:8px de style.css se anula para que llegue al máximo (el
   padding del propio <a> ya la separa del borde). min-width:0 deja que el label siga
   partiéndose en dos líneas en vez de ensanchar el wrapper.
   En modo fluido no molesta: el wrapper tiene max-width:0 y se recorta entero. */
.mega-design.menu-vertical #sidebar > ul.sidebar-menu > li > a > .sidebar-menu-extra {
  flex: 1 1 auto;
  min-width: 0;
}
.mega-design.menu-vertical #sidebar > ul.sidebar-menu > li > a > .sidebar-menu-extra > .menu-arrow {
  margin-left: auto;
  margin-right: 0;
}

/* Modo fluido: centrar por PADDING, no por justify-content. Usuario 2026-09-23 ("más suave, sin
   la pausa"). justify-content no se puede animar: con la regla de arriba el icono saltaba al
   centro en el primer frame mientras la columna aún medía 200px, y luego se deslizaba con ella.
   Un padding-left sí se anima, con la misma duración y curva que la columna (tokens
   --sl-sidebar-* de mega-design.css), así que icono y columna llegan a la vez.

   El valor es el que centra la caja del icono en el riel: el <i> es border-box de 1.25em
   (fa-fw) y en este estado ya no lleva su padding-right de 6px, así que mide
   1.25 × --sl-menu-icono. En el tramo grande sale 15.5px contra los 15px de expandido: el
   icono prácticamente no se mueve, se estrecha la columna a su alrededor. En los tramos
   compactos pad-x baja a 10-12px y ahí sí se desliza unos px hasta el centro.

   Ni el logo ni el bloque de usuario entran aquí: el logo intercambia imagen, y el bloque de
   usuario se centra por el tamaño de su FOTO, no del icono (regla siguiente). */
.mega-design.menu-vertical.sidebar-fluido #sidebar.menu-azul>ul.sidebar-menu>li:not(.sidebar-logo):not(.user-dropdown)>a {
  justify-content: flex-start;
  padding-left: calc((var(--sl-sidebar-riel, 56px) - 1.25 * var(--sl-menu-icono, 20px)) / 2);
}
.mega-design.menu-vertical.sidebar-fluido #sidebar.menu-azul>ul.sidebar-menu>li.user-dropdown>a {
  justify-content: flex-start;
  padding-left: calc((var(--sl-sidebar-riel, 56px) - var(--sl-menu-foto, 34px)) / 2);
}
.mega-design.menu-vertical.sidebar-fluido #sidebar.menu-azul>ul.sidebar-menu>li>a>.sidebar-menu-label{
  display: none;
}
.mega-design.menu-vertical.sidebar-fluido #sidebar.menu-azul>ul.sidebar-menu>li>a>i{
  display: flex;
  justify-content: center;
  align-content: center;
}

/* ══ Menú lateral: que quepa siempre y, cuando no quepa, que se pueda desplazar ═══════════════
   Usuario 2026-09-22. Con 17 filas de 71px el menú mide 1224px CLAVADOS, así que necesitaba una
   pantalla de ~1250px de alto para verse entero. Por debajo de eso no se recortaba "un poco":
   medido a 760px de alto, quedaban SEIS entradas inalcanzables — Usuarios y Rptes., Configuración,
   Herramientas, Comunicación, Sobre INTRA LINE y el bloque de usuario, o sea también "Cerrar
   sesión". No había scroll en ninguna de las tres cajas del menú, de modo que lo que sobraba lo
   cortaba el overflow:hidden del grid y desaparecía sin dar ninguna señal.

   Se ataca por los dos lados, en este orden:

     1. COMPACTAR por tramos de altura, para que en la mayoría de pantallas siga cabiendo entero
        y no haya que desplazar nada (ver los tokens justo debajo).
     2. SCROLL como red de seguridad, para las pantallas muy bajas y para los usuarios con más
        entradas de las 17 de referencia — el número de items depende del nivel, así que ningún
        juego de tamaños puede garantizar que quepa SIEMPRE.

   El punto 2 arrastra el problema que explica por qué esto no se había hecho antes: en CSS no
   existe "scroll vertical con desbordamiento horizontal visible". Si un eje es auto y el otro
   visible, el navegador COMPUTA ese visible a auto. Y el submenú es un flyout (left:100%) que
   vive fuera del ancho del sidebar: al activar overflow-y quedaba recortado asomando 15px de sus
   211px, con una barra horizontal absurda. Por eso #sidebar lleva su overflow:visible !important
   con ese comentario en mega-design.css. La salida está en el bloque 3, más abajo. */

/* ── 1. Tokens de tamaño del menú, por tramos de ALTURA de pantalla ───────────────────────────
   TODO el tamaño del menú sale de aquí: alto de fila, padding, tipografía, icono, logo y foto.
   Compactar es cambiar estos números, no tocar reglas.

   Por qué UN solo juego de variables y no dos: el alto de fila tiene que ser el MISMO colapsado
   que expandido (petición del usuario; es lo que hace que contraer no mueva nada en vertical).
   Eso se cumple mientras el min-height mande, es decir mientras ningún contenido lo desborde, y
   quien puede desbordarlo es distinto en cada estado:

       expandido → el texto de DOS líneas   2 × --sl-menu-lh    + 2 × --sl-menu-pad-y
       colapsado → el icono                     --sl-menu-icono + 2 × --sl-menu-pad-y

   Compartiendo las variables, los dos estados no pueden separarse por descuido. Cada tramo se
   calcula dejando ambos por DEBAJO de --sl-menu-fila, con un par de px de margen:

       tramo      fila   2 líneas + padding   menú entero   viewport que necesita
       ──────────────────────────────────────────────────────────────────────────
       ≥1249px     71      40 + 30 = 70 ✓         1224px               1248
       ≤1248px     58      36 + 20 = 56 ✓         1053px               1077
       ≤1076px     50      32 + 16 = 48 ✓          903px                927
       ≤ 926px     44      30 + 12 = 42 ✓          750px                774

   Los cortes son exactamente la altura a la que el tramo anterior deja de caber, así que el menú
   se compacta justo cuando hace falta y ni un píxel antes. Por debajo de 774px ya no hay tramo
   que valga: ahí entra el scroll del bloque 2.

   La columna "menú entero" está MEDIDA, no calculada: 17 x fila se queda corto porque el logo y
   el bloque de usuario no se ciñen al min-height y el ul suma bordes. Calcular en vez de medir
   dejaba los cortes ~65px optimistas, o sea una franja de alturas con scroll innecesario.

   Están calibrados con el menú MÁS LARGO (nivel 9, 17 entradas). Un usuario con menos entradas
   cabe de sobra en cualquier tramo; uno con más se apoya en el scroll, que para eso está.

   Van en px y no en rem por el mismo motivo que el 71 original: son medidas de layout de este
   menú —como los 200px de su columna en el grid— y no tipografía que deba escalar con la raíz. */
.mega-design.menu-vertical {
  --sl-menu-fila:   65px;
  --sl-menu-pad-y:  15px;
  --sl-menu-pad-x:  15px;
  --sl-menu-fuente: 16px;
  --sl-menu-lh:     20px;
  --sl-menu-icono:  20px;
  --sl-menu-logo:   44px;   /* max-height del logo (lleva su propio padding, menor) */
  --sl-menu-foto:   34px;   /* foto del bloque de usuario */
}
@media (max-height: 1248px) {
  .mega-design.menu-vertical {
    --sl-menu-fila: 58px; --sl-menu-pad-y: 10px; --sl-menu-pad-x: 12px;
    --sl-menu-fuente: 14px; --sl-menu-lh: 18px; --sl-menu-icono: 18px;
    --sl-menu-logo: 38px; --sl-menu-foto: 32px;
  }
}
@media (max-height: 1076px) {
  .mega-design.menu-vertical {
    --sl-menu-fila: 50px; --sl-menu-pad-y: 8px; --sl-menu-pad-x: 10px;
    --sl-menu-fuente: 13px; --sl-menu-lh: 16px; --sl-menu-icono: 16px;
    --sl-menu-logo: 32px; --sl-menu-foto: 30px;
  }
}
@media (max-height: 926px) {
  .mega-design.menu-vertical {
    --sl-menu-fila: 44px; --sl-menu-pad-y: 6px; --sl-menu-pad-x: 10px;
    --sl-menu-fuente: 12px; --sl-menu-lh: 15px; --sl-menu-icono: 15px;
    --sl-menu-logo: 28px; --sl-menu-foto: 28px;
  }
}

/* El logo y la foto de usuario son IMÁGENES: no las encoge el padding, hay que decirles el alto,
   o esas dos filas se quedarían grandes mientras el resto compacta. max-height y no height a
   propósito — con width:auto conservan proporción y nunca se pasan del tope, que es lo único que
   el alto de fila necesita garantizar. El logo lleva su propio padding, menor que el de los
   items porque ocupa el ancho completo del sidebar. */
.mega-design.menu-vertical #sidebar .sidebar-menu li.sidebar-logo a.logo-home-link {
  padding: calc(var(--sl-menu-pad-y, 15px) - 5px) 10px;
}
/* Expandido: 20px a los lados para que la pastilla de colapsar (.sl-sidebar-fluid-toggle, montada
   sobre el borde derecho a esta altura) no pise el wordmark. Solo aquí: en modo fluido el sidebar
   mide 56px y con 20px por lado la marca compacta se quedaría en 16px. */
.mega-design.menu-vertical:not(.sidebar-fluido) #sidebar .sidebar-menu li.sidebar-logo a.logo-home-link {
  padding-left: 20px;
  padding-right: 20px;
}
.mega-design.menu-vertical .sidebar-menu li.sidebar-logo img {
  max-height: var(--sl-menu-logo, 44px);
  width: auto;
}
.mega-design.menu-vertical #sidebar .user-dropdown .username img {
  height: var(--sl-menu-foto, 34px) !important;
  width: var(--sl-menu-foto, 34px);
}
/* El logo de empresa (solo modo CRM) se apila ENCIMA de la foto dentro de la misma fila, así que
   escala con ella o esa fila crecería por su cuenta y rompería la uniformidad. */
.mega-design.menu-vertical #sidebar .user-dropdown .sidebar-user-logo {
  max-height: var(--sl-menu-foto, 34px);
  margin-bottom: calc(var(--sl-menu-pad-y, 15px) / 2);
}

/* ── 2. El scroll ─────────────────────────────────────────────────────────────────────────────
   Va en el UL y no en #sidebar: ese conserva su overflow:visible (lo necesita el flyout, ver
   bloque 3) y además es quien pinta el fondo y la sombra de la tarjeta, que no deben desplazarse
   con el contenido. El ul ya estaba preparado para esto sin saberlo — es flex:1 1 auto con
   min-height:0, así que ya se encogía al alto disponible; sencillamente no tenía por dónde sacar
   lo que le sobraba (medido: clientHeight 713 contra scrollHeight 1224).

   overflow-x:hidden es explícito y no accidental: al poner overflow-y:auto el navegador lo
   computaría a auto de todas formas, y entonces aparecía barra horizontal. */
.mega-design.menu-vertical #sidebar > ul.sidebar-menu {
  overflow-y: auto;
  overflow-x: hidden;
  /* Barra fina y discreta: la columna mide 200px y una de 15px se come un 7% del ancho útil del
     menú. Sin scrollbar-gutter:stable a propósito — reservaría el canal SIEMPRE, y en las
     pantallas donde el menú cabe entero (que ahora son la mayoría) se vería descentrado sin
     motivo. Las dos formas conviven: la estándar la entiende Chrome 121+, ::-webkit- cubre lo
     anterior. */
  scrollbar-width: thin;
  scrollbar-color: var(--sl-blue-100, #cfe0f2) transparent;
}
.mega-design.menu-vertical #sidebar > ul.sidebar-menu::-webkit-scrollbar { width: 6px; }
.mega-design.menu-vertical #sidebar > ul.sidebar-menu::-webkit-scrollbar-track { background: transparent; }
.mega-design.menu-vertical #sidebar > ul.sidebar-menu::-webkit-scrollbar-thumb {
  background: var(--sl-blue-100, #cfe0f2);
  border-radius: 3px;
}
.mega-design.menu-vertical #sidebar > ul.sidebar-menu::-webkit-scrollbar-thumb:hover {
  background: var(--sl-blue, #034d96);
}

/* ── 3. El flyout, fuera del contenedor que scrollea ──────────────────────────────────────────
   A un position:fixed no lo recorta el overflow de sus ancestros, así que el submenú vuelve a
   poder salirse del sidebar. El precio es que fixed se posiciona respecto al VIEWPORT y no
   respecto a su item, o sea que las coordenadas ya no puede ponerlas CSS: las calcula
   phastardMenuFlyout() en menu.tpl al pasar el ratón.

   Por eso la regla se activa con .js-flyout-fixed, una clase que pone ese mismo JS al arrancar:
   si no llegara a ejecutarse, el flyout se queda como estaba (absolute, recortado por el scroll)
   en lugar de aparecer suelto en una esquina de la pantalla. Es la degradación menos mala.

   El resto del aspecto —fondo, borde, sombra, max-height, min-width— sigue viniendo de
   mega-design.css; aquí solo cambia de qué depende su posición. */
.mega-design.menu-vertical #sidebar.js-flyout-fixed .sidebar-menu li.sub-menu > ul.sub {
  position: fixed;
  left: auto;      /* las pone el JS */
  top: auto;
  bottom: auto;
}
button.btn_add_textarea {
  height: unset;
  padding: .3rem;
  line-height: 1;
}

/* Rótulo flotante (.label-header-sup) que lleva dentro los botones de btn.add.texto.textarea.tpl,
   SOLO en diálogos. style.css lo ancla por ARRIBA (top:-13px), una medida pensada para un rótulo
   de 11px de alto; con los botones de arriba mide ~24px y su mitad inferior se montaba sobre el
   borde del textarea. Anclándolo por ABAJO (bottom:100%) su base queda justo encima de la caja
   mida lo que mida. Cabe en el hueco que ya dejan las filas de los diálogos (25px medidos en
   dialog.encargo.edit.tpl), así que no desplaza nada.

   Scopeado a .modal a propósito: el mismo include se usa fuera de diálogos (asunto.panel.notas.tpl)
   con otra maquetación, y ahí no debe cambiar. Las modales de bootstrap-dialog viven fuera de
   #sl-app, por eso el prefijo es .modal y no #sl-app. */
.modal label.label-header-sup:has(> button.btn_add_textarea) {
  top: auto;
  bottom: 100%;
  margin-top: 0;
  margin-bottom: 0;
}

/* PAGINA ABOUT */
.mega-design #sl-app .panel.sl-panel-flush {
  height: 64.2vh;
  display: flex;
  justify-content: center;
  align-items: center;
}
.mega-design #sl-app.about .about-sl {
  position: relative;
}
.mega-design #sl-app.about .about-sl::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-image: url(../img/about/sl-acerca-de.png);
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  opacity: 0.1; /* Opacity applies ONLY to the image */
  z-index: 0; /* Keeps the background behind content */
  pointer-events: none; /* Prevents pseudo-element from blocking clicks */
  filter: blur(0px) brightness(100%);
}
/* Ensures child elements sit above the background pseudo-element */
mega-design #sl-app.about .about-sl > * {
  position: relative;
  z-index: 1;
}
/* FIN PAGINA ABOUT */
table#list-table>tbody>tr:last-child {
  border-bottom: 0;
}
/* --- Resaltado de coincidencias de búsqueda en títulos de listado ---------
   Pintado por JS (sl_highlight_search_terms(), modules/js/asuntos.tpl.js),
   que envuelve cada aparición literal de las palabras buscadas dentro de
   #list-table .no_romper_fkg_tabla (título de asunto/encargo) en un
   <span class="highlight-search">. Fondo ámbar suave vía color-mix (mismo
   mecanismo que .sl-generic-pill--tag en filtros-grid.css) en vez de un
   color plano, para no tapar el color de fondo que ya lleve la celda/fila
   debajo (p.ej. la columna ID, con su propio $color por fila). */
.highlight-search {
  background: var(--sl-highlight-bg);
  border-radius: .15rem;
  padding: 0 .1rem;
  font-weight: 700;
}
/* Pill "Buscando" del resumen de búsqueda (asuntos.resumen.busqueda.tpl, [data-sl-highlight]
   pasado vía $pill_extra_attrs): MISMO --sl-highlight-bg que .highlight-search de arriba, para
   que la pill "avise" del color exacto con el que luego aparece marcada la palabra en la tabla
   — a petición del usuario, 2026-09-25. Sube el fondo del 12% de .sl-generic-pill--tag (su mezcla
   por defecto) al 45% de --sl-highlight-bg; gana por especificidad (clase+atributo > clase sola),
   sin !important.
   ⚠️ color:inherit es querido, no un descuido: la primera versión dejaba el TEXTO en
   --sl-generic-pill-color (pill_color="var(--sl-amber)", igual que el borde) encima de este
   mismo fondo al 45% — ámbar sobre ámbar, ilegible, y además distinto de .highlight-search (que
   NUNCA toca el color del texto, solo el fondo). Corregido a petición del usuario, 2026-09-25:
   el texto hereda el color normal del párrafo, IGUAL que en la tabla; solo el borde se queda
   ámbar (pill_color sigue puesto para eso). */
.sl-generic-pill--tag[data-sl-highlight] {
  background: var(--sl-highlight-bg);
  color: inherit;
}
/* ============================================================================
   §16 - TARJETA "RESULTADOS / ACCIONES RAPIDAS" (.sl-resumen-actividad)
   ----------------------------------------------------------------------------
   La tarjeta azul que acompana a los filtros en los listados. La incluyen CINCO
   plantillas, una por listado:

       modules/asuntos.resumen.actividad.tpl
       modules/asuntos_comerciales.resumen.actividad.tpl
       modules/llamadas.resumen.actividad.tpl
       modules/partes.resumen.actividad.tpl
       modules/partes_comerciales.resumen.actividad.tpl

   Hasta el 2026-09-15 estas reglas vivian DUPLICADAS en el <style> inline de
   cada una de las cinco -hasta 5 copias literales de la misma regla-, y cada
   archivo llevaba un comentario explicando que se duplicaban "a proposito"
   porque la variante del aviso rojo no era igual en todas las paginas. Ese
   motivo no se sostenia: la unica diferencia real era DONDE se coloca el aviso,
   y eso es un modificador (--inline), no una razon para copiar la hoja entera.

   Reparto de responsabilidades a partir de ahora:
     - Lo comun (esto) vive AQUI y solo aqui.
     - Lo que de verdad varia por pagina se queda como override local en su
       .tpl. Hoy es UNA sola cosa: el height:100% del wrapper en partes.

   Nota de especificidad, porque es lo que hacia arriesgado el movimiento:
   pasar estas reglas de un <style> del <body> a esta hoja NO cambia quien gana.
   ".sl-resumen-actividad__actions .sl-btn" es 0-2-0 y sigue ganando al ".sl-btn"
   base (0-1-0) por ESPECIFICIDAD, no por orden de carga. Y ninguna otra hoja
   declara reglas sobre .sl-resumen-actividad*, incluida filtros-grid.css, que
   carga DESPUES de esta (head.tpl: 253 -> 256) y solo la menciona en un
   comentario. Si algun dia filtros-grid.css declara algo sobre esta tarjeta con
   la misma especificidad, ganaria ella: comprobarlo antes.
   ============================================================================ */

.sl-resumen-actividad__resumen {
  background: var(--sl-blue-050);
  border: 1px solid var(--sl-border);
  border-radius: var(--sl-radius-card);
  padding: .875rem;
  height: 100%;
  box-sizing: border-box;
}

/* --- Layout en columnas (modules/asuntos.resumen.actividad.tpl) -----------
   Por defecto ".sl-resumen-actividad__cols" y sus ".sl-resumen-actividad__col"
   son <div> sueltos sin ninguna regla propia: se apilan en el flujo normal del
   documento, exactamente como esta tarjeta se ha visto siempre (secciones en
   fila, separadas por ".separator"). SOLO cuando el padre lleva el modificador
   "--cols" pasan a ser columnas de un flex — se activa a petición del usuario
   cuando la tarjeta ocupa el ancho completo de la fila (sin la rejilla de
   filtros al lado, ver .sl-filtros-resumen-row__resumen--full en
   filtros-grid.css): con ese ancho de sobra, apilar 3-4 secciones solo suma
   alto sin necesidad.
   El borde entre columnas sustituye a los ".separator" horizontales de la
   variante en filas — el propio .tpl deja de pintarlos en modo columnas, así
   que no hay que ocultarlos aquí por CSS. Mismo gris que ".separator"
   (var(--sl-border-3)) para que sea el mismo lenguaje visual, solo que
   vertical. "align-items" se deja en el valor por defecto (stretch) a
   propósito: así el borde de cada columna llega hasta abajo aunque las
   columnas vecinas tengan distinta altura de contenido. */
.sl-resumen-actividad__resumen--cols .sl-resumen-actividad__cols {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
}
.sl-resumen-actividad__resumen--cols .sl-resumen-actividad__col {
  flex: 1 1 0;
  min-width: 190px;
}
.sl-resumen-actividad__resumen--cols .sl-resumen-actividad__col:not(:first-child) {
  padding-left: 1.25rem;
  border-left: 1px solid var(--sl-border-3);
}

/* --- Contadores ----------------------------------------------------------- */
.sl-resumen-actividad__stats {
  display: flex; gap: .5rem;
  margin-bottom: .5rem;
  margin-top: .5rem;
}
.sl-resumen-actividad__stat {
  flex: 1 1 0; min-width: 0;
  text-align: center;
  background: #ffffff;
  border: 1px solid var(--sl-border);
  border-radius: var(--sl-radius-card);
  padding: .625rem .375rem;
}
.sl-resumen-actividad__stat-val, .sl-resumen-actividad__alert-val {
  font-size: 1.375rem; font-weight: 800; line-height: 1.1;
  color: var(--sl-blue);
}
.sl-resumen-actividad__stat-lbl, .sl-resumen-actividad__alert-lbl {
  margin-top: .1875rem;
  font-size: 14px; font-weight: 500;
  color: var(--sl-fg-2);
}

/* Sufijo de unidad de las cifras de TIEMPO ("22:06 h"). 2026-09-15: hasta esa
   fecha los contadores de Partes pintaban "22:06" a secas y nada decia si eran
   horas, minutos o segundos.
   Va en un <span> propio y NO como texto suelto dentro de la cifra porque
   .sl-resumen-actividad__stat-val es 1.375rem/800: una "h" escrita a pelo
   saldria igual de grande y gorda que el numero y competiria con el.
   - font-size en "em" (no rem) para que siga a la cifra si algun dia cambia.
   - color heredado + opacity en vez de un token fijo: la MISMA clase se usa en
     el contador (azul) y dentro del aviso rojo (#c0392b, ver mas abajo), asi
     que un color propio obligaria a duplicarla o dejaria una "h" gris sobre
     texto rojo.
   Hoy solo la usa modules/partes.resumen.actividad.tpl — las otras cuatro
   tarjetas de resumen no muestran tiempos. Vive aqui y no en el <style> local
   de esa plantilla por el mismo motivo que las reglas del aviso rojo: sin
   marcado que las case, no pintan nada. */
.sl-resumen-actividad__unit {
  font-size: .625em;
  font-weight: 600;
  margin-left: .1875rem;
  color: inherit;
  opacity: .65;
}

/* --- Aviso rojo (Importantes / Pendiente Revisar / Sin representante) ------
   El <i> del interior NO es un icono en linea con el texto: se saca del flujo
   con position:absolute y se convierte en el icono gigante rotado de fondo. De
   ahi el overflow:hidden del contenedor.
   En las cuatro copias inline el selector .sl-resumen-actividad__alert aparecia
   DOS veces seguidas; se declaraba asi "para que un diff entre las copias
   salga limpio". Con una sola copia ese motivo desaparece y van fusionadas. */
.sl-resumen-actividad__alert {
  position: relative;
  overflow: hidden;
  text-align: center;
  background: #fdf1f1;
  border: 1px solid #f0c4c4;
  color: #c0392b;
  border-radius: var(--sl-radius-card);
  padding: .625rem .5rem;
  margin-bottom: .75rem;
}
.sl-resumen-actividad__alert-val, .sl-resumen-actividad__alert-lbl {
  color: #c0392b;
}
.sl-resumen-actividad__alert i {
  position: absolute;
  right: 0;
  bottom: -15px;
  font-size: 120px;
  opacity: 0.1;
  transform: rotate(20deg);
  transition: transform 0.5s ease-in-out;
}
.sl-resumen-actividad__alert:hover i {
  transform: rotate(9deg) scale(1.3);
}
.sl-resumen-actividad__alert.is-clickable { cursor: pointer; }
.sl-resumen-actividad__alert.is-clickable:hover { filter: brightness(.97); }

/* Modificador: el aviso va DENTRO de .sl-resumen-actividad__stats, al lado del
   contador, en vez de ser un bloque propio a ancho completo debajo. Lo usa hoy
   solo Llamadas ("Importantes" junto a "Llamadas", 2026-09-01), de ahi que
   necesite ser un hermano flexible y perder el margen inferior que si quiere la
   variante de bloque. */
.sl-resumen-actividad__alert--inline {
  flex: 1 1 0; min-width: 0;
  margin-bottom: 0;
}

/* --- Acciones rapidas -----------------------------------------------------
   Los botones NO ocupan el 100% del ancho: cada uno mide lo que su texto
   necesita y fluyen en fila, envolviendo a la linea siguiente si no caben -
   mismo lenguaje visual que las pills de "Filtrando por:" de arriba. */
.sl-resumen-actividad__actions {
  display: flex; flex-wrap: wrap;
  gap: .5rem;
  margin-top: .5rem;
}
.sl-resumen-actividad__actions .sl-btn {
  flex: 0 0 auto;
  font-size: 13px;
}

/* La fila de "Vistas rapidas" (modules/proyectos.resumen.actividad.tpl) ya NO usa este
   contenedor: usa el agrupado de dos niveles de .sl-resumen-pills / __g (filtros-grid.css),
   que separa los grupos (18px) mas que las pills de dentro de un grupo (4px) — el mismo de
   la cabecera de la ficha de asunto. Lo UNICO que se perdio en el cambio es el aire bajo el
   rotulo, porque .sl-eyebrow no trae margen inferior y quien lo ponia era el margin-top de
   .sl-resumen-actividad__actions.
   Va escopado a .sl-resumen-actividad y NO anadido a .sl-resumen-pills, que comparte con la
   cabecera de la ficha de asunto: alli el bloque va EN LINEA con el ID y las etiquetas, sin
   nada encima, y un margen superior lo descuadraria. */
.sl-resumen-actividad .sl-resumen-pills { margin-top: .5rem; }

/* --- Fila del titulo "Visualizacion" --------------------------------------
   El titulo a la izquierda y "Guardar vista"/"Cargar vista" a la derecha en la
   MISMA fila, como enlaces de solo texto (no como botones dentro de
   .sl-resumen-actividad__actions, donde vivieron hasta 2026-09-01). */
.sl-resumen-actividad__eyebrow-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .5rem;
}
.sl-resumen-actividad__view-links {
  display: flex;
  align-items: baseline;
  gap: .375rem;
  flex: 0 0 auto;
}
.sl-resumen-actividad__view-link {
  font-size: .6875rem;
  font-weight: 600;
  color: var(--sl-blue);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}
.sl-resumen-actividad__view-link:hover {
  color: var(--sl-blue-600);
  text-decoration: underline;
}
.sl-resumen-actividad__view-sep {
  font-size: .6875rem;
  color: var(--sl-border);
}
/* --- Fila "Buscando" (modules/asuntos.resumen.busqueda.tpl) --------------
   Solo aparece DENTRO de esta misma tarjeta cuando la pantalla es el
   resultado de una busqueda. Fila de pills en flex-wrap, SIN .sl-eyebrow
   propio delante (2026-09-25): cada pill lleva ya su propio
   pill_prelabel="Buscando", asi no anade una seccion alta a la tarjeta, solo
   una linea mas que envuelve si no caben todas las pills. (Vivio antes
   como tarjeta propia en la columna de al lado — se fusiono aqui a peticion
   del usuario, para no ocupar dos huecos por una sola busqueda.) */
.sl-resumen-actividad__buscando {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: .375rem .5rem;
  flex-direction: column;
}
/* FIN TARJETA .sl-resumen-actividad */

/* --- Fila "expandir asunto" de los listados (.webapp tr.more) ---------------
   La fila oculta que cada listado de asuntos pinta VACÍA debajo de la del
   asunto (<tr class="more"></tr>); al pulsar el ID, modules/js/asuntos.tpl.js
   la rellena por AJAX con modules/expandir_asunto.tpl y la muestra.

   Hasta el 2026-09-15 estas cuatro reglas estaban copiadas en el <style> de
   asuntos.tpl, asuntos_clientes.tpl, asuntos_comerciales.tpl y
   estadisticas_comerciales.tpl. En esta última eran código muerto: es la
   página de gráficas, no tiene ninguna <table> ni ningún tr.more.

   Se pueden globalizar sin afectar a nadie más porque en TODO el proyecto solo
   hay cinco <tr class="more">: los tres listados citados y los dos
   encargos_mode.tpl de modules/, que se incluyen desde ellos. Ni PHP ni JS
   emiten otro (comprobado el 2026-09-15). inventarios.tpl tiene un
   <style id="expandir_asunto"> vacío, pero ni incluye esa plantilla ni pinta
   tr.more, así que no le llega nada nuevo.

   El ancho de .more_asunto / .more_encargo NO se fija aquí: lo escribe el JS
   en <style id="expandir_asunto"> midiendo las columnas reales de la tabla
   (asuntos.tpl.js:374). Aquí solo van float y min-height.
   ---------------------------------------------------------------------------- */
table.table.webapp tr.more { display: none; background: white; }
table.table.webapp tr.more p { margin: 5px 0; }
table.table.webapp tr.more > td {
  border-top: 1px dashed black;
  border-bottom: 1px solid black;
  border-right: 1px solid black;
  padding-top: 0px !important;
  padding-bottom: 0px !important;
}
td div.more_asunto, td div.more_encargo { float: left; min-height: 1px; }

/* ── Ocultar filtros y columnas por usuario ─────────────────────────────────────────────────
   Un filtro escondido se PINTA igual (así su control sigue enviando su valor neutro en el
   form) y solo se esconde aquí. En modo personalizar no se esconde nada: se atenúa, para
   poder recuperarlo. Ver _devel/claude/diseno-ocultar-filtros-columnas-2026-09-16.md */
/* ".sl-filtros-grid" está aquí para GANAR ESPECIFICIDAD, no para acotar: sin él, este selector
   mide 1-2-0 y empata con ".sl-filtros-grid #div-creado-por .form-group" de filtros-grid.css
   (display:flex), que gana por orden de carga. Esa regla nombra #div-cliente-id, #div-representantes
   y #div-creado-por, así que el empate dejaba a Cliente, Representantes y Creado por SIN esconderse
   — los otros 13 filtros sí se escondían, lo que hacía el fallo aún más difícil de ver. Con este
   selector medimos 1-3-0 y ganamos. Verificado en el DOM, no deducido. */
#sl-app:not(.sl-personalizando) .sl-filtros-grid .sl-filtro--oculto { display: none; }

#sl-app.sl-personalizando .sl-filtro--oculto {
  opacity: .45;
  outline: 1px dashed var(--sl-border);
  outline-offset: 2px;
}

/* El ojo / candado del modo personalizar. Solo existen dentro del modo, así que no necesitan
   esconderse fuera de él: la plantilla no los pinta.

   EL OJO ya no tiene caja propia: usa las clases del sistema ".sl-btn .sl-btn--pink .sl-btn--xs
   .sl-btn--icon", el mismo botón rosa de 24px que el resto de acciones pequeñas de la app (ver
   asuntos.encargos.tpl:57). Aquí solo queda lo que ese botón no da: separación del rótulo y los
   dos estados propios. ".sl-oo__btn" se conserva como ENGANCHE del JS (personalizar.tpl.js lo usa
   de selector), no como clase de presentación — por eso no lleva estilo. */
#sl-app .sl-oo__btn { margin-left: .25rem; vertical-align: middle; position: absolute; right: 0; top: 0; z-index: 1; }

/* Algunos filtros son un <%include%> entero (el selector de prioridad, el combo de
   seguimiento) y no tienen un <label> propio donde colgar el ojo sin entrar a modificar el
   componente — que lo comparten otras pantallas. El ojo va entonces en su propio div, que no
   ocupa alto: se posiciona como los demás (absolute, arriba a la derecha de la celda) sin
   empujar el control hacia abajo. */
#sl-app .sl-oo__flotante { position: relative; height: 0; }

/* Escondido: el mismo botón rosa, atenuado. */
#sl-app .sl-oo--oculto { opacity: .55; }

/* La pastilla "Tienes N filtros ocultos" de la cabecera (modules/asuntos.filtros.tpl) se
   apaga y enciende con el atributo "hidden", que en modo personalizar mueve el JS según
   sube y baja el contador. Hace falta esta regla porque .sl-generic-pill es inline-flex
   (filtros-grid.css) y una clase le gana al display:none que el navegador da a [hidden] en
   su hoja de usuario-agente: sin esto, poner "hidden" no escondía nada. Con el #sl-app
   delante (1-2-0) gana por especificidad y no por orden de carga.
   En un style no cabía: pill.tpl ya emite el suyo para $pill_color, y dos atributos style en
   la misma etiqueta no se suman -- el navegador se queda con el primero. */
#sl-app .sl-generic-pill[hidden] { display: none; }

/* Una columna cuyo dato aparece solo según el filtro. Se tiñe de azul en vez de rosa: con el
   botón relleno, el color del icono ya no distingue nada (es blanco en los dos casos), así que
   el distintivo tiene que estar en el FONDO. */
#sl-app .sl-oo--automatica,
#sl-app .sl-oo--automatica:hover,
#sl-app .sl-oo--automatica:focus { background: var(--sl-blue-600); border-color: var(--sl-blue-600); }

/* Los elementos FIJOS no pintan nada: ni ojo ni candado. Hubo un candado gris hasta el
   2026-09-17 y se quitó a petición del usuario — la ausencia de ojo ya dice que ese filtro o
   esa columna no se pueden esconder, y el candado solo añadía ruido a una rejilla que este
   modo existe para despejar. Por eso aquí no queda ninguna regla para ellos. */

/* Mientras personalizas, la rejilla de filtros no debe colapsar: lo oculto sigue ocupando su
   sitio, atenuado (la regla de .sl-filtro--oculto de arriba ya lo hace). */
#sl-app.sl-personalizando .sl-panel-filtros, #sl-app.sl-personalizando .sl-table-bordered { border: 2px solid var(--sl-pink); }
#sl-app.sl-personalizando .sl-table-bordered tbody,
#sl-app.sl-personalizando .sl-filtros-activos-bar {
  opacity: .45;
}

/* Celda de filtros VACÍA (2026-09-16): esconder TODOS los filtros de una celda dejaba el chip
   ocupando su sitio en la rejilla -- hueco en blanco, cero espacio ganado, justo lo contrario
   del objetivo de esta funcionalidad. Fuera del modo personalizar, una celda sin NINGÚN
   .sl-filtro visible desaparece entera; dentro del modo se queda (con el resto de esta
   funcionalidad atenuando cada .sl-filtro--oculto por separado), para poder recuperarlos.

   Los tres filtros FIJOS (fechas, estado, mode) llevan su propio .sl-filtro que
   Filtros_Model::set_ocultos() nunca deja marcar --oculto (están en FIJOS y se descartan al
   guardar) -- así la celda que los aloja nunca cumple la condición de "ningún .sl-filtro
   visible", aunque comparta hueco con un filtro sí ocultable (Estado encargos + Tipo). Sin
   ese envoltorio, esconder solo "Tipo" se habría llevado por delante "Estado encargos".

   :not(:has(.sl-orden)) excluye la celda de "Ordenar por": ese filtro no está en
   Filtros_Model::CATALOGO y por tanto no lleva ningún .sl-filtro -- sin esta exclusión, la
   celda (compartida con Creado por / Listar por / Filtro especial) desaparecería entera en
   cuanto esos tres se escondieran, llevándose el selector de orden por delante.

   "!important" + el ID "#sl-app": esta celda compite con reglas "display: flex !important" de
   filtros-grid.css (las de "input[name='prio']" y las de "#elegir_usuario"/
   "#elegir_usuario_cr_e") que maquetan el CONTENIDO de la celda cuando está visible -- sin
   ganarles el pulso, la celda seguiría en flex y visible aunque todo lo de dentro estuviera
   --oculto. */
#sl-app:not(.sl-personalizando) .sl-filtros-grid > .sl-fcell:has(.sl-filtro):not(:has(.sl-filtro:not(.sl-filtro--oculto))):not(:has(.sl-orden)) {
  display: none !important;
}

/* ── Modo personalizar: la tarjeta de resumen se apaga salvo sus dos botones ──────────────────
   Dentro del modo, "Ver vista por defecto", "Guardar/Cargar vista", los logos de cliente y todas
   las acciones rápidas siguen ahí pero no pintan nada: lo que el usuario está haciendo es elegir
   qué ve, y lo único que puede hacer desde esta tarjeta es guardar o restaurar. Atenuarlas lo dice
   sin tener que escribirlo, y el pointer-events evita que se pulse algo que le sacaría del modo.

   El bloque de los dos botones (.sl-modo-acciones) NO está dentro de lo atenuado sino al lado:
   "opacity" se hereda a todos los descendientes y ninguna regla puede devolverla, así que la única
   forma de dejarlos a plena intensidad es que no cuelguen de nada apagado. Por eso la plantilla los
   saca a su propia fila.

   Se apaga cada HERMANO del camino que baja hasta .sl-modo-acciones, a cualquier profundidad, y
   nunca un antepasado suyo. Hasta el 2026-09-23 la regla era "hijos directos de __resumen menos
   .sl-modo-acciones"; r7209 metió las secciones en __cols > __col, la fila de botones dejó de ser
   hija directa, y la regla apagó __cols ENTERO con los botones dentro: Salir y Restaurar todo se
   quedaron con pointer-events:none, a la vista pero sin responder. Con :has() la regla ya no
   depende de cuántos envoltorios haya. Sin botones en la tarjeta (otras pantallas) se apagan
   todos los hijos directos, igual que antes. */
#sl-app.sl-personalizando :is(.sl-resumen-actividad__resumen, .sl-resumen-actividad__resumen :has(.sl-modo-acciones)) > :not(.sl-modo-acciones):not(:has(.sl-modo-acciones)) {
  opacity: .4;
  pointer-events: none;
}
.clientes_logos_asunto {
  padding-left: 0;
}
.clientes_logos {
  width: 100%;
}

/* -- Entrada de hilo: autor + fecha + texto, con franja de color ------------------------------
   Una entrada cronológica escrita por alguien: un mensaje de cliente, una reclamación, mañana
   cualquier otra cosa con la misma forma. Rótulo a la izquierda con el color de la franja, fecha
   a la derecha atenuada, texto debajo a todo el ancho.

   La franja izquierda es lo que distingue el origen SIN depender del ancho disponible, que es la
   razón por la que este patrón nació en el drawer de la ficha: un icono + etiqueta superpuestos
   al nombre se solapaban. El color va por variable y NO por modificador de dominio
   (--cliente / --interna), igual que components/pill.tpl hace con --sl-generic-pill-color: así
   quien lo usa decide qué significa cada color sin tener que declarar una clase nueva aquí.

   Sin prefijo #sl-app a propósito: son clases propias que no compiten con nada de Bootstrap, y
   así valen también DENTRO de una modal de bootstrap-dialog, que vive fuera de #sl-app.

   El gap lo pone la lista y no el .sl-panel__body, que en cuanto contiene un .sl-ficha-field-group
   se queda a gap:0 (ver "Cuerpo de panel hecho de celdas" más arriba).

   Lo usan, de momento, dos sitios: los mensajes del encargo
   (modules/asunto.encargo.panel.info.tpl) y la lista de reclamaciones del drawer de la ficha
   (modules/dialog/ficha/encargo.tpl), que es de donde salió el diseño y que hasta el
   2026-09-21 llevaba su propia copia en un <style> local. */
.sl-entry-list {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.sl-entry {
  --sl-entry-color: var(--sl-border);
  /* text-align propio: la tarjeta no puede depender de la alineación del contenedor. En el
     listado del portal estas entradas viven en un <td> centrado -el centro es para el botón
     "Anotar"- y sin esto el texto de la anotación salía centrado dentro de su caja. */
  text-align: left;
  padding: .4rem .625rem;
  border: 1px solid var(--sl-border);
  border-left: 3px solid var(--sl-entry-color);
  border-radius: var(--sl-radius-sm, 4px);
  /* fondo propio, para que la tarjeta se recorte sobre el area de conversacion */
  background: var(--sl-bg-card);
  font-size: .8125rem;
}
.sl-entry__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .5rem;
  margin-bottom: .25rem;
}
.sl-entry__autor {
  font-weight: 600;
  color: var(--sl-entry-color);
}
.sl-entry__texto {
  color: var(--sl-fg-2);
}

/* -- ...en modo CONVERSACIÓN -------------------------------------------------------------------
   Variante para un hilo entre dos partes, a petición del usuario 2026-09-21: lo que escribe el
   cliente cae a la izquierda con su franja a la izquierda, y lo nuestro a la derecha con la
   franja a la DERECHA. Es opt-in (--chat) porque no todo lo que usa .sl-entry es un diálogo: la
   lista de reclamaciones del drawer de la ficha son apuntes, no una conversación.

   El width:fit-content es lo que hace que se lea como un chat y no es cosmética: con las burbujas
   al 100% del panel -aquí son 1839px- alinear a izquierda o derecha no se nota absolutamente
   nada, porque todas empiezan y acaban en el mismo sitio. Cada una mide lo que mide su texto,
   con un tope para que un mensaje largo no cruce la pantalla entera.

   El modificador se llama --propio y no --derecha a propósito: nombra QUIÉN lo escribió, no dónde
   cae. El lado es una decisión de presentación y vive aquí, no repartida por las plantillas.

   Ojo al reset del borde izquierdo: .sl-entry ya pinta 3px de color a la izquierda, así que para
   moverlo al otro lado hay que devolver ese a 1px además de pintar el derecho. */
.sl-entry-list--chat {
  /* El hilo se lee como una superficie propia -- tarjetas blancas sobre un azul muy claro --
     y no como texto suelto dentro del panel. El color es el token del sistema, que vale
     exactamente el #F3F7FB pedido; escribir el hex aqui lo dejaria fuera del tema. */
  background: var(--sl-blue-050);
  padding: .625rem;
  border-radius: var(--sl-radius-sm, 4px);
}
.sl-entry-list--chat > .sl-entry {
  width: fit-content;
  max-width: 75%;
}
/* Los saltos de linea SOLO se respetan aqui, y es una diferencia de DATO, no de estetica:
   el texto de un mensaje llega crudo de la base (encargos_mensajes_cliente), mientras que el
   de una anotacion pasa por nl2br() en Asunto_Model::get_asunto() y llega ya con sus <br>.
   Con pre-line en el bloque base, esa anotacion rompia DOS veces por cada salto: una por el
   <br> y otra por el 
 que nl2br conserva detras. */
.sl-entry-list--chat .sl-entry__texto {
  white-space: pre-line;
}
.sl-entry-list--chat > .sl-entry--propio {
  margin-left: auto;
  border-left: 1px solid var(--sl-border);
  border-right: 3px solid var(--sl-entry-color);
}

/* -- Dos paneles en paralelo -------------------------------------------------------------------
   Las secciones del panel del encargo se apilan una debajo de otra, que es lo correcto cuando
   cada una es una tabla ancha. Pero "Anotación" y "Anotación cliente" son dos textos cortos que
   dicen lo mismo desde los dos lados: apiladas desperdician media pantalla cada una y obligan a
   bajar para comparar. Envolviéndolas en esta fila se leen de un vistazo. Usuario 2026-09-21.

   flex-wrap + una base de 20rem, y no dos columnas fijas: con una sola de las dos anotaciones la
   fila tiene un único hijo y ocupa el ancho entero -que es lo que se quiere-, y en una pantalla
   estrecha vuelven a apilarse solas sin necesidad de media query.

   El min-width:0 no es decorativo: un hijo flex arranca en min-width:auto, así que un texto largo
   SIN espacios (una URL, una referencia) ensancharía su columna y desbordaría la fila en vez de
   partirse. Es la trampa clásica de flex y aquí el contenido lo escribe un usuario.

   El hueco usa el mismo token que .sl-mt-2, que es el margen con el que se separan estas mismas
   secciones cuando van apiladas: así el aire horizontal y el vertical miden igual. */
.sl-panel-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sl-space-2);
}
.sl-panel-row > .sl-panel {
  flex: 1 1 20rem;
  min-width: 0;
}

/* ===============================================================================================
   CIERRES MASIVOS — panel de resultados de /cierres
   ===============================================================================================
   Tres problemas de la primera version, todos se ven en cuanto hay 1.000 filas en pantalla:

     1. Todo iba pegado. Los bloques (aviso, tabla, confirmacion, avance) eran hijos sueltos de un
        contenedor sin `gap`, asi que se leian como un solo muro.
     2. El boton "Cerrar" llevaba `btn-block` dentro de un `col-md-6`: media pantalla de ancho para
        la unica accion irreversible de la aplicacion. Un boton gigante no es un boton importante,
        es un boton facil de pulsar sin querer.
     3. El campo de confirmar era un `form-control` a ancho completo para escribir cuatro digitos.

   El recuento vive ahora en la cabecera del panel (.sl-panel__header--row), que ya existia. */

/* La columna interior. Va aparte y no como estilo en linea porque lo que importa es el `gap`:
   es lo unico que separa los bloques entre si.

   ⚠️ El width:100% no sobra. .sl-panel__body es flex-ROW, asi que este div es un flex item y
   sin el se encogeria a su contenido, dejando la tabla y la franja de accion a media anchura. */
.sl-cierres-col {
  display: flex;
  flex-direction: column;
  width: 100%;
  gap: var(--sl-space-3);
}

/* El recuento. Grande porque es el dato que decide si seguir o volver a filtrar, y porque es el
   numero que hay que teclear abajo para confirmar. */
.sl-cierres-cifra {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--sl-blue);
  margin-right: .25rem;
}

/* La tabla, en su propio scroll. El alto es el de ~8 filas: suficiente para hacerse una idea de
   lo que entra en el lote sin que la franja de accion se vaya fuera de la pantalla. */
/* ⚠️ SIN borde ni radio propios: .sl-table ya se enmarca sola (border + radius +
   overflow:hidden, softline-ui.css:1167). Los tenia y eran un SEGUNDO marco pegado al de la
   tabla. Aqui solo queda lo que es de esta pantalla: la caja de scroll vertical.

   (/llamadas si envuelve en .sl-table-bordered, pero porque su <table> es la antigua de
   Bootstrap y no lleva marco propio. Con .sl-table ese envoltorio duplicaria el borde.) */
.sl-cierres-tabla {
  max-height: 26rem;
  overflow: auto;
}

/* El grupo de confirmacion, dentro de la cabecera del panel.

   ⚠️ VA ARRIBA POR EL WIDGET DE FEEDBACK: es fijo abajo a la derecha, asi que toda accion
   alineada a la derecha al final de la pagina acaba tapada por el. Medido en el navegador con
   1.258 filas: el boton "Cerrar" quedaba literalmente debajo.

   margin-left:auto y no el space-between de .sl-panel__header--row: esa cabecera tiene TRES
   hijos (el recuento, el "se muestran N" y este grupo), y con space-between el de en medio
   flotaria suelto. Con auto, los dos textos se agrupan a la izquierda y la accion se pega a la
   derecha, que es donde se busca.

   flex-wrap para que en pantalla estrecha se apile solo, sin media query. */
.sl-cierres-accion {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sl-space-2);
  margin-left: auto;
}
.sl-cierres-accion__txt {
  margin: 0;
  text-transform: none;   /* .sl-label va en versalitas; aqui lleva una cifra dentro y se lee peor */
}
.sl-cierres-accion__txt b { color: var(--sl-pink); }

/* El ID y la fecha no se parten. Son valores unicos y cortos, y al dejarlos envolver la columna
   de fecha sacaba "2022-01-04 / 15:15:00" en tres lineas, que ademas desalineaba las filas entre
   si. El comentario, que es el texto largo, se queda con todo el ancho sobrante.

   Por posicion y no por clase porque las columnas las decide el model segun el cierre
   (ll_id/a_id, ll_fecha/a_fecha_cr...), pero las dos primeras SIEMPRE son id y fecha.

   ⚠️ Son la 1 y la 2, no la 2 y la 3: hubo una columna de casillas delante y al quitarla
   (2026-09-23) estos selectores apuntaban a Fecha y Cliente. Un selector por posicion se
   desplaza entero en cuanto cambia una columna, y no da ningun error al hacerlo. */
.sl-cierres-tabla td:nth-child(1),
.sl-cierres-tabla th:nth-child(1),
.sl-cierres-tabla td:nth-child(2),
.sl-cierres-tabla th:nth-child(2) {
  white-space: nowrap;
  width: 1%;
}

/* Ancho para los digitos que puede llegar a tener el lote y ni uno mas: el `size` del HTML no
   gobierna porque .sl-input no declara width, pero tampoco conviene dejarlo a ancho completo. */
.sl-cierres-accion__num {
  width: 7rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* ——— Actividad: .sl-activity (modules/dialog/notificaciones.tpl) ——————————————————
   Feed del diálogo "Actividad" del header (antes "Notificaciones"). Secciones por día con la
   cabecera pegada arriba al hacer scroll, y una fila por evento hecha con las MISMAS piezas que
   los listados — aquí solo se maqueta la fila, no hay componentes propios:

     [  A  ] [  E  ]                                       17:07  [ACABADO]
     [55723] [71078]
     Tolo Sans ha pasado un encargo a «Acabado»
     LOS PDFS NO SE GUARDAN EN EL NAS
     (6846) [logo] FAMILY CASTRO & MARTIN, S.L.
     título del asunto (solo si no es el mismo que el del encargo)

   El "A" de un encargo NO abre la ficha: lleva a /asunto/ver con la pestaña de ese encargo.

   Dos líneas (2026-09-28, a petición del usuario): arriba el badge y, enfrente, hora + estado;
   debajo el cuerpo a TODO el ancho. Con el badge a la izquierda de todo el cuerpo, el texto se
   quedaba en la mitad del diálogo y partía en dos líneas casi cualquier nombre de cliente. Sin
   iconos de tipo de evento: la frase ya dice qué pasó.

     · components/id-badge.tpl → abre la ficha del registro, como en los listados;
     · components/pill.tpl → código de cliente (rosa, abre su ficha) y estado (pill_estado);
     · components/cliente-nombre.tpl → logo + nombre.

   Ni la fila ni el título son enlaces (2026-09-28): se navega por los badges (A → asunto con la
   pestaña del encargo; E/L → ficha), la pastilla del cliente (su ficha) y el lápiz de editar de
   las llamadas.

   Va SIN prefijo #sl-app a propósito: bootstrap-dialog monta la modal fuera de #sl-app (§17). */
.sl-activity__toolbar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sl-space-2);
  margin-bottom: var(--sl-space-3);
}
.sl-activity__toolbar .sl-generic-pill { font-family: var(--sl-font); font-size: .75rem; }
.sl-activity__toolbar .sl-generic-pill.is-active .sl-activity__n { color: #fff; }
.sl-activity__n { font-size: .6875rem; font-weight: 700; color: var(--sl-fg-3); }
.sl-activity__scroll { max-height: 62vh; overflow-y: auto; margin: 0 calc(-1 * var(--sl-space-2)); padding: 0 var(--sl-space-2); }

.sl-activity__day {
  position: sticky; top: 0; z-index: 2;
  background: var(--sl-bg-card);
  padding: var(--sl-space-3) 0 var(--sl-space-1);
  font-size: .625rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--sl-fg-3);
}

.sl-activity__item {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "badge aside" "body body";
  align-items: center;
  gap: var(--sl-space-2) var(--sl-space-3);
  padding: var(--sl-space-2) var(--sl-space-3);
  border-bottom: 1px solid var(--sl-border-2);
  position: relative;
  transition: background .15s;
}
.sl-activity__section .sl-activity__item:last-child { border-bottom: 0; }
.sl-activity__item:hover { background: var(--sl-blue-050); }
/* Apagada (llamada acabada): mismo criterio y misma opacidad que .sl-row--muted de llamadas.tpl.
   Se atenúan los HIJOS y no la fila, para no lavar el fondo de "sin leer" ni su barra rosa
   (el ::before es de la fila, no un hijo). */
.sl-activity__item.is-muted > * { opacity: .65; }
/* Sin leer al abrir el diálogo: el servidor ya las ha marcado leídas, así que esta es la
   única vez que se ven como nuevas. Barra rosa a la izquierda + fondo tintado. */
.sl-activity__item.is-unread { background: var(--sl-blue-050); }
.sl-activity__item.is-unread::before {
  content: ""; position: absolute; left: 0; top: var(--sl-space-2); bottom: var(--sl-space-2);
  width: 3px; border-radius: 3px; background: var(--sl-pink);
}

.sl-activity__badge { grid-area: badge; display: flex; align-items: center; gap: var(--sl-space-2); } /* A del asunto + E del encargo */
.sl-activity__body  { grid-area: body; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.sl-activity__event { font-size: .6875rem; font-weight: 500; color: var(--sl-fg-3); line-height: 1.3; }
.sl-activity__title {
  font-size: .8125rem; font-weight: 700; color: var(--sl-blue); line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sl-activity__title--plain { font-weight: 500; color: var(--sl-fg-2); font-variant-numeric: tabular-nums; }
.sl-activity__cliente { display: flex; align-items: center; gap: var(--sl-space-2); min-width: 0; }
/* En los listados el nombre tiene 180px de columna; aquí la fila entera es suya. */
.sl-activity__cliente .sl-cliente-nombre,
.sl-activity__cliente .sl-cliente-nombre__label,
.sl-activity__cliente .sl-cliente-nombre--sin-logo { max-width: none; }
.sl-activity__cliente .sl-cliente-nombre { flex-direction: row; align-items: center; gap: var(--sl-space-2); }
.sl-activity__cliente .sl-cliente-nombre__logo { height: 24px; padding-bottom: 0; }
.sl-activity.sl-hide-cliente-logos .sl-cliente-nombre__logo { display: none; }
.sl-activity__ctx {
  font-size: .6875rem; color: var(--sl-fg-3); line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sl-activity__ctx b { font-weight: 700; color: var(--sl-fg-2); }

.sl-activity__aside { grid-area: aside; display: flex; align-items: center; justify-content: flex-end; gap: var(--sl-space-2); }
.sl-activity__time { font-size: .6875rem; font-weight: 600; color: var(--sl-fg-3); font-variant-numeric: tabular-nums; }

.sl-activity__empty {
  padding: var(--sl-space-5) var(--sl-space-4); text-align: center;
  font-size: .8125rem; color: var(--sl-fg-3);
}
.sl-activity__empty i { display: block; font-size: 1.75rem; margin-bottom: var(--sl-space-2); color: var(--sl-border-2); }
