/* =====================================================================
   WERP · Componentes de interfaz
   ===================================================================== */

/* --- Botones --- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--e-2);
  padding: 9px 16px; border-radius: var(--radio-sm);
  font: 500 var(--t-14)/1 var(--f-ui);
  border: 1px solid transparent; cursor: pointer;
  transition: background .15s ease, border-color .15s ease, color .15s ease;
  white-space: nowrap;
}
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn svg { width: 15px; height: 15px; }

.btn-laton {
  background: var(--laton); color: var(--laton-tinta);
  border-color: var(--laton-oscuro); font-weight: 600;
}
.btn-laton:hover:not(:disabled) { background: var(--laton-claro); }

.btn-fantasma {
  background: transparent; color: var(--texto-suave); border-color: var(--linea);
}
.btn-fantasma:hover:not(:disabled) { color: var(--texto); border-color: var(--linea-fuerte); background: var(--superficie-2); }

.btn-peligro {
  background: transparent; color: var(--peligro); border-color: color-mix(in srgb, var(--peligro) 45%, transparent);
}
.btn-peligro:hover:not(:disabled) { background: var(--peligro-velo); }

.btn-sm { padding: 6px 11px; font-size: var(--t-13); }

/* Botón que parece un enlace (v0.21): «¿No recuerdas tu contraseña?» y
   «Volver al acceso». En WERP no hay <a> que ejecuten cosas —los
   eventos se conectan con addEventListener, nunca con onclick—, así que
   lo que parece un enlace por dentro es un botón. */
.btn-enlace {
  background: none; border: 0; padding: 2px 0;
  color: var(--laton-texto); font-size: var(--t-13); font-weight: 500;
  text-decoration: underline; text-underline-offset: 3px;
  align-self: center; min-height: 0;
}
.btn-enlace:hover:not(:disabled) { color: var(--texto); }
/* El que no se puede deshacer. Va en rojo desde el principio y no solo al
   pasar por encima: si el color de aviso aparece con el ratón ya encima,
   llega tarde para el que iba a pulsar. */
.btn-enlace-peligro { color: var(--peligro); }
.btn-enlace-peligro:hover:not(:disabled) { color: var(--peligro); text-decoration-thickness: 2px; }

.icono-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: var(--radio-sm);
  background: transparent; border: 1px solid var(--linea);
  color: var(--texto-suave); cursor: pointer;
}
.icono-btn:hover { color: var(--texto); background: var(--superficie-2); }
.icono-btn svg { width: 18px; height: 18px; }

/* --- Campos de formulario --- */
.campo { display: flex; flex-direction: column; gap: 6px; }
.campo label { font-size: var(--t-13); font-weight: 500; color: var(--texto-suave); }
.campo .obligatorio { color: var(--laton); }

.campo input, .campo select, .campo textarea, .buscador input {
  width: 100%;
  background: var(--superficie-2);
  border: 1px solid var(--linea);
  border-radius: var(--radio-sm);
  color: var(--texto);
  font: 400 var(--t-14)/1.4 var(--f-ui);
  padding: 9px 12px;
  transition: border-color .15s ease, background .15s ease;
}
.campo textarea { resize: vertical; min-height: 74px; }
.campo input:focus, .campo select:focus, .campo textarea:focus, .buscador input:focus {
  outline: none; border-color: var(--laton-oscuro); background: var(--superficie-3);
}
.campo input:disabled, .campo select:disabled, .campo textarea:disabled {
  opacity: .6; cursor: not-allowed;
}
.campo .ayuda { font-size: var(--t-12); color: var(--texto-mudo); }
.campo.con-error input { border-color: var(--peligro); }
.campo .error-texto { font-size: var(--t-12); color: var(--peligro); }

select { appearance: none; background-image: linear-gradient(45deg, transparent 49%, var(--texto-mudo) 50%), linear-gradient(135deg, var(--texto-mudo) 50%, transparent 51%); background-position: calc(100% - 16px) 55%, calc(100% - 11px) 55%; background-size: 5px 5px; background-repeat: no-repeat; padding-right: 32px; }

.formulario-rejilla {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-4);
}
.formulario-rejilla .campo.ancho { grid-column: 1 / -1; }
@media (max-width: 640px) { .formulario-rejilla { grid-template-columns: 1fr; } }

/* Buscador con icono */
.buscador { position: relative; min-width: 220px; }
.buscador svg {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  width: 15px; height: 15px; color: var(--texto-mudo); pointer-events: none;
}
.buscador input { padding-left: 34px; }

/* Interruptor (switch) */
.interruptor { display: inline-flex; align-items: center; gap: var(--e-2); cursor: pointer; user-select: none; }
.interruptor input { position: absolute; opacity: 0; width: 0; height: 0; }
.interruptor .pista {
  width: 34px; height: 19px; border-radius: 20px; position: relative; flex: none;
  background: var(--superficie-3); border: 1px solid var(--linea); transition: background .15s ease;
}
.interruptor .pista::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 13px; height: 13px;
  border-radius: 50%; background: var(--texto-mudo); transition: transform .15s ease, background .15s ease;
}
.interruptor input:checked + .pista { background: var(--laton-velo); border-color: var(--laton-oscuro); }
.interruptor input:checked + .pista::after { transform: translateX(15px); background: var(--laton); }
.interruptor input:focus-visible + .pista { outline: 2px solid var(--laton); outline-offset: 2px; }
.interruptor .etiqueta { font-size: var(--t-13); color: var(--texto-suave); }

/* --- Tarjetas --- */
.tarjeta {
  background: var(--superficie);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  box-shadow: var(--sombra-1);
}
.tarjeta-relleno { padding: var(--e-5); }

.tarjetas-rejilla {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--e-4); margin-bottom: var(--e-5);
}
.dato-tarjeta { padding: var(--e-5); }
.dato-etiqueta {
  font-family: var(--f-datos); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--texto-mudo); margin-bottom: var(--e-2);
}
.dato-valor { font-family: var(--f-titulos); font-size: var(--t-28); font-weight: 700; line-height: 1.1; }
.dato-pie { margin-top: var(--e-1); font-size: var(--t-12); color: var(--texto-mudo); }

/* --- Insignias --- */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: 999px;
  font-family: var(--f-datos); font-size: 11px; letter-spacing: .04em;
}
.badge-laton { background: var(--laton-velo); color: var(--laton-texto); border: 1px solid color-mix(in srgb, var(--laton) 55%, transparent); }
.badge-ok { background: var(--ok-velo); color: var(--ok); }
.badge-mudo { background: var(--info-velo); color: var(--texto-suave); }
.badge-peligro { background: var(--peligro-velo); color: var(--peligro); }

.mono { font-family: var(--f-datos); font-size: var(--t-13); }

/* --- Avisos en bloque --- */
/* v0.21.4 · .aviso ERA UN CONTENEDOR FLEX, y eso destrozaba cualquier
   aviso con algo de marcado dentro. En un contenedor flex, cada trozo
   —cada <strong>, cada <span> y cada pedazo de texto suelto— se convierte
   en un elemento independiente y se separa del siguiente con el hueco del
   `gap`. Un aviso como «<strong>Enlace comprobado.</strong> Pon aquí tu
   contraseña para <span>jgl@wadax.eu</span>» salía desmigado en columnas.
   Se hizo flex pensando en «icono + texto», y se comprobó antes de
   cambiarlo: de los 80 avisos del proyecto, NINGUNO lleva icono dentro.
   Los dos únicos con varios hijos ya envuelven en un solo <div>, así que
   se comportan igual en bloque. Pasa a bloque, que es lo que un aviso de
   texto necesita: las líneas fluyen y el negrita vuelve a ser negrita. */
.aviso {
  display: block;
  padding: var(--e-4); border-radius: var(--radio-sm);
  border: 1px solid var(--linea); background: var(--superficie-2);
  font-size: var(--t-13); color: var(--texto-suave);
}
.aviso.aviso-peligro { border-color: color-mix(in srgb, var(--peligro) 40%, transparent); background: var(--peligro-velo); color: var(--peligro); }
.aviso.aviso-laton { border-color: color-mix(in srgb, var(--laton) 55%, transparent); background: var(--laton-velo); color: var(--laton-texto); }

/* --- Modal --- */
.modal-velo {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(35, 30, 20, .38); backdrop-filter: blur(3px);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 6vh var(--e-4) var(--e-4);
  overflow-y: auto;
}
.modal {
  width: 100%; max-width: 660px;
  background: var(--superficie-3);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  box-shadow: var(--sombra-2);
  animation: modal-entra .18s ease;
}
.modal-sm { max-width: 430px; }
@keyframes modal-entra { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.modal-cabecera {
  display: flex; align-items: center; gap: var(--e-3);
  padding: var(--e-4) var(--e-5);
  border-bottom: 1px solid var(--linea);
}
.modal-cabecera h2 { flex: 1; font-size: var(--t-18); }
/* Logo abreviado de WADAX en la esquina de la ventana (v0.15) */
.modal-marca { width: 28px; height: 28px; flex: 0 0 auto; border-radius: 6px; }
.modal-cuerpo { padding: var(--e-5); }
.modal-pie {
  display: flex; justify-content: flex-end; gap: var(--e-2);
  padding: var(--e-4) var(--e-5);
  border-top: 1px solid var(--linea);
}
.modal-pie .a-la-izquierda { margin-right: auto; }

/* --- Toasts --- */
.capa-toasts {
  position: fixed; bottom: var(--e-5); right: var(--e-5); z-index: 300;
  display: flex; flex-direction: column; gap: var(--e-2);
  max-width: min(380px, calc(100vw - 32px));
}
.toast {
  display: flex; gap: var(--e-3); align-items: flex-start;
  background: var(--superficie-3);
  border: 1px solid var(--linea);
  border-left: 3px solid var(--laton);
  border-radius: var(--radio-sm);
  box-shadow: var(--sombra-2);
  padding: var(--e-3) var(--e-4);
  font-size: var(--t-13);
  animation: toast-entra .2s ease;
}
.toast-ok { border-left-color: var(--ok); }
.toast-error { border-left-color: var(--peligro); }
.toast-aviso { border-left-color: var(--aviso); }
@keyframes toast-entra { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* --- Pantalla de acceso --- */
.acceso {
  position: relative;   /* el marco de las banderas de la esquina */
  min-height: 100vh;
  display: grid; place-items: center;
  padding: var(--e-5);
  background:
    radial-gradient(900px 480px at 50% -10%, rgba(199, 177, 111, .12), transparent 60%),
    var(--fondo);
}
.acceso-caja { width: 100%; max-width: 400px; }
.acceso-marca { text-align: center; margin-bottom: var(--e-6); }
.acceso-logo { width: 230px; max-width: 70vw; height: auto; margin: 0 auto; }
.acceso-marca .hilo { height: 2px; width: 120px; margin: var(--e-4) auto 0; background: var(--hilo-laton); border-radius: 2px; }
.acceso-marca .sub {
  margin-top: var(--e-3);
  font-family: var(--f-datos); font-size: 10px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--texto-mudo);
}
.acceso-form { display: flex; flex-direction: column; gap: var(--e-4); padding: var(--e-6); }
.acceso-pie { text-align: center; margin-top: var(--e-5); font-size: var(--t-12); color: var(--texto-mudo); }

/* --- Utilidades --- */
.oculto { display: none !important; }
.lista-simple { margin: 0; padding-left: 1.1em; color: var(--texto-suave); }
.lista-simple li { margin: 4px 0; }
.texto-mudo { color: var(--texto-mudo); }
.separado-arriba { margin-top: var(--e-5); }

/* --- Selector segmentado (opciones a la vista, un solo clic) --- */
.segmentos { display: flex; gap: var(--e-2); flex-wrap: wrap; }
.segmento { position: relative; }
.segmento input { position: absolute; opacity: 0; width: 0; height: 0; }
.segmento span {
  display: inline-flex; align-items: center;
  padding: 8px 14px; border-radius: 999px;
  border: 1px solid var(--linea);
  background: var(--superficie);
  color: var(--texto-suave);
  font: 500 var(--t-13)/1 var(--f-ui);
  cursor: pointer; user-select: none;
  transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.segmento:hover span { border-color: var(--linea-fuerte); }
.segmento input:checked + span {
  background: var(--laton); border-color: var(--laton-oscuro);
  color: var(--laton-tinta); font-weight: 700;
}
.segmento input:focus-visible + span { outline: 2px solid var(--laton-oscuro); outline-offset: 2px; }
.segmento input:disabled + span { opacity: .55; cursor: not-allowed; }

/* --- Elección de cliente (ventana con lista desplazable) --- */
.eleccion {
  margin-top: var(--e-2);
  border: 1px solid var(--linea);
  border-radius: var(--radio-sm);
  background: var(--superficie);
  overflow: hidden;
}
.eleccion .eleccion-buscar { padding: var(--e-2); border-bottom: 1px solid var(--linea-suave); }
.eleccion-lista { max-height: 240px; overflow-y: auto; }
.eleccion-item {
  display: flex; align-items: center; gap: var(--e-3);
  width: 100%; padding: 10px 12px;
  background: transparent; border: 0; border-bottom: 1px solid var(--linea-suave);
  font: inherit; color: var(--texto); text-align: left; cursor: pointer;
}
.eleccion-item:last-child { border-bottom: 0; }
.eleccion-item:hover { background: var(--laton-velo); }
.eleccion-item .cod { color: var(--laton-texto); font-weight: 700; font-size: var(--t-13); min-width: 74px; }
.eleccion-item .nom { flex: 1; }
.eleccion-vacia { padding: var(--e-4); color: var(--texto-mudo); font-size: var(--t-13); text-align: center; }

/* Ficha del elegido */
.chip-cliente {
  display: flex; align-items: center; gap: var(--e-3);
  margin-top: var(--e-2);
  padding: 10px 12px;
  border: 1px solid color-mix(in srgb, var(--laton) 55%, transparent);
  background: var(--laton-velo);
  border-radius: var(--radio-sm);
}
.chip-cliente .cod { color: var(--laton-texto); font-weight: 700; }
.chip-cliente .nom { flex: 1; }

/* --- Direcciones de envío adicionales (ficha de cliente) --- */
.direcciones-lista { display: flex; flex-direction: column; gap: var(--e-2); }
.direccion-item {
  display: flex; align-items: center; gap: var(--e-3);
  padding: 10px 12px;
  border: 1px solid var(--linea);
  background: var(--superficie);
  border-radius: var(--radio-sm);
}
.direccion-textos { flex: 1; min-width: 0; }
.direccion-nombre { font-weight: 600; }
.direccion-detalle { font-size: var(--t-13); color: var(--texto-suave); }
.direccion-vacia {
  padding: 10px 12px;
  border: 1px dashed var(--linea);
  border-radius: var(--radio-sm);
  color: var(--texto-mudo); font-size: var(--t-13);
}
.direcciones-pie { margin-top: var(--e-2); }

/* --- Ajustes: títulos de sección y tablas llanas --- */
.ajustes-titulo { font-size: var(--t-18); margin-bottom: var(--e-2); }
.ajustes-sub { font-size: var(--t-13); color: var(--texto-suave); margin-bottom: var(--e-4); max-width: 72ch; }

.tabla-llana-envoltura { overflow-x: auto; max-width: 100%; }
.tabla-llana { width: 100%; border-collapse: collapse; font-size: var(--t-14); }
.tabla-llana th {
  text-align: left; padding: 8px 12px;
  font-family: var(--f-datos); font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--texto-mudo);
  border-bottom: 1px solid var(--linea);
  background: var(--superficie-2);
  white-space: nowrap;
}
.tabla-llana td { padding: 8px 12px; border-bottom: 1px solid var(--linea-suave); vertical-align: middle; }
.tabla-llana tr:last-child td { border-bottom: 0; }
.tabla-llana .centrado { text-align: center; }
.matriz-permisos .interruptor { justify-content: center; }

/* Campo compacto dentro de tablas llanas */
.campo-llano {
  width: 100%; min-width: 130px;
  background: var(--superficie-2);
  border: 1px solid var(--linea);
  border-radius: var(--radio-sm);
  color: var(--texto);
  font: 400 var(--t-13)/1.3 var(--f-ui);
  padding: 6px 9px;
}
.campo-llano:focus { outline: none; border-color: var(--laton-oscuro); background: var(--superficie-3); }
.campo-llano:disabled { opacity: .55; cursor: not-allowed; }

/* --- Copias de seguridad --- */
.copias-acciones { display: flex; gap: var(--e-2); flex-wrap: wrap; margin-bottom: var(--e-4); }
.copias-botones { display: inline-flex; gap: 6px; }
.icono-btn-sm { width: 30px; height: 30px; }
.icono-btn-sm svg { width: 15px; height: 15px; }

/* =====================================================================
   CRM (M-10) · pestañas, barra de acciones, listas y tablero de embudo
   ===================================================================== */

/* --- Pestañas del módulo --- */
.pestanas {
  display: flex; gap: 4px; flex-wrap: wrap;
  border-bottom: 1px solid var(--linea);
  margin-top: var(--e-4);
}
.pestana {
  appearance: none; background: none; border: 0; cursor: pointer;
  padding: 9px 14px;
  font: 500 var(--t-14)/1.2 var(--f-ui);
  color: var(--texto-suave);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.pestana:hover { color: var(--texto); }
.pestana.activa {
  color: var(--laton-texto);
  border-bottom-color: var(--laton);
  font-weight: 700;
}

/* --- Barra de acciones dentro de una pestaña --- */
.crm-barra {
  display: flex; gap: var(--e-2); align-items: center; flex-wrap: wrap;
  margin-bottom: var(--e-3);
}
.crm-barra .buscador { flex: 1 1 220px; max-width: 420px; }

/* --- Listas del resumen (tareas próximas, última actividad) --- */
.tarjetas-rejilla-2 {
  display: grid; gap: var(--e-3);
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.crm-lista { display: flex; flex-direction: column; gap: 6px; margin-top: var(--e-2); }
.crm-lista-item {
  appearance: none; text-align: left; cursor: pointer; width: 100%;
  background: var(--superficie-2);
  border: 1px solid var(--linea-suave);
  border-radius: var(--radio-sm);
  padding: 9px 12px;
  font: 400 var(--t-13)/1.35 var(--f-ui);
  color: var(--texto);
}
.crm-lista-item:hover { border-color: var(--laton-oscuro); background: var(--superficie-3); }
.crm-lista-titulo { font-weight: 500; }
.crm-lista-pie { color: var(--texto-mudo); font-size: var(--t-12); margin-top: 2px; }

/* --- Tablero del embudo de oportunidades --- */
.kanban {
  display: grid; gap: var(--e-2);
  grid-template-columns: repeat(6, minmax(190px, 1fr));
  overflow-x: auto;
  align-items: start;
  padding-bottom: var(--e-2);
}
@media (max-width: 1100px) { .kanban { grid-template-columns: repeat(3, minmax(190px, 1fr)); } }
@media (max-width: 640px)  { .kanban { grid-template-columns: repeat(2, minmax(160px, 1fr)); } }
.kanban-col {
  background: var(--superficie-2);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  padding: var(--e-2);
  min-height: 120px;
}
.kanban-col.kanban-ok  { border-top: 2px solid var(--ok); }
.kanban-col.kanban-mal { border-top: 2px solid var(--peligro); }
.kanban-cab { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.kanban-titulo {
  font-family: var(--f-datos); font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--texto-mudo);
}
.kanban-cuenta { font: 700 var(--t-13)/1 var(--f-datos); color: var(--laton-texto); }
.kanban-suma { color: var(--texto-mudo); font-size: var(--t-12); min-height: 16px; margin-top: 2px; }
.kanban-cartas { display: flex; flex-direction: column; gap: 8px; margin-top: var(--e-2); }
.kanban-vacia { color: var(--texto-mudo); text-align: center; padding: 10px 0; }
.kanban-carta {
  appearance: none; text-align: left; cursor: pointer; width: 100%;
  background: var(--superficie);
  border: 1px solid var(--linea-suave);
  border-radius: var(--radio-sm);
  box-shadow: var(--sombra-1);
  padding: 10px 12px;
  font: 400 var(--t-13)/1.35 var(--f-ui);
  color: var(--texto);
}
.kanban-carta:hover { border-color: var(--laton-oscuro); }
.kanban-carta-codigo { font-size: var(--t-12); color: var(--laton-texto); font-weight: 700; }
.kanban-carta-titulo { font-weight: 500; margin-top: 2px; }
.kanban-carta-cliente { color: var(--texto-suave); font-size: var(--t-12); margin-top: 2px; }
.kanban-carta-pie { color: var(--texto-mudo); font-size: var(--t-12); margin-top: 4px; }

/* --- Kanban de tareas (4 columnas) y arrastre --- */
.kanban-4 { grid-template-columns: repeat(4, minmax(190px, 1fr)); }
@media (max-width: 1100px) { .kanban-4 { grid-template-columns: repeat(2, minmax(190px, 1fr)); } }
@media (max-width: 640px)  { .kanban-4 { grid-template-columns: minmax(160px, 1fr); } }
.badge-aviso { background: var(--aviso-velo); color: var(--aviso); }
.kanban-carta.arrastrando { opacity: .45; }
.sobre-destino { outline: 2px dashed var(--laton-oscuro); outline-offset: -2px; background: var(--laton-velo); }

/* --- Embudo de oportunidades en FRANJAS (v0.8.0) ---
   Cabecera con las 6 etapas (pinchar = ordenar; también admite soltar)
   y una franja horizontal por oportunidad. Con muchas franjas, la zona
   tiene su propia barra de scroll y la cabecera se queda a la vista. */
.embudo {
  overflow: auto;
  max-height: calc(100vh - 300px);
  min-height: 260px;
  padding: 0;
}
.embudo-ayuda { font-size: var(--t-12); flex: 0 1 auto; }
.embudo-cab {
  display: grid;
  grid-template-columns: repeat(6, minmax(150px, 1fr));
  min-width: 920px;
  position: sticky; top: 0; z-index: 2;
  background: var(--superficie-2);
  border-bottom: 1px solid var(--linea);
}
.embudo-etapa {
  appearance: none; cursor: pointer;
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  background: transparent; border: none;
  border-left: 1px solid var(--linea-suave);
  padding: 10px 12px 8px;
  text-align: left;
}
.embudo-etapa:first-child { border-left: none; }
.embudo-etapa:hover { background: var(--laton-velo); }
.embudo-etapa.activa { box-shadow: inset 0 -2px 0 var(--laton-oscuro); background: var(--laton-velo); }
.embudo-etapa.etapa-ok { box-shadow: inset 0 2px 0 var(--ok); }
.embudo-etapa.etapa-mal { box-shadow: inset 0 2px 0 var(--peligro); }
.embudo-etapa.activa.etapa-ok, .embudo-etapa.activa.etapa-mal { box-shadow: inset 0 -2px 0 var(--laton-oscuro); }
.embudo-fila {
  display: grid;
  grid-template-columns: repeat(6, minmax(150px, 1fr));
  min-width: 920px;
  border-bottom: 1px solid var(--linea-suave);
}
.embudo-fila:hover { background: var(--superficie-3); }
.embudo-celda {
  border-left: 1px dashed var(--linea-suave);
  padding: 8px;
  min-height: 56px;
}
.embudo-celda:first-child { border-left: none; }
.embudo-carta { position: relative; box-shadow: none; }

/* Miniatura de tareas pendientes en la tarjeta de una oportunidad:
   borde verde (sin vencer), naranja (a punto) o rojo (vencida). */
.tarea-chip {
  position: absolute; top: 6px; right: 6px;
  display: inline-flex; align-items: center; gap: 3px;
  font: 700 var(--t-12)/1 var(--f-datos);
  padding: 2px 6px;
  border-radius: 999px;
  background: var(--superficie);
  border: 2px solid var(--ok);
  color: var(--texto-suave);
}
.tarea-chip svg { width: 11px; height: 11px; }
.tarea-chip.urgencia-verde { border-color: var(--ok); color: var(--ok); }
.tarea-chip.urgencia-naranja { border-color: var(--aviso); color: var(--aviso); }
.tarea-chip.urgencia-rojo { border-color: var(--peligro); color: var(--peligro); }

/* --- Botón de "tarea hecha" en la tabla de tareas --- */
.icono-btn.hecho { color: var(--ok); border-color: var(--ok); background: var(--ok-velo); }

/* ---------------------------------------------------------------------
   Avatar de usuario: foto (miniatura o URL) o iniciales sobre dorado.
   Tamaños: -sm barra superior · -md listas · -lg editor de foto.
   --------------------------------------------------------------------- */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--laton);
  color: var(--laton-tinta);
  font-family: var(--f-ui);
  font-weight: 700;
  overflow: hidden;
  flex: none;
  user-select: none;
}
.avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.avatar-sm { width: 28px; height: 28px; font-size: 11px; }
.avatar-md { width: 36px; height: 36px; font-size: 13px; }
.avatar-lg { width: 72px; height: 72px; font-size: 24px; }

/* =====================================================================
   v0.9.0 · Minifichas de tareas, pop-overs, ficha de producto y avisos
   ===================================================================== */

/* Borde rojo cuando hay tareas pendientes (pedido del 26/07/2026) */
.kanban-carta.tarea-pendiente {
  border: 1.5px solid var(--peligro);
}
.crm-lista-item.tarea-pendiente {
  border: 1.5px solid var(--peligro);
  border-radius: var(--radio-sm);
}
.dato-tarjeta.tarjeta-alerta {
  border: 1.5px solid var(--peligro);
  box-shadow: 0 0 0 3px var(--peligro-velo);
}

/* Minificha de tarea: más alta, con los datos clave a la vista */
.kanban-carta.minificha {
  min-height: 96px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: stretch;
  text-align: left;
}
.minificha-linea {
  display: flex;
  gap: 6px;
  align-items: baseline;
  font-size: var(--t-12);
  min-width: 0;
}
.minificha-etiqueta {
  color: var(--texto-mudo);
  flex: none;
}
.minificha-detalle {
  font-size: var(--t-12);
  color: var(--texto-suave);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Los objetos con pop-up avisan al pasar el ratón */
.minificha-objeto {
  border-bottom: 1px dotted var(--linea-fuerte);
  cursor: help;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.kanban-carta-titulo.minificha-objeto {
  white-space: normal;
  align-self: flex-start;
}
.minificha-objeto:hover {
  background: var(--laton-velo);
  border-bottom-color: var(--laton-oscuro);
}

/* Pop-over de consulta rápida (D-033) */
.popover {
  position: fixed;
  z-index: 300;
  max-width: 360px;
  min-width: 220px;
  background: var(--superficie-3);
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--radio);
  box-shadow: var(--sombra-2);
  padding: 12px 14px;
  font-size: var(--t-13);
  pointer-events: none;
}
.popover-titulo {
  font-weight: 700;
  margin-bottom: 6px;
}
.popover-fila {
  display: flex;
  gap: 8px;
  padding: 1.5px 0;
}
.popover-etiqueta {
  color: var(--texto-mudo);
  flex: none;
  min-width: 96px;
}
.popover-valor {
  color: var(--texto);
  overflow-wrap: anywhere;
}
.popover-detalle {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--linea-suave);
  color: var(--texto-suave);
  white-space: pre-wrap;
}

/* Ficha de producto: modal ancho, pestañas y piezas (D-032).
   Desde v0.9.8, más ancho aún: la tabla de Archivos entra entera
   sin scroll horizontal. */
.modal-lg {
  width: min(1320px, 96vw);
  max-width: 1320px;
}
.ficha-pestanas {
  margin-bottom: var(--e-5);
}
.pestana-atenuada {
  opacity: 0.45;
}
.formulario-rejilla.rejilla-4 {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 720px) {
  .formulario-rejilla.rejilla-4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
.fila-alta {
  display: flex;
  gap: 10px;
  align-items: flex-end;
  flex-wrap: wrap;
  margin-bottom: var(--e-4);
}
.fila-alta .campo {
  min-width: 130px;
  flex: 1;
}
.fila-vigente td {
  background: var(--laton-velo);
}
.icono-producto {
  width: 72px;
  height: 72px;
  flex: none;
  border-radius: var(--radio-sm);
  border: 1px solid var(--linea);
  object-fit: cover;
  background: var(--superficie-2);
}
.icono-producto.icono-vacio {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--texto-mudo);
}
.dropzone {
  border: 2px dashed var(--linea-fuerte);
  border-radius: var(--radio);
  padding: 22px 16px;
  text-align: center;
  color: var(--texto-mudo);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.dropzone:hover,
.dropzone.sobre {
  border-color: var(--laton);
  background: var(--laton-velo);
  color: var(--laton-texto);
}

/* El avatar de la barra superior ahora es un botón (Mi perfil, D-031) */
.avatar-boton {
  cursor: pointer;
  border: none;
  padding: 0;
}

/* v0.9.2 · Miniaturas de producto y de documentación */
.producto-mini {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid var(--linea);
  background: var(--superficie-2);
  color: var(--texto-mudo);
}
.producto-mini img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.producto-mini.producto-mini-vacia svg {
  width: 16px;
  height: 16px;
}
.dropzone.dropzone-compacta {
  flex-direction: row;
  justify-content: center;
  padding: 8px 14px;
  gap: 8px;
  font-size: var(--t-13);
}
.dropzone.dropzone-compacta svg {
  width: 16px;
  height: 16px;
  flex: none;
}
.doc-miniatura {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--linea);
  border-radius: var(--radio-sm);
  background: var(--superficie-2);
  color: var(--texto-mudo);
  overflow: hidden;
  cursor: zoom-in;
}
.doc-miniatura img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.popover-imagen {
  display: block;
  max-width: 320px;
  max-height: 400px;
  width: auto;
  height: auto;
  border: 1px solid var(--linea);
  border-radius: var(--radio-sm);
  margin-bottom: 8px;
  background: #fff;
}
.popover-icono {
  color: var(--texto-mudo);
  margin-bottom: 6px;
}
.popover-icono svg {
  width: 32px;
  height: 32px;
}

/* v0.9.3 · Firmware: subtipo dentro del icono */
.doc-miniatura.doc-firmware {
  flex-direction: column;
  gap: 1px;
  padding: 3px 2px;
}
.doc-miniatura.doc-firmware svg {
  width: 16px;
  height: 16px;
  flex: none;
}
.doc-mini-sub {
  font-size: 7.5px;
  line-height: 1.1;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-align: center;
  color: var(--laton-texto);
  max-width: 100%;
  overflow: hidden;
}

/* v0.9.5 · Miniatura del listado ampliable al pasar el ratón */
.producto-mini.producto-mini-ampliable {
  cursor: zoom-in;
}
.popover-imagen-producto {
  max-width: 280px;
  max-height: 280px;
  margin-bottom: 0;
}

/* v0.9.5 · Interruptores de descarga por archivo (pestaña Archivos).
   Desde v0.9.8 en rejilla 2×2: compactos y siempre alineados. */
.descarga-interruptores {
  display: grid;
  grid-template-columns: auto auto;
  gap: 4px 14px;
  width: max-content;
}
.descarga-interruptores .interruptor .etiqueta {
  font-size: var(--t-12);
}

/* v0.9.7 · Tabla de Archivos: scroll vertical solo de filas (cabecera
   fija con position sticky) y cabeceras ordenables con su flecha */
.archivos-tabla {
  max-height: 420px;
  overflow-y: auto;
}
.archivos-tabla thead th {
  position: sticky;
  top: 0;
  z-index: 2;
}
.th-ordenable {
  cursor: pointer;
  user-select: none;
}
.th-ordenable:hover {
  color: var(--texto);
}
.orden-flecha {
  margin-left: 4px;
  font-size: 8px;
  color: var(--laton-oscuro);
}

/* v0.9.9 · QR y código de barras EAN-13 en la cabecera de la ficha */
.ficha-codigos {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0 10px;
  flex: none;
}
.ficha-qr svg {
  width: 56px;
  height: 56px;
  display: block;
}
.ficha-ean {
  color: var(--texto);
}
.ficha-ean svg {
  height: 56px;
  width: auto;
  display: block;
}

/* =====================================================================
   BOM multinivel (v0.10, D-039): árbol de la pestaña «BOM» de la ficha
   ===================================================================== */
.bom-barra {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  margin-bottom: var(--e-2);
}
.bom-arbol {
  list-style: none;
  margin: 0;
  padding: 0;
}
.bom-arbol:not(.bom-arbol-raiz) {
  margin-left: 30px;
  padding-left: var(--e-2);
  border-left: 1px solid var(--linea);
}
.bom-nodo { margin: 2px 0; }
.bom-fila {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  padding: 4px 6px;
  border-radius: var(--radio-sm);
}
.bom-fila:hover { background: var(--superficie-2); }
.bom-caret {
  border: 0;
  background: none;
  cursor: pointer;
  width: 22px;
  height: 22px;
  flex: 0 0 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--laton-texto);
  font-size: var(--t-14);
  transition: transform 0.15s ease;
}
.bom-caret svg { width: 14px; height: 14px; }
.bom-caret-abierta { transform: rotate(90deg); }
.bom-caret-hueca { visibility: hidden; }
.bom-mini { width: 28px; height: 28px; flex: 0 0 28px; }
.bom-sku { min-width: 100px; font-size: var(--t-13); }
.bom-nombre { font-size: var(--t-14); }
.bom-cantidad {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--t-13);
  color: var(--texto-suave);
}
.bom-cantidad-input {
  width: 78px;
  padding: 3px 8px;
  font-family: var(--f-datos);
  font-size: var(--t-13);
}
.bom-acciones { display: inline-flex; gap: 4px; }

/* Buscador del componente a añadir */
.bom-resultados {
  margin-top: var(--e-2);
  max-height: 300px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.bom-resultado {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  text-align: left;
  padding: 8px 10px;
  border: 1px solid var(--linea);
  border-radius: var(--radio-sm);
  background: var(--superficie);
  cursor: pointer;
  font-size: var(--t-13);
}
.bom-resultado:hover { border-color: var(--laton); background: var(--laton-velo); }
.bom-resultado .mono { min-width: 100px; }
.bom-resultado .badge { margin-left: auto; }

/* =====================================================================
   v0.11 · BOM Manager (M-04) y visor STEP
   ===================================================================== */

/* --- Piezas comunes nuevas --- */
.buscador-lleno { width: 100%; max-width: none; }
.buscador-lleno input { width: 100%; }
.interruptor-sm .etiqueta { font-size: var(--t-12); }

.paso-step {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border: 1px solid var(--laton-oscuro);
  border-radius: 999px; background: var(--laton-velo);
  color: var(--laton-texto); font-size: var(--t-12); font-weight: 600;
  cursor: pointer; letter-spacing: .04em;
}
.paso-step:hover { background: var(--laton); color: var(--laton-tinta); }
.paso-step svg { width: 13px; height: 13px; }

/* --- BOM Manager: dos mitades --- */
.bomm-cuerpo {
  display: grid; grid-template-columns: minmax(320px, 2fr) 3fr;
  height: calc(100vh - 190px); min-height: 460px; overflow: hidden;
}
.bomm-izq {
  border-right: 1px solid var(--linea);
  display: flex; flex-direction: column; gap: var(--e-2);
  padding: var(--e-3); min-width: 0;
}
.bomm-lista { overflow-y: auto; flex: 1; min-height: 0; }
.bomm-vacio { padding: var(--e-3); }
.bomm-fila {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 8px; border-radius: 8px; cursor: pointer;
  border: 1px solid transparent;
}
.bomm-fila:hover { background: var(--superficie-2); border-color: var(--linea); }
.bomm-fila[draggable="true"] { cursor: grab; }
.bomm-arrastrando { opacity: .45; }
.bomm-fila-texto { flex: 1; min-width: 0; }
.bomm-fila-texto > div:first-child {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bomm-sku { font-size: var(--t-13); margin-right: 6px; }
.bomm-nombre { font-size: var(--t-14); }
.bomm-fila-badges { display: flex; gap: 6px; margin-top: 2px; flex-wrap: wrap; }
.bomm-fila-acciones { display: flex; gap: 6px; align-items: center; }

.bomm-der { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.bomm-sin-raiz { display: flex; align-items: center; justify-content: center; height: 100%; }
.bomm-sin-raiz-caja { max-width: 420px; text-align: center; color: var(--texto-suave); padding: var(--e-5); }
.bomm-sin-raiz-caja svg { width: 42px; height: 42px; color: var(--laton-oscuro); margin-bottom: var(--e-3); }

.bomm-cab {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--e-3); flex-wrap: wrap;
  padding: var(--e-3); border-bottom: 1px solid var(--linea);
  background: var(--superficie-2);
}
.bomm-cab-quien { display: flex; align-items: center; gap: 10px; min-width: 0; }
.bomm-cab-nombre { font-size: var(--t-15); }
.bomm-props { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 4px; color: var(--texto-suave); font-size: var(--t-13); }
.bomm-props strong { color: var(--texto); font-variant-numeric: tabular-nums; }
.bomm-cab-acciones { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.bomm-arbol { overflow: auto; flex: 1; min-height: 0; padding: var(--e-2) var(--e-3); }

/* Zona de soltado del arrastre: la rama se ilumina */
.bom-soltar {
  outline: 2px dashed var(--laton-oscuro); outline-offset: -2px;
  background: var(--laton-velo) !important; border-radius: 8px;
}

/* --- Visor STEP --- */
.visor-velo {
  position: fixed; inset: 0; z-index: 300;
  background: var(--fondo);
  display: flex; flex-direction: column;
}
.visor-cabecera {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-3); padding: 10px var(--e-4);
  border-bottom: 1px solid var(--linea); background: var(--superficie);
  flex-wrap: wrap;
}
.visor-titulo { display: flex; align-items: center; gap: 10px; min-width: 0; }
.visor-titulo > svg { width: 26px; height: 26px; color: var(--laton-oscuro); flex: 0 0 auto; }
.visor-nombre { font-weight: 600; font-size: var(--t-15); }
.visor-sub { font-size: var(--t-12); }
.visor-mandos { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.visor-cuerpo { display: flex; flex: 1; min-height: 0; }
.visor-lateral {
  width: 320px; flex: 0 0 320px; border-right: 1px solid var(--linea);
  background: var(--lateral-fondo);
  display: flex; flex-direction: column; gap: var(--e-2); padding: var(--e-3);
  min-height: 0;
}
.visor-arbol { overflow: auto; flex: 1; min-height: 0; font-size: var(--t-13); }
.visor-nodo-fila { display: flex; align-items: center; gap: 2px; border-radius: 6px; }
.visor-nodo-fila:hover { background: var(--superficie-2); }
.visor-nodo-ojo {
  border: 0; background: none; cursor: pointer; color: var(--texto-mudo);
  display: inline-flex; padding: 3px; border-radius: 6px; flex: 0 0 auto;
}
.visor-nodo-ojo:hover { color: var(--texto); background: var(--linea-suave); }
.visor-nodo-ojo.apagado { color: var(--linea-fuerte); }
.visor-nodo-ojo svg { width: 15px; height: 15px; }
.visor-nodo-nombre {
  border: 0; background: none; cursor: pointer; color: var(--texto);
  text-align: left; padding: 4px 6px; border-radius: 6px; flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--t-13);
}
.visor-nodo-nombre.activa { background: var(--laton-velo); color: var(--laton-texto); font-weight: 600; }
.visor-lienzo { flex: 1; position: relative; min-width: 0; background: #f6f4ef; }
.visor-canvas { position: absolute; inset: 0; width: 100% !important; height: 100% !important; display: block; }
.visor-pie {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; justify-content: space-between; gap: var(--e-3); flex-wrap: wrap;
  padding: 6px var(--e-3); font-size: var(--t-12);
  background: rgba(255, 255, 255, .82); border-top: 1px solid var(--linea);
}
.visor-estado {
  position: absolute; inset: 0; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  background: rgba(246, 244, 239, .94);
}
.visor-estado-caja { text-align: center; color: var(--texto-suave); max-width: 420px; padding: var(--e-4); }
.visor-estado-caja > div:nth-child(2) { font-size: var(--t-15); font-weight: 600; color: var(--texto); margin-bottom: 4px; }
.visor-estado-error .cargando-anillo { display: none; }
.visor-estado-error > .visor-estado-caja > div:nth-child(2) { color: var(--peligro); }
.cargando-anillo {
  width: 34px; height: 34px; margin: 0 auto var(--e-3);
  border: 3px solid var(--linea); border-top-color: var(--laton-oscuro);
  border-radius: 50%; animation: visor-giro 0.9s linear infinite;
}
@keyframes visor-giro { to { transform: rotate(360deg); } }

@media (max-width: 900px) {
  .bomm-cuerpo { grid-template-columns: 1fr; height: auto; }
  .bomm-izq { border-right: 0; border-bottom: 1px solid var(--linea); max-height: 45vh; }
  .visor-lateral { width: 240px; flex-basis: 240px; }
}

/* v0.11.2 · mover líneas dentro del árbol del BOM Manager */
.bomm-der .bom-fila[draggable="true"] { cursor: grab; }
.bomm-der .bom-fila[draggable="true"]:active { cursor: grabbing; }

/* =====================================================================
   v0.11.3 · Resumen del BOM, desplegable de BOM y ventana del MASTER BOM
   ===================================================================== */

/* --- Resumen del BOM (pestaña BOM de la ficha y ventana del BOM) --- */
.bom-resumen {
  margin: var(--e-2) 0 var(--e-3);
  padding: var(--e-3);
  background: var(--superficie-2);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
}
.bom-resumen-cifras {
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
  color: var(--texto-suave);
  font-size: var(--t-13);
  margin-bottom: var(--e-2);
}
.bom-resumen-cifras strong {
  color: var(--texto);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-15);
}
.bom-resumen-tabla { max-height: 240px; overflow: auto; }
.bom-resumen-tabla .tabla-llana { font-size: var(--t-13); }
.bom-resumen-tabla th.der,
.bom-resumen-tabla td.der { text-align: right; }
.bom-resumen-semi td { color: var(--texto-suave); font-style: italic; }

/* --- Campos que se rellenan eligiendo, no escribiendo --- */
.campo-fila-botones { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.campo-boton {
  justify-content: flex-start;
  min-width: 260px;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.enlace-bom {
  background: none;
  border: none;
  padding: 0;
  color: var(--laton-oscuro);
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.enlace-bom:hover { color: var(--laton-tinta); }

/* --- El desplegable de BOM --- */
.bomsel-lista {
  margin-top: var(--e-2);
  max-height: 46vh;
  overflow: auto;
  border: 1px solid var(--linea-suave);
  border-radius: var(--radio-sm);
}
.bomsel-fila {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  background: none;
  border: none;
  border-bottom: 1px solid var(--linea-suave);
  text-align: left;
  cursor: pointer;
  font: inherit;
}
.bomsel-fila:last-child { border-bottom: none; }
.bomsel-fila:hover { background: var(--laton-velo); }
.bomsel-sku { font-size: var(--t-13); min-width: 96px; }
.bomsel-nombre { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bomsel-lineas { font-size: var(--t-12); white-space: nowrap; }

/* --- La ventana del BOM --- */
.bomvent-cab {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding-bottom: var(--e-2);
  border-bottom: 1px solid var(--linea);
}
.bomvent-quien { flex: 1; min-width: 200px; }
.bomvent-sub { font-size: var(--t-12); }
.bomvent-botones { display: flex; gap: 6px; }
.bomvent-arbol { max-height: 46vh; overflow: auto; padding: var(--e-1) 0; }

/* --- v0.11.4 · Pestaña MASTER BOM: historial y resumen del BOM Activo --- */
.mbom-historial .bom-resumen { margin-top: 0; }
.mbom-activo-cab {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: var(--e-3);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--linea-suave);
  font-size: var(--t-13);
  color: var(--texto-suave);
}
.mbom-activo-cab strong { color: var(--texto); }

/* --- Visor de Gerber (v0.13, D-053) ------------------------------- */
/* La escena es un marco que se mueve y se acerca; dentro van las capas
   apiladas como hojas de calco, todas con el mismo encuadre. */
.gerber-escena { position: absolute; inset: 0; display: grid; place-items: center; overflow: hidden; }
.gerber-marco {
  position: relative; width: 86%; height: 86%;
  transform-origin: center center; will-change: transform;
}
.gerber-hoja { position: absolute; inset: 0; }
.gerber-hoja svg { width: 100%; height: 100%; display: block; }
.gerber-tinta {
  width: 10px; height: 10px; border-radius: 3px; flex: 0 0 auto;
  margin: 0 4px 0 2px; border: 1px solid rgba(0, 0, 0, .18);
}
.visor-lienzo.agarrando { cursor: grabbing; }
.visor-lienzo:has(.gerber-marco) { cursor: grab; }

/* Selector compacto de la barra del visor (Placa/Capas, Arriba/Abajo) */
.visor-seg { display: inline-flex; border: 1px solid var(--linea); border-radius: 999px; overflow: hidden; background: var(--superficie); }
.visor-seg-op {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  padding: 6px 12px; color: var(--texto-suave);
  font: 500 var(--t-12)/1 var(--f-ui);
}
.visor-seg-op + .visor-seg-op { border-left: 1px solid var(--linea); }
.visor-seg-op:hover { background: var(--superficie-2); color: var(--texto); }
.visor-seg-op.activa { background: var(--laton); color: var(--laton-tinta); font-weight: 700; }

/* El visor de Ucamco, empotrado */
.visor-iframe { flex: 1; width: 100%; height: 100%; border: 0; display: block; background: #2b333c; }
.ucamco-tira {
  display: flex; align-items: center; gap: var(--e-4); flex-wrap: wrap;
  padding: 8px var(--e-4); border-bottom: 1px solid var(--linea);
  background: var(--laton-velo); font-size: var(--t-12);
}
.ucamco-tira strong {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; margin-right: 6px; border-radius: 50%;
  background: var(--laton); color: var(--laton-tinta); font-size: var(--t-11, 11px);
}

/* --- Pestaña «Archivos»: que quepa todo (v0.14.1) ------------------ */
/* El nombre del archivo puede ser larguísimo («…Gerber_Wadax multi
   carrier_v1.0_2024-04-23.zip»). Antes empujaba la tabla hacia la
   derecha y los iconos de tipo se salían de la ventana. Ahora el
   nombre se recorta con puntos suspensivos —el nombre entero sigue en
   el título y en la vista previa— y el icono no se encoge nunca. */
.doc-celda-nombre { max-width: 280px; }
.doc-nombre { max-width: 100%; }
.doc-nombre span {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: inline-block; max-width: 100%; vertical-align: bottom;
}
.doc-celda-nombre .paso-step { flex: 0 0 auto; margin-left: 6px; }

/* El desplegable de categoría no necesita 200 px para decir «CAD» */
.archivos-tabla .campo-llano { min-width: 108px; max-width: 150px; }

/* La franja de subida y la tabla no se salen de la ficha */
.archivos-tabla { max-width: 100%; }
.archivos-tabla table { min-width: 0; }

/* La columna «Tipo»: estrecha, pegada a la miniatura y nunca se encoge */
.th-tipo { width: 1%; }
.doc-celda-tipo { white-space: nowrap; padding-left: 0 !important; padding-right: 6px !important; }

/* Fecha y tamaño, compactos: no necesitan romperse en dos líneas */
.archivos-tabla td, .archivos-tabla th { white-space: nowrap; }
.archivos-tabla .doc-celda-nombre { white-space: normal; }

/* Chip de tipo apagado: el archivo no se abre dentro de WERP, solo se
   descarga (firmware, Inventor, DWG, binarios sueltos) — v0.14.2 */
.paso-step.paso-tipo-apagado {
  border-color: var(--linea); background: var(--superficie-2);
  color: var(--texto-mudo); font-weight: 500;
}
.paso-step.paso-tipo-apagado:hover { background: var(--linea-suave); color: var(--texto); }

/* ---------------------------------------------------------------------
   Capacidad y consumo (v0.15) · las barras de «cuánto margen queda»
   --------------------------------------------------------------------- */
.cap-rejilla {
  display: grid; gap: var(--e-3);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.cap-tarjeta {
  border: 1px solid var(--linea); border-radius: var(--radio-2);
  background: var(--superficie-2); padding: var(--e-4);
}
.cap-titulo {
  font-family: var(--f-datos); font-size: 10px; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase; color: var(--texto-mudo);
}
.cap-cifra { font-size: var(--t-18); margin: 4px 0 8px; }
.cap-barra {
  height: 8px; border-radius: 999px; background: var(--linea);
  overflow: hidden;
}
.cap-barra > span { display: block; height: 100%; background: var(--laton); border-radius: 999px; }
.cap-barra.cap-barra-aviso > span { background: color-mix(in srgb, var(--laton) 40%, orange); }
.cap-barra.cap-barra-peligro > span { background: var(--peligro); }
.cap-pie { font-size: var(--t-13); margin-top: 6px; }

/* El total del cronómetro de desarrollo (v0.35.0): la misma tarjeta de
   arriba, pero con la cifra en grande. Es lo que lleva costando WERP y
   es lo primero que hay que ver al llegar a la sección; las demás
   cifras de Ajustes se consultan, esta se mira. */
.cap-cifra-grande {
  font-family: var(--f-titulos); font-size: var(--t-28);
  font-weight: 700; line-height: 1.1;
}

/* =====================================================================
   v0.16 · El PCB y sus tres SKU (D-056)
   ---------------------------------------------------------------------
   Semáforo: rojo mientras falte alguna de las tres, verde cuando están
   las tres. Se usa en la columna «Tipo» del listado, en la pestaña PCB
   y en el resumen de la propia pestaña.
   ===================================================================== */
.semaforo {
  display: inline-block; width: 10px; height: 10px; border-radius: 999px;
  flex: 0 0 auto; margin-left: 6px; vertical-align: middle;
  border: 1px solid rgba(0, 0, 0, .18);
}
.semaforo-ok { background: var(--ok); }
.semaforo-falta { background: var(--peligro); }
.celda-tipo { display: inline-flex; align-items: center; gap: 2px; }
.badge-pcb { background: var(--laton-velo); color: var(--laton-texto); border: 1px solid color-mix(in srgb, var(--laton) 45%, transparent); }

.pcb-zona { display: flex; flex-direction: column; gap: var(--e-4); }
.pcb-resumen { display: flex; align-items: center; gap: 8px; }
.pcb-resumen-texto { font: 600 var(--t-14)/1.4 var(--f-ui); color: var(--texto); }
.pcb-huecos { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--e-3); }
.pcb-hueco {
  border: 1px solid var(--linea); border-radius: 10px; padding: var(--e-3);
  background: var(--superficie); display: flex; flex-direction: column; gap: 6px;
}
.pcb-hueco-falta { border-color: color-mix(in srgb, var(--peligro) 35%, var(--linea)); background: var(--peligro-velo); }
.pcb-hueco-puesta { border-color: color-mix(in srgb, var(--ok) 30%, var(--linea)); }
.pcb-hueco-cab { display: flex; align-items: center; gap: 6px; }
.pcb-hueco-titulo { font: 700 var(--t-14)/1.2 var(--f-titulos); color: var(--texto); flex: 1; }
.pcb-hueco-cuerpo { display: flex; flex-direction: column; gap: 8px; }
.pcb-sku { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pcb-sku-cod { font-weight: 700; color: var(--laton-texto); }
.pcb-sku-nombre { flex: 1; min-width: 120px; color: var(--texto); }
.pcb-acciones { display: flex; gap: 6px; flex-wrap: wrap; }

/* =====================================================================
   v0.16 · Las capas del Gerber colgando del ZIP (D-056)
   ---------------------------------------------------------------------
   En la pestaña «Archivos» el ZIP deja de ser un bulto: cada capa
   cuelga de él como una rama, con su color, su miniatura al pasar el
   ratón y su propio botón de visor.
   ===================================================================== */
.doc-caret {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  color: var(--texto-mudo); padding: 2px 4px; line-height: 1;
  transition: transform .12s ease;
}
.doc-caret:hover { color: var(--laton-texto); }
.doc-caret.abierta { transform: rotate(90deg); }
.archivos-tabla tr.fila-capa > td { background: var(--superficie-2); border-top: 1px solid var(--linea-suave); }
.archivos-tabla tr.fila-capa.oculto { display: none; }
.doc-capa-sangria { display: inline-flex; align-items: center; gap: 6px; padding-left: 22px; }
.doc-capa-nombre { font: 500 var(--t-13)/1.3 var(--f-ui); color: var(--texto); }
.doc-capa-fichero { font-size: var(--t-12); color: var(--texto-mudo); }
.doc-capa-cuenta { font-size: var(--t-12); color: var(--texto-mudo); margin-left: 6px; }
.doc-capa-mini { width: 34px; height: 26px; object-fit: contain; border: 1px solid var(--linea); border-radius: 3px; background: #fff; }

/* =====================================================================
   v0.17 · El visor de Gerber enseña el ZIP entero
   ---------------------------------------------------------------------
   Cada capa lleva a su derecha las letras de su extensión (GTL, GBL,
   TXT…), que es como se la nombra en Altium. Y debajo de las capas
   cuelgan los demás ficheros del ZIP —los informes—, que se leen en el
   propio visor.
   ===================================================================== */
.capa-ext {
  margin-left: auto; flex: 0 0 auto;
  font: 700 var(--t-12)/1 var(--f-datos);
  letter-spacing: .04em;
  color: var(--laton-texto);
  background: var(--laton-velo);
  border: 1px solid color-mix(in srgb, var(--laton) 45%, transparent);
  border-radius: 4px; padding: 3px 5px;
}
.gerber-tinta-hueca { background: transparent !important; border-style: dashed; }
.visor-arbol-titulo {
  margin: var(--e-3) 0 4px; padding-top: var(--e-2);
  border-top: 1px solid var(--linea);
  font: 700 var(--t-12)/1.2 var(--f-titulos);
  color: var(--texto-mudo); text-transform: uppercase; letter-spacing: .05em;
}
.visor-nodo-nombre.apagado { color: var(--texto-mudo); font-style: italic; }

/* Leer un fichero del ZIP dentro del visor */
.gerber-escena:has(.gerber-texto-caja) { overflow: auto; place-items: stretch; }
.gerber-texto-caja { width: 100%; height: 100%; display: flex; flex-direction: column; background: var(--superficie); }
.gerber-texto-cab {
  display: flex; align-items: center; gap: 8px;
  padding: 10px var(--e-4); border-bottom: 1px solid var(--linea);
  background: var(--superficie-2); position: sticky; top: 0; z-index: 1;
}
.gerber-texto-nombre { font: 700 var(--t-14)/1.2 var(--f-titulos); color: var(--texto); flex: 1; }
.gerber-texto {
  margin: 0; padding: var(--e-4); flex: 1; overflow: auto;
  font: 400 var(--t-13)/1.5 var(--f-datos);
  color: var(--texto); white-space: pre; tab-size: 4;
  user-select: text;
}

/* =====================================================================
   NORMATIVA DE FICHEROS (v0.19, D-060)
   El semáforo, el informe de «¿Qué falta?» y la lista de Ajustes.
   Solo tokens: ni un color suelto.
   ===================================================================== */
.aviso.aviso-ok { border-color: color-mix(in srgb, var(--ok) 40%, transparent); background: var(--ok-velo); color: var(--ok); }

/* --- El semáforo, como pastilla --- */
.nor-luz {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  padding: 4px 10px; border-radius: 999px; border: 1px solid var(--linea);
  font: 700 var(--t-12)/1 var(--f-ui); letter-spacing: .02em;
}
.nor-luz svg { width: 14px; height: 14px; }
.nor-luz-ok { color: var(--ok); background: var(--ok-velo); border-color: color-mix(in srgb, var(--ok) 35%, transparent); }
.nor-luz-aviso { color: var(--aviso); background: var(--aviso-velo); border-color: color-mix(in srgb, var(--aviso) 35%, transparent); }
.nor-luz-falta { color: var(--peligro); background: var(--peligro-velo); border-color: color-mix(in srgb, var(--peligro) 35%, transparent); }
.nor-luz-mudo { color: var(--texto-mudo); }

/* Ancho intermedio: .modal son 660px y .modal-lg 1320px. El informe de
   normativa pide algo en medio: las tarjetas se leen mal más estrechas y
   no necesitan una pantalla entera. */
.modal-md { width: min(860px, 96vw); max-width: 860px; }

/* --- El informe --- */
.nor-informe { display: flex; flex-direction: column; gap: var(--e-4); }
.nor-cabecera { display: flex; align-items: flex-start; gap: var(--e-3); }
.nor-cabecera-texto { flex: 1; min-width: 0; }
.nor-frase { font: 700 var(--t-15)/1.35 var(--f-titulos); color: var(--texto); margin-bottom: 4px; }
.nor-elementos { display: flex; flex-direction: column; gap: var(--e-3); max-height: 52vh; overflow: auto; }

.nor-elemento {
  border: 1px solid var(--linea); border-left-width: 3px; border-radius: 10px;
  padding: var(--e-3); background: var(--superficie);
  display: flex; flex-direction: column; gap: 6px;
}
.nor-elemento-falta { border-left-color: var(--peligro); }
.nor-elemento-aviso { border-left-color: var(--aviso); }
.nor-elemento-cab { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.nor-elemento-sku { font-weight: 700; color: var(--laton-texto); }
.nor-elemento-nombre { flex: 1; min-width: 120px; color: var(--texto); }
.nor-elemento-tipo { font: 500 var(--t-12)/1.2 var(--f-ui); }

.nor-lista { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.nor-lista li { font: 500 var(--t-13)/1.45 var(--f-ui); color: var(--texto-suave); }
.nor-lista li strong { color: var(--texto); }

.nor-etiqueta {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  font: 700 var(--t-12)/1.6 var(--f-ui); letter-spacing: .03em; text-transform: uppercase;
  border: 1px solid transparent;
}
.nor-etiqueta-falta { color: var(--peligro); background: var(--peligro-velo); border-color: color-mix(in srgb, var(--peligro) 30%, transparent); }
.nor-etiqueta-aviso { color: var(--aviso); background: var(--aviso-velo); border-color: color-mix(in srgb, var(--aviso) 30%, transparent); }

/* --- La lista de Ajustes --- */
.nor-acciones { white-space: nowrap; }
.nor-acciones > * { margin-right: 6px; vertical-align: middle; }
.nor-fila-off { opacity: .55; }

@media (max-width: 720px) {
  .nor-cabecera { flex-direction: column; }
  .nor-elementos { max-height: none; }
}

/* =====================================================================
   M-11 · Tareas y Proyectos (v0.23)
   ---------------------------------------------------------------------
   Tres piezas: la tarjeta del escritorio (que reaprovecha .kanban-* y
   .minificha del CRM), el lienzo del Gantt y las tablas de carga y
   costes. Solo tokens de tokens.css: ni un color suelto.
   ===================================================================== */

/* --- Adornos compartidos --- */
.tar-punto {
  display: inline-block; width: 9px; height: 9px; border-radius: 999px;
  flex: none; box-shadow: 0 0 0 1px rgba(0, 0, 0, .08);
}
.tar-celda-proyecto { display: flex; align-items: center; gap: 7px; min-width: 0; }
.tar-celda-proyecto span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.tar-avance { display: flex; align-items: center; gap: 8px; }
.tar-avance-canal {
  flex: 1 1 60px; height: 7px; border-radius: 999px;
  background: var(--superficie-2); border: 1px solid var(--linea-suave); overflow: hidden;
}
.tar-avance-relleno { height: 100%; background: var(--laton); transition: width .2s ease; }
.tar-avance-cifra { font: 700 var(--t-12)/1 var(--f-datos); color: var(--texto-suave); flex: none; }
.tar-avance-sm .tar-avance-canal { height: 5px; }
.tar-avance-editor { display: flex; align-items: center; gap: var(--e-3); }
.tar-avance-editor input[type="range"] { flex: 1; accent-color: var(--laton-oscuro); }
.tar-avance-editor output { font: 700 var(--t-13)/1 var(--f-datos); color: var(--laton-texto); min-width: 44px; }

.tar-resumen-linea {
  display: flex; gap: var(--e-4); flex-wrap: wrap; align-items: baseline;
  margin-bottom: var(--e-3);
}
.tar-resumen-dato { font-size: var(--t-12); color: var(--texto-mudo); }
.tar-resumen-dato strong { font: 700 var(--t-18)/1 var(--f-datos); color: var(--texto); margin-right: 3px; }
.tar-resumen-dato.tar-alerta strong { color: var(--peligro); }

/* --- LAS TRES CIFRAS QUE SE PINCHAN · v0.62.0 ------------------------
   «Abiertas», «vencidas» y «bloqueadas» filtran el tablero. Son botones
   de verdad —se alcanzan con el tabulador y se disparan con Enter—, así
   que hay que quitarles la pinta de botón del navegador y dejarlas
   exactamente igual que sus vecinas, que no se pinchan. La diferencia
   tiene que verse SOLO al pasar el ratón y al estar puestas: una línea
   de cifras donde tres parecen botones y dos no es una línea que se lee
   dos veces. */
button.tar-resumen-dato {
  display: inline-flex; align-items: baseline; gap: 0;
  border: 1px solid transparent; border-radius: var(--radio-sm);
  padding: 2px 6px; margin: -2px 0;
  background: none; font-family: var(--f-ui); cursor: pointer;
  /* Sin esto la línea de cifras se descuadra: la barra de filtros alinea
     por `baseline` y un botón crea su propio contexto. */
  vertical-align: baseline;
}
button.tar-resumen-dato:hover { border-color: var(--linea); background: var(--laton-velo); }
button.tar-resumen-dato:focus-visible { outline: 2px solid var(--laton); outline-offset: 1px; }
/* PUESTA: dorada y con el fondo tocado. No basta con el color —hay quien
   no lo distingue—: el marco entero cambia, y `aria-pressed` lo dice en
   voz alta para quien no ve ninguna de las dos cosas. */
button.tar-resumen-dato.puesto {
  border-color: var(--laton-oscuro); background: var(--laton-velo);
}
button.tar-resumen-dato.puesto strong { color: var(--laton-texto); }
button.tar-resumen-dato.puesto span { color: var(--texto); }
.tar-pie-ayuda { font-size: var(--t-12); margin-top: var(--e-2); }

/* --- Paneles de la ficha (horas y esperas) --- */
.tar-panel {
  margin-top: var(--e-5); padding-top: var(--e-4);
  border-top: 1px solid var(--linea-suave);
}
.tar-panel-cab {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-3); flex-wrap: wrap; margin-bottom: var(--e-2);
}
.tar-panel-cab h3 {
  display: flex; align-items: center; gap: 7px; margin: 0;
  font: 600 var(--t-14)/1.2 var(--f-titulos); color: var(--texto);
}
.tar-panel-cab h3 svg { width: 17px; height: 17px; color: var(--laton-texto); }

.tar-horas-alta {
  display: flex; gap: var(--e-2); flex-wrap: wrap; align-items: center; margin-top: var(--e-3);
}
.tar-horas-alta input[type="date"] { max-width: 160px; }
.tar-horas-alta input[type="number"] { max-width: 110px; }
.tar-horas-alta input[type="text"] { flex: 1 1 180px; min-width: 140px; }
.tar-horas-alta select { max-width: 240px; }
.tar-horas-lista { display: flex; flex-direction: column; gap: 4px; }
.tar-horas-fila {
  display: flex; gap: var(--e-3); align-items: center; flex-wrap: wrap;
  padding: 6px 10px; border: 1px solid var(--linea-suave);
  border-radius: var(--radio-sm); background: var(--superficie-2);
  font-size: var(--t-13);
}
.tar-horas-fecha { font-family: var(--f-datos); color: var(--texto-mudo); flex: none; }
.tar-horas-quien { font-weight: 500; flex: 0 1 180px; min-width: 120px; }
.tar-horas-cifra { font: 700 var(--t-13)/1 var(--f-datos); color: var(--laton-texto); flex: none; }
.tar-horas-coste { color: var(--texto-suave); flex: none; }
.tar-horas-nota { color: var(--texto-mudo); flex: 1 1 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- v0.26 · el equipo del proyecto y su expediente de ficheros ----- */
.tar-equipo-alta {
  display: flex; gap: var(--e-2); flex-wrap: wrap; align-items: center;
  margin: var(--e-3) 0;
}
.tar-equipo-alta select { flex: 0 1 240px; min-width: 170px; }
.tar-equipo-puesto { flex: 1 1 120px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tar-arch-botones { display: flex; gap: 6px; align-items: center; flex: none; flex-wrap: wrap; }
.tar-arch-select { flex: none; max-width: 190px; font-size: var(--t-12); }
.tar-arch-grupo { margin-top: var(--e-3); }
.tar-arch-cab {
  display: flex; align-items: center; gap: 8px; margin-bottom: 5px;
  padding-bottom: 4px; border-bottom: 1px solid var(--linea-suave);
}
.tar-arch-cat {
  font: 700 var(--t-12)/1 var(--f-ui); color: var(--texto-mudo);
  text-transform: uppercase; letter-spacing: .06em;
}

/* --- Elegir el color del proyecto --- */
.tar-colores { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.tar-color {
  width: 26px; height: 26px; border-radius: 999px; cursor: pointer;
  border: 2px solid transparent; box-shadow: 0 0 0 1px var(--linea);
}
.tar-color.elegido { border-color: var(--texto); }
.tar-color:disabled { cursor: default; }
.tar-color-libre {
  width: 40px; height: 28px; padding: 0; border: 1px solid var(--linea);
  border-radius: var(--radio-sm); background: var(--superficie); cursor: pointer;
}

/* --- El escritorio (sobre el Kanban del CRM) --- */
.tar-carta { cursor: pointer; }
.tar-carta-cab { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.tar-carta-pie { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.tar-carta-hito { border-left: 3px solid var(--laton-oscuro); }
.tar-enlace-proyecto {
  appearance: none; background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: var(--laton-texto); text-align: left;
  border-bottom: 1px dotted var(--linea-fuerte); max-width: 100%;
}
.tar-enlace-proyecto:hover { background: var(--laton-velo); border-bottom-color: var(--laton-oscuro); }

/* =====================================================================
   El Gantt
   Rejilla de filas de alto fijo (--alto-fila) con la columna izquierda
   pegada (sticky) y las barras en posiciones absolutas sobre la pista.
   Es lo único que mantiene cada texto alineado con su barra cuando hay
   scroll horizontal y vertical a la vez.
   ===================================================================== */
.tar-gantt-cabecera { margin-bottom: var(--e-3); }
.tar-gantt-ficha {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-4); flex-wrap: wrap;
  border: 1px solid var(--linea); border-radius: var(--radio);
  background: var(--superficie-2); padding: var(--e-3) var(--e-4);
}
.tar-gantt-ficha-izq { display: flex; align-items: center; gap: var(--e-3); min-width: 0; }
.tar-gantt-ficha-der { display: flex; align-items: center; gap: var(--e-4); flex-wrap: wrap; }
.tar-gantt-ficha-der .tar-avance { min-width: 140px; }
.tar-gantt-titulo { font: 600 var(--t-15)/1.25 var(--f-titulos); color: var(--texto); }

.tar-gantt {
  overflow: auto;
  max-height: calc(100vh - 330px);
  min-height: 320px;
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  background: var(--superficie);
}
.tar-gantt-marco { display: inline-block; min-width: 100%; --ancho-izq: 430px; --alto-fila: 34px; }
.tar-gantt-fila-cab { display: flex; position: sticky; top: 0; z-index: 3; }
.tar-gantt-cuerpo { display: flex; align-items: flex-start; }
.tar-gantt-izq {
  width: var(--ancho-izq); flex: none;
  position: sticky; left: 0; z-index: 2;
  background: var(--superficie);
  border-right: 1px solid var(--linea);
}
.tar-gantt-cab-izq, .tar-gantt-cab-der { background: var(--superficie-2); }
.tar-gantt-cab-izq { z-index: 4; border-bottom: 1px solid var(--linea); }
.tar-gantt-der {
  flex: none; position: relative;
  /* v0.26 · TODO lo del lienzo (rayas de festivo, barras arrastradas,
     hitos, puntos de enganche, cable) vive dentro de esta capa y no
     puede colarse por encima de la columna de tareas al desplazar el
     tiempo. `isolation` encierra las alturas de dentro; el z-index 0
     las deja por debajo de la columna, que va en la 2. */
  z-index: 0;
}
.tar-gantt-cab-der { border-bottom: 1px solid var(--linea); }

.tar-gantt-fila, .tar-gantt-cab-izq {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) 86px 76px 76px;
  gap: 4px; align-items: center;
  height: var(--alto-fila);
  padding: 0 8px;
  font-size: var(--t-13);
  border-bottom: 1px solid var(--linea-suave);
}
.tar-gantt-cab-izq {
  height: calc(var(--alto-fila) + 18px);
  font: 600 var(--t-12)/1 var(--f-ui); color: var(--texto-mudo);
  text-transform: uppercase; letter-spacing: .06em;
}
.tar-gantt-fila { cursor: pointer; }
.tar-gantt-fila:hover { background: var(--laton-velo); }
.tar-gantt-fila.tar-fila-hecha .tar-gantt-col-titulo { color: var(--texto-mudo); text-decoration: line-through; }
.tar-gantt-col-wbs { font: 600 var(--t-12)/1 var(--f-datos); color: var(--texto-mudo); }
.tar-gantt-col-titulo { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tar-gantt-col-quien, .tar-gantt-col-fecha {
  font-size: var(--t-12); color: var(--texto-suave);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* PERO LA COLUMNA DE LA CARA NO RECORTA (v0.60.1). El `overflow: hidden`
   de arriba está para que un nombre largo no se salga, y de paso se
   comía el anillo de presencia, que es un `box-shadow` y sobresale 4 px
   del avatar. Un `overflow: hidden` recorta también las sombras.
   El nombre sigue recortándose donde toca: en su propio hueco, que ya
   lleva sus puntos suspensivos. */
.tar-gantt-col-quien { overflow: visible; }
.tar-gantt-quien-nombre { min-width: 0; }
/* Y al anillo se le deja el sitio que pide: 4 px, no 3. Con 3 se le
   comía un píxel por cada lado, que es justo lo que se ve como un
   círculo «achatado» sin saber por qué. */
.tar-gantt-col-quien .pres-anillo, .tar-gantt-col-gente .pres-anillo { margin: 4px; }
.tar-gantt-col-fecha { font-family: var(--f-datos); }

.tar-gantt-piso { display: flex; height: 18px; }
.tar-gantt-piso-bajo { height: var(--alto-fila); }
.tar-gantt-periodo {
  flex: none; border-right: 1px solid var(--linea);
  font: 600 var(--t-12)/18px var(--f-ui); color: var(--texto-suave);
  padding-left: 6px; overflow: hidden; white-space: nowrap; text-transform: capitalize;
}
.tar-gantt-celda {
  flex: none; border-right: 1px solid var(--linea-suave);
  font: 500 var(--t-12)/var(--alto-fila) var(--f-datos); color: var(--texto-mudo);
  text-align: center; overflow: hidden;
}
.tar-gantt-celda.tar-finde { background: var(--superficie-2); }
.tar-gantt-celda.tar-hoy { background: var(--peligro-velo); color: var(--peligro); font-weight: 700; }

.tar-gantt-pista { background-image: linear-gradient(to bottom, var(--linea-suave) 1px, transparent 1px); }
.tar-gantt-franja { position: absolute; top: 0; bottom: 0; pointer-events: none; }
/* v0.26 · la raya de un día que no se trabaja SÍ responde al ratón: es
   donde se mira, y hasta ahora no decía nada. Va por debajo de las
   barras, así que pasar el ratón por una barra sigue leyendo la barra. */
.tar-gantt-franja.tar-franja-dice { pointer-events: auto; cursor: help; }
.tar-gantt-finde { background: var(--superficie-2); }
.tar-gantt-hoy { background: var(--peligro-velo); border-left: 1.5px solid var(--peligro); }
.tar-gantt-flechas { position: absolute; top: 0; left: 0; pointer-events: none; overflow: visible; }
.tar-gantt-flecha { fill: none; stroke: var(--texto-mudo); stroke-width: 1.2; }
.tar-gantt-punta { fill: var(--texto-mudo); stroke: none; }

.tar-gantt-barra {
  position: absolute; height: 22px; box-sizing: border-box;
  border: 1.5px solid var(--laton-oscuro); border-radius: 5px;
  background: var(--superficie);
  overflow: hidden; cursor: grab; touch-action: none;
  box-shadow: var(--sombra-1);
  /* v0.30 · El hueco de dentro mide 19 px (22 menos los dos bordes) y el
     porcentaje se escribía con una altura de línea de 20: sobraba un
     píxel por arriba y otro por abajo, y con `overflow: hidden` lo que
     sobra se corta. Se centra en vertical y se deja que la altura de
     línea la ponga el hueco, no un número escrito a mano. */
  display: flex; align-items: center;
}
.tar-gantt-barra:hover { filter: brightness(.98); }
.tar-gantt-relleno { position: absolute; inset: 0 auto 0 0; opacity: .55; }
.tar-gantt-barra-texto {
  position: relative; display: block; padding: 0 6px;
  font: 600 var(--t-12)/1 var(--f-datos); color: var(--texto);
  white-space: nowrap; pointer-events: none;
}
.tar-gantt-barra.tar-barra-hecha { border-style: dashed; opacity: .7; }
/* TODAS LAS BARRAS MIDEN LO MISMO (v0.30.1).
   Desde la v0.23.0 la barra de una tarea con hijas medía 14 px contra los
   22 de las demás. La intención era la de cualquier Gantt de manual —que
   un resumen se lea distinto de un trabajo— pero el efecto era otro: en
   un proyecto anidado tres niveles salían tres grosores distintos en
   cuatro filas seguidas, y lo primero que se piensa al verlo es que algo
   está mal pintado. El grosor es de las pocas cosas que el ojo compara
   sin querer, así que **no puede significar nada que no sea importante**;
   si además hay que explicarlo, ya no lo es.
   La distinción se queda donde no estorba: **esquinas rectas** para una
   madre y redondeadas para una tarea de verdad. Y como ahora sí caben,
   las madres vuelven a decir su porcentaje. */
.tar-gantt-barra.tar-barra-madre { border-radius: 2px; }
.tar-gantt-barra.tar-barra-movida { cursor: grabbing; box-shadow: var(--sombra-2); z-index: 5; }
.tar-gantt-tirador {
  position: absolute; top: 0; right: 0; width: 8px; height: 100%;
  cursor: ew-resize; background: linear-gradient(90deg, transparent, var(--laton-velo));
}
/* El hito: una caja que NO gira (para que los puntos de enganche y el
   ratón coincidan) con el rombo girado dentro. v0.24.1 */
.tar-gantt-hito-caja {
  position: absolute; width: 22px; height: 22px; cursor: grab;
  display: flex; align-items: center; justify-content: center;
  touch-action: none;
}
.tar-gantt-hito {
  width: 14px; height: 14px; display: block;
  transform: rotate(45deg); border-radius: 2px;
  border: 1.5px solid var(--laton-oscuro);
}
.tar-gantt-hito-caja.tar-hito-movido { cursor: grabbing; z-index: 6; }
.tar-gantt-hito-etiqueta {
  position: absolute; left: 26px; top: 1px; white-space: nowrap;
  font: 600 var(--t-12)/20px var(--f-datos); color: var(--laton-texto);
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--radio-sm); padding: 0 6px; pointer-events: none;
}

/* --- Tablas de carga y de costes --- */
.tar-tabla .num { text-align: right; font-family: var(--f-datos); white-space: nowrap; }
.tar-tabla th.num { text-align: right; }
.tar-tabla td.tar-alerta { color: var(--peligro); font-weight: 700; }
.tar-tabla-nombre { font-weight: 500; }
.tar-fila-pinchable { cursor: pointer; }
.tar-fila-pinchable:hover { background: var(--laton-velo); }
.tar-tabla tfoot .tar-total td {
  border-top: 1.5px solid var(--linea-fuerte);
  font-weight: 700; background: var(--superficie-2);
}
.tar-carga { display: flex; align-items: center; gap: 8px; min-width: 130px; }
.tar-carga-canal {
  flex: 1 1 70px; height: 9px; border-radius: 999px;
  background: var(--superficie-2); border: 1px solid var(--linea-suave); overflow: hidden;
}
.tar-carga-relleno { height: 100%; }
.tar-carga-verde { background: var(--ok); }
.tar-carga-naranja { background: var(--aviso); }
.tar-carga-rojo { background: var(--peligro); }
.tar-carga-gris { background: var(--linea-fuerte); }
.tar-carga-cifra { font: 700 var(--t-12)/1 var(--f-datos); flex: none; color: var(--texto-suave); }

@media (max-width: 900px) {
  .tar-gantt-marco { --ancho-izq: 240px; }
  .tar-gantt-fila, .tar-gantt-cab-izq { grid-template-columns: 34px minmax(0, 1fr) 74px; }
  .tar-gantt-col-fecha { display: none; }
  /* Y LAS CARAS TAMBIÉN SE VAN (v0.60.1). Aquí la rejilla se queda en
     tres columnas y había ocho cosas metidas: las que no cabían se
     doblaban a una segunda línea dentro de una fila de alto fijo, o sea,
     fuera de la fila. La cara salía cortada y nadie sabía por qué.
     En una pantalla de 900 px lo que hace falta es el título y la fecha;
     quién la lleva se ve abriendo la tarea. */
  .tar-gantt-col-quien, .tar-gantt-col-gente, .tar-gantt-col-anidar,
  .tar-gantt-col-dura { display: none; }
}

/* =====================================================================
   M-11 · v0.24 · las otras dos vistas del escritorio, los adjuntos y
   lo que el Gantt tenía que decir mejor
   ===================================================================== */

.tar-barra-vistas { margin-top: calc(var(--e-2) * -1); }

/* --- TORRE: lo que antes vence, arriba --- */
.tar-torres {
  display: grid; gap: var(--e-3);
  grid-template-columns: minmax(0, 1fr) minmax(240px, 340px);
  align-items: start;
}
@media (max-width: 900px) { .tar-torres { grid-template-columns: minmax(0, 1fr); } }
.tar-torre {
  background: var(--superficie-2);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  padding: var(--e-2);
  min-height: 140px;
}
.tar-torre-sin-fecha { background: var(--lateral-fondo); }
.tar-torre-cab { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.tar-torre-cartas {
  display: flex; flex-direction: column; gap: 8px; margin-top: var(--e-2);
  max-height: calc(100vh - 400px); overflow-y: auto; padding-right: 2px;
}
/* UNA TARJETA NO SE ENCOGE (v0.27.3, BUG-2026-007).
   Esta torre tiene altura máxima y scroll. En una columna flex con
   altura acotada, los hijos llevan `flex-shrink: 1` de fábrica: cuando
   el contenido no cabe, el navegador **aplasta las tarjetas** hasta su
   altura mínima en vez de dejar que la torre se desplace, y lo que
   sobra —el pie con «Vence…» y «Hito»— se sale por debajo del borde y
   se monta encima del separador de la fecha siguiente. Se veía como
   textos pisándose y era esto. La torre está para desplazarse; las
   tarjetas, para medir lo que miden.
   Vale también para el tablero: hoy sus columnas no tienen tope, pero
   el día que lo tengan el fallo volvería igual. */
.tar-torre-cartas > *, .kanban-cartas > * { flex: none; }
.tar-torre-sep {
  font: 700 10px/1.6 var(--f-datos); letter-spacing: .12em; text-transform: uppercase;
  color: var(--texto-mudo); border-top: 1px solid var(--linea);
  padding-top: 6px; margin-top: 4px;
}
.tar-torre-sep-vencido { color: var(--peligro); border-top-color: var(--peligro); }
.tar-torre-sep-hoy { color: var(--laton-texto); border-top-color: var(--laton-oscuro); }

/* Lo que vence HOY: marco rojo grueso con intermitencia (pedido del
   13/08/2026). Quien tenga el sistema con «menos movimiento» activado
   ve el marco fijo: el aviso no se pierde, solo deja de parpadear. */
.tar-vence-hoy {
  border: 3px solid var(--peligro) !important;
  animation: tar-latido 1.15s ease-in-out infinite;
}
@keyframes tar-latido {
  0%, 100% { box-shadow: 0 0 0 0 rgba(194, 69, 81, .55); border-color: var(--peligro); }
  50%      { box-shadow: 0 0 0 6px rgba(194, 69, 81, 0); border-color: color-mix(in srgb, var(--peligro) 45%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .tar-vence-hoy { animation: none; }
}

/* --- CALENDARIO: este mes y el siguiente --- */
.tar-calendarios {
  display: grid; gap: var(--e-4);
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
}
.tar-mes {
  background: var(--superficie);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  overflow: hidden;
}
.tar-mes-cab {
  font: 600 var(--t-15)/1 var(--f-titulos); color: var(--texto);
  padding: var(--e-3) var(--e-4); background: var(--superficie-2);
  border-bottom: 1px solid var(--linea); text-transform: capitalize;
  display: flex; align-items: center; gap: 8px;
}
.tar-mes-nombre { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tar-mes-flecha {
  appearance: none; cursor: pointer; flex: none;
  width: 26px; height: 26px; border-radius: 50%;
  border: 1px solid var(--linea); background: var(--superficie);
  font: 600 16px/1 var(--f-ui); color: var(--texto-suave);
}
.tar-mes-flecha:hover { border-color: var(--laton-oscuro); color: var(--laton-texto); background: var(--laton-velo); }
.tar-mes-flecha:focus-visible { outline: 2px solid var(--laton); outline-offset: 2px; }
.tar-mes-hoy {
  appearance: none; cursor: pointer; flex: none;
  border: 1px solid var(--laton-oscuro); background: var(--laton-velo);
  color: var(--laton-texto); border-radius: 999px; padding: 3px 10px;
  font: 600 var(--t-12)/1 var(--f-ui); text-transform: none;
}

/* --- v0.26 · la tira de catorce meses vista ------------------------- */
.tar-tira-meses {
  display: grid; grid-template-columns: repeat(14, minmax(0, 1fr));
  gap: 6px; margin-bottom: var(--e-4);
}
.tar-mini {
  appearance: none; cursor: pointer; text-align: left;
  display: flex; flex-direction: column; gap: 4px; min-width: 0;
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--radio-sm); padding: 5px 5px 4px;
}
.tar-mini:hover { border-color: var(--laton-oscuro); background: var(--laton-velo); }
.tar-mini:focus-visible { outline: 2px solid var(--laton); outline-offset: 1px; }
/* El mes de hoy, recuadrado en rojo: es la referencia de la tira */
.tar-mini-actual { box-shadow: inset 0 0 0 2px var(--peligro); border-color: var(--peligro); }
/* Los dos que están abiertos en grande, en dorado */
.tar-mini-abierto { border-color: var(--laton-oscuro); background: var(--laton-velo); }
.tar-mini-cab { display: flex; align-items: baseline; gap: 3px; min-width: 0; }
.tar-mini-mes {
  font: 700 var(--t-12)/1 var(--f-ui); color: var(--texto);
  text-transform: capitalize; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tar-mini-anio { font: 500 9px/1 var(--f-datos); color: var(--texto-mudo); }
.tar-mini-rejilla { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; }
.tar-mini-dia {
  aspect-ratio: 1; border-radius: 1px; min-height: 4px;
  background: var(--linea-suave);
}
.tar-mini-hueco { background: transparent; }
.tar-mini-nolab { background: var(--superficie-2); box-shadow: inset 0 0 0 1px var(--linea-suave); }
.tar-mini-wadax { background: var(--laton-velo); }
.tar-mini-con { background: var(--laton); }
.tar-mini-rojo { background: var(--peligro); }
.tar-mini-hoy { box-shadow: inset 0 0 0 1.5px var(--peligro); }
.tar-mini-pie { font: 600 var(--t-12)/1 var(--f-datos); color: var(--texto-mudo); }
.tar-mini-pie-alerta { color: var(--peligro); }

/* Con menos sitio la tira se parte en dos filas de siete en vez de
   apretar catorce meses hasta que no se lean */
@media (max-width: 1100px) {
  .tar-tira-meses { grid-template-columns: repeat(7, minmax(0, 1fr)); }
}
.tar-mes-semana {
  display: grid; grid-template-columns: repeat(7, 1fr);
  font: 700 10px/1 var(--f-datos); letter-spacing: .1em; color: var(--texto-mudo);
  text-align: center; padding: 6px 0; border-bottom: 1px solid var(--linea-suave);
}
.tar-mes-dias { display: grid; grid-template-columns: repeat(7, 1fr); }
.tar-dia {
  min-height: 74px; padding: 4px 5px;
  border-right: 1px solid var(--linea-suave);
  border-bottom: 1px solid var(--linea-suave);
  display: flex; flex-direction: column; gap: 3px; min-width: 0;
}
.tar-dia:nth-child(7n) { border-right: 0; }
.tar-dia-fuera { background: var(--superficie-2); opacity: .5; }
.tar-dia-finde { background: var(--superficie-2); }
.tar-dia-hoy { background: var(--laton-velo); box-shadow: inset 0 0 0 2px var(--laton-oscuro); }
.tar-dia-alerta { box-shadow: inset 0 0 0 2px var(--peligro); }
.tar-dia-numero { font: 600 var(--t-12)/1 var(--f-datos); color: var(--texto-suave); }
.tar-dia-hoy-marca {
  font: 700 9px/1 var(--f-datos); letter-spacing: .1em; text-transform: uppercase;
  color: var(--laton-texto);
}
.tar-dia-tareas { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

.tar-chip {
  appearance: none; cursor: pointer; text-align: left; width: 100%;
  display: flex; align-items: center; gap: 4px; min-width: 0;
  background: var(--superficie); border: 1px solid var(--linea-suave);
  border-left: 3px solid var(--linea-fuerte);
  border-radius: 4px; padding: 2px 5px;
  font: 500 var(--t-12)/1.25 var(--f-ui); color: var(--texto);
}
.tar-chip:hover { border-color: var(--laton-oscuro); background: var(--laton-velo); }
.tar-chip-texto { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tar-chip-rojo { border-left-color: var(--peligro); }
.tar-chip-naranja { border-left-color: var(--aviso); }
.tar-chip-hecha { border-left-color: var(--ok); color: var(--texto-mudo); text-decoration: line-through; }
.tar-tira-vencidas { display: flex; flex-direction: column; gap: 6px; margin-bottom: var(--e-3); }
.tar-tira-chips { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.tar-tira-chips .tar-chip { width: auto; max-width: 320px; }

/* --- Ficheros y enlaces de una tarea --- */
.tar-adjuntos-alta {
  display: flex; gap: var(--e-2); flex-wrap: wrap; align-items: center; margin-top: var(--e-3);
}
.tar-adjuntos-alta input[type="url"] { flex: 1 1 220px; min-width: 180px; }
.tar-adjuntos-alta input[type="text"] { flex: 0 1 200px; }
.tar-boton-fichero { position: relative; overflow: hidden; cursor: pointer; }
.tar-boton-fichero input[type="file"] {
  position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; height: 100%;
}
.tar-adjunto-tipo { display: inline-flex; color: var(--laton-texto); flex: none; }
.tar-adjunto-tipo svg { width: 16px; height: 16px; }
.tar-adjunto-nombre {
  appearance: none; background: none; border: 0; padding: 0; cursor: pointer;
  font: 500 var(--t-13)/1.3 var(--f-ui); color: var(--texto); text-align: left;
  flex: 1 1 160px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  border-bottom: 1px dotted var(--linea-fuerte);
}
.tar-adjunto-nombre:hover { color: var(--laton-texto); border-bottom-color: var(--laton-oscuro); }

/* --- Gantt: bloqueada, y el arrastre entre líneas --- */
.tar-gantt-barra.tar-bloqueada {
  border: 3px solid var(--peligro);
  box-shadow: 0 0 0 1px var(--peligro-velo), var(--sombra-1);
}
.tar-gantt-hito.tar-bloqueada { border: 3px solid var(--peligro); }
.tar-gantt-fila.tar-fila-bloqueada .tar-gantt-col-titulo { color: var(--peligro); font-weight: 600; }
.tar-gantt-fila.tar-fila-destino {
  outline: 2px dashed var(--laton-oscuro); outline-offset: -2px; background: var(--laton-velo);
}
.tar-gantt-fila.arrastrando { opacity: .45; }
.tar-gantt-barra.tar-barra-cambia-linea {
  border-style: dashed; border-color: var(--laton-oscuro);
  box-shadow: var(--sombra-2);
}

/* --- v0.24.1 · enlazar tirando de un cable, como en Project --- */
.tar-gantt-nodo {
  position: absolute; top: 50%; width: 11px; height: 11px;
  margin-top: -5.5px; border-radius: 999px;
  background: var(--superficie); border: 2px solid var(--laton-oscuro);
  cursor: crosshair; opacity: 0; transition: opacity .12s ease;
  touch-action: none; z-index: 4;
}
.tar-nodo-izq { left: -6px; }
.tar-nodo-der { right: -6px; }
.tar-gantt-barra:hover .tar-gantt-nodo,
.tar-gantt-hito-caja:hover .tar-gantt-nodo,
.tar-gantt-nodo:hover { opacity: 1; }
.tar-gantt-nodo:hover { background: var(--laton); transform: scale(1.25); }
.tar-gantt-hito-caja .tar-nodo-izq { left: -3px; }
.tar-gantt-hito-caja .tar-nodo-der { right: -3px; }

/* Mientras se tira del cable, todos los puntos a la vista: así se ve
   dónde se puede soltar sin ir buscando con el ratón. */
.tar-cableando .tar-gantt-nodo { opacity: .55; }
.tar-cableando .tar-gantt-barra,
.tar-cableando .tar-gantt-hito-caja { cursor: crosshair; }

.tar-gantt-cable { position: absolute; top: 0; left: 0; pointer-events: none; overflow: visible; z-index: 7; }
.tar-cable-linea {
  fill: none; stroke: var(--laton-oscuro); stroke-width: 2;
  stroke-dasharray: 5 4; stroke-linecap: round;
}
.tar-cable-punta { fill: var(--laton-oscuro); }
.tar-gantt-cable.tar-cable-listo .tar-cable-linea { stroke: var(--ok); stroke-dasharray: none; }
.tar-gantt-cable.tar-cable-listo .tar-cable-punta { fill: var(--ok); }

.tar-gantt-destino-cable {
  outline: 2px solid var(--ok); outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--ok-velo) !important;
}

/* La flecha de una espera se puede pinchar para quitarla: el trazo fino
   no se acierta con el ratón, así que encima va uno gordo e invisible. */
.tar-gantt-flechas { pointer-events: none; }
.tar-gantt-flecha-zona {
  fill: none; stroke: transparent; stroke-width: 12;
  pointer-events: stroke; cursor: pointer;
}
.tar-gantt-flecha-zona:hover { stroke: var(--peligro-velo); }

/* --- v0.24.2 · la ventana que pregunta qué hacer con las que esperan --- */
.tar-opciones { display: flex; flex-direction: column; gap: var(--e-2); margin-top: var(--e-4); }
.tar-opcion {
  appearance: none; cursor: pointer; text-align: left; width: 100%;
  display: flex; flex-direction: column; gap: 3px;
  background: var(--superficie-2);
  border: 1px solid var(--linea);
  border-radius: var(--radio-sm);
  padding: 11px 13px;
}
.tar-opcion:hover { border-color: var(--laton-oscuro); background: var(--laton-velo); }
.tar-opcion:focus-visible { outline: 2px solid var(--laton); outline-offset: 2px; }
.tar-opcion-principal { border-color: var(--laton-oscuro); background: var(--laton-velo); }
.tar-opcion-titulo { font: 600 var(--t-14)/1.3 var(--f-ui); color: var(--texto); }
.tar-opcion-detalle { font: 400 var(--t-12)/1.45 var(--f-ui); color: var(--texto-mudo); }

/* --- v0.25 · el calendario laboral: lo que no cuenta, rayado en rojo --- */
.tar-gantt-franja.tar-gantt-festivo {
  background: repeating-linear-gradient(
    135deg,
    var(--peligro-velo) 0 6px,
    transparent 6px 12px
  );
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--peligro) 18%, transparent);
}
.tar-gantt-celda.tar-festivo {
  color: var(--peligro); font-weight: 700;
  background: var(--peligro-velo);
}
/* v0.26 · en semanas y en meses una celda son varios días: si dentro hay
   un festivo se marca por abajo, para que se vea que hay algo que leer
   al pasar el ratón. */
.tar-gantt-celda.tar-celda-tiene-festivo {
  box-shadow: inset 0 -2px 0 0 color-mix(in srgb, var(--peligro) 55%, transparent);
  cursor: help;
}

/* Los días que no se trabajan, dentro de la propia barra */
.tar-barra-nolab {
  position: absolute; top: 0; bottom: 0; z-index: 2; pointer-events: auto;
  background: repeating-linear-gradient(
    135deg,
    color-mix(in srgb, var(--peligro) 42%, transparent) 0 3px,
    transparent 3px 7px
  );
}
.tar-barra-nolab.tar-barra-festivo {
  background: repeating-linear-gradient(
    135deg,
    color-mix(in srgb, var(--peligro) 62%, transparent) 0 3px,
    transparent 3px 6px
  );
}
.tar-gantt-barra-texto { position: relative; z-index: 3; }

/* En el calendario del escritorio */
.tar-dia-festivo { background: var(--peligro-velo); }
.tar-dia-festivo-marca {
  font: 700 9px/1 var(--f-datos); letter-spacing: .08em; text-transform: uppercase;
  color: var(--peligro);
}

/* --- v0.25.1 · la regla con el día de la semana, y el cierre de WADAX --- */
.tar-gantt-celda.tar-celda-dos-pisos {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  line-height: 1.05; padding-top: 1px;
}
.tar-celda-semana {
  font: 700 9px/1 var(--f-datos); letter-spacing: .04em;
  color: var(--texto-mudo); text-transform: uppercase;
}
.tar-celda-numero { font: 500 var(--t-12)/1.15 var(--f-datos); }
.tar-gantt-celda.tar-finde .tar-celda-semana { color: var(--texto-suave); }
.tar-gantt-celda.tar-festivo .tar-celda-semana { color: var(--peligro); }
.tar-gantt-celda.tar-wadax { color: var(--laton-texto); background: var(--laton-velo); }
.tar-gantt-celda.tar-wadax .tar-celda-semana { color: var(--laton-texto); }

/* El cierre de la casa se distingue del festivo oficial: dorado, no rojo */
.tar-gantt-franja.tar-gantt-wadax {
  background: repeating-linear-gradient(
    135deg,
    var(--laton-velo) 0 6px,
    transparent 6px 12px
  );
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--laton-oscuro) 22%, transparent);
}
.tar-barra-nolab.tar-barra-wadax {
  background: repeating-linear-gradient(
    135deg,
    color-mix(in srgb, var(--laton-oscuro) 60%, transparent) 0 3px,
    transparent 3px 6px
  );
}
.tar-dia-wadax { background: var(--laton-velo); }
.tar-dia-wadax .tar-dia-festivo-marca { color: var(--laton-texto); }

/* La regla invita a usar la rueda encima de ella */
.tar-gantt-fila-cab { cursor: ns-resize; }

/* =====================================================================
   M-11 · v0.27 · las personas se ven: caras en las tarjetas, tira de
   equipo con arrastre, el «+» de cada columna y las columnas nuevas
   del Gantt (coordinador, asignada a, duración y anidar)
   ===================================================================== */

/* Una talla más pequeña que `sm`, para caber dentro de una tarjeta */
.avatar-xs { width: 22px; height: 22px; font-size: 9px; }

.tar-avatar { border: 1px solid var(--linea); }
.tar-avatar-pinchable { cursor: pointer; }
.tar-avatar-pinchable:hover { outline: 2px solid var(--laton); outline-offset: 1px; }
.tar-avatar-pinchable:focus-visible { outline: 2px solid var(--laton); outline-offset: 2px; }
.tar-avatar-mas { background: var(--superficie-2); color: var(--texto-suave); font-weight: 600; }

.tar-tira-personas { display: inline-flex; align-items: center; gap: 3px; flex-wrap: wrap; }

/* --- El «+» de cada columna del tablero --- */
.kanban-mas {
  border: 1px solid var(--linea); background: var(--superficie);
  color: var(--texto-suave); border-radius: var(--radio-sm);
  width: 22px; height: 22px; line-height: 1; padding: 0;
  font: 600 16px/1 var(--f-ui); cursor: pointer; flex: none;
}
.kanban-mas:hover { border-color: var(--laton-oscuro); background: var(--laton-velo); color: var(--laton-texto); }
.kanban-mas:focus-visible { outline: 2px solid var(--laton); outline-offset: 2px; }
.kanban-cab { align-items: center; }

/* --- La tira del equipo, en la fila de las vistas --- */
.tar-equipo-tira {
  display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap;
  padding: 10px 2px 4px;
  border-bottom: 1px solid var(--linea-suave);
}
.tar-equipo-rotulo {
  font: 400 var(--t-12)/1.3 var(--f-ui); color: var(--texto-mudo);
  align-self: center; max-width: 190px;
}
.tar-empleado {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  width: 86px; padding: 22px 2px 4px; cursor: pointer;
  border: 1px solid transparent; border-radius: var(--radio-sm);
  background: none;
}
.tar-empleado:hover { border-color: var(--linea); background: var(--laton-velo); }
.tar-empleado:focus-visible { outline: 2px solid var(--laton); outline-offset: 1px; }
.tar-empleado.sobre-destino {
  border-color: var(--laton-oscuro); background: var(--laton-velo);
  box-shadow: 0 0 0 2px var(--laton) inset;
}
.tar-empleado-nombre {
  font: 600 var(--t-12)/1.1 var(--f-ui); color: var(--texto);
  max-width: 84px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tar-empleado-apellido {
  font: 400 10px/1.1 var(--f-ui); color: var(--texto-mudo);
  max-width: 84px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* v0.27.4 · los TRES números de cada persona, cada uno en su sitio y
   con su color: izquierda gris (pendientes), encima verde (en curso),
   derecha amarillo (bloqueadas). El sitio es fijo aunque falte alguno,
   que es lo que permite leerlos sin leerlos. */
.tar-empleado-cara { position: relative; display: inline-flex; }
.tar-empleado-punto {
  position: absolute; z-index: 2;
  min-width: 18px; height: 18px; padding: 0 3px;
  border-radius: 9px; border: 1.5px solid var(--superficie);
  font: 700 10px/15px var(--f-datos); text-align: center;
  box-shadow: 0 1px 2px rgb(0 0 0 / .18);
}
/* Los tres van FUERA del avatar, no encima: pegados a su borde por el
   lado que les toca. Encima taparían la cara, que es justo lo que la
   tira está para enseñar —y con las iniciales tapadas ya no se sabe de
   quién son los números—. */
.tar-punto-pendiente { right: 100%; top: 50%; transform: translateY(-50%); margin-right: 3px;
  background: var(--linea-fuerte); color: var(--texto); }
.tar-punto-curso     { bottom: 100%; left: 50%; transform: translateX(-50%); margin-bottom: 2px;
  background: var(--ok); color: #FFF; }
.tar-punto-bloqueada { left: 100%; top: 50%; transform: translateY(-50%); margin-left: 3px;
  background: #E8C33F; color: #4A3A05; }
/* Al pasar el ratón por la ficha, la tarjeta se tiñe: que los números no
   se pierdan contra ese fondo. */
.tar-empleado:hover .tar-empleado-punto { border-color: var(--laton-velo); }

/* --- La ventana de «lo que tiene abierto» una persona --- */
.tar-personas-cuenta { margin: 0 0 8px; }
.tar-persona-fila {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 8px 10px; margin-bottom: 6px; text-align: left;
  border: 1px solid var(--linea); border-radius: var(--radio-sm);
  background: var(--superficie); cursor: pointer;
}
.tar-persona-fila:disabled { cursor: default; }
.tar-persona-fila:hover:not(:disabled) { border-color: var(--laton-oscuro); background: var(--laton-velo); }
.tar-persona-fila-vencida { border-left: 3px solid var(--peligro); }
.tar-persona-texto { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.tar-persona-titulo {
  font: 600 var(--t-13)/1.3 var(--f-ui); color: var(--texto);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tar-persona-sub {
  font: 400 var(--t-12)/1.3 var(--f-ui); color: var(--texto-mudo);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* --- Elegir a quién se le asigna, en la ficha de la tarea --- */
.tar-elige-personas { display: flex; flex-wrap: wrap; gap: 6px; }
.tar-chip-persona {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px 3px 3px; cursor: pointer;
  border: 1px solid var(--linea); border-radius: 999px;
  background: var(--superficie); color: var(--texto-suave);
  font: 400 var(--t-12)/1 var(--f-ui);
}
.tar-chip-persona:hover:not(:disabled) { border-color: var(--laton-oscuro); }
.tar-chip-persona:disabled { cursor: default; opacity: .7; }
.tar-chip-persona.elegido {
  border-color: var(--laton-oscuro); background: var(--laton-velo);
  color: var(--laton-texto); font-weight: 600;
}

/* --- El Gantt, con dos columnas más y los botones de anidar ---
   v0.30 · LAS CABECERAS Y LAS FECHAS SALÍAN CORTADAS. Las cabeceras van
   en versalitas y con espaciado entre letras, así que «ASIGNADA A» pide
   80 px y tenía 76, y «DURACIÓN» pide 64 y tenía 58. Y una fecha entera
   —«15/08/2026», diez caracteres de tipografía de datos— pide 84 px y
   tenía 72. Cortar el año de una fecha en un Gantt no es un defecto de
   estética: «15/08/20…» se lee mal y esa columna existe justo para
   comparar años cuando un proyecto cruza de ejercicio.
   El ancho total de la izquierda sube con ellas: si no, lo que se comería
   el sitio sería el título de la tarea, que es lo único que no se puede
   estrechar. */
.tar-gantt-marco { --ancho-izq: 764px; }
.tar-gantt-fila, .tar-gantt-cab-izq {
  grid-template-columns: 42px minmax(0, 1fr) 40px 112px 96px 84px 82px 84px;
}
.tar-gantt-col-anidar { display: inline-flex; gap: 2px; justify-content: center; }
.tar-anidar-btn {
  border: 1px solid var(--linea); background: var(--superficie);
  color: var(--texto-suave); border-radius: 3px;
  width: 17px; height: 19px; padding: 0; line-height: 1;
  font: 600 13px/1 var(--f-ui); cursor: pointer;
}
.tar-anidar-btn:hover { border-color: var(--laton-oscuro); background: var(--laton-velo); color: var(--laton-texto); }
.tar-anidar-btn:focus-visible { outline: 2px solid var(--laton); outline-offset: 1px; }
.tar-gantt-col-quien { display: inline-flex; align-items: center; gap: 5px; }
.tar-gantt-quien-nombre { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* `overflow: visible` y no `hidden` (v0.60.1): el anillo de presencia es
   una sombra que sobresale 4 px del avatar, y un `hidden` se la come. Lo
   que hay que recortar aquí no es el anillo, es la tira cuando hay más
   caras de las que caben — y de eso ya se encarga `tiraAsignados` con su
   tope de cuatro. */
.tar-gantt-col-gente { display: inline-flex; align-items: center; overflow: visible; }
.tar-gantt-col-dura {
  font: 500 var(--t-12)/1 var(--f-datos); color: var(--texto-suave);
  text-align: right; white-space: nowrap;
}
.tar-gantt-cab-izq .tar-gantt-col-dura { text-align: right; }
/* Las cabeceras no se recortan con puntos suspensivos: una cabecera a
   medias no dice qué hay debajo. Si algún día no cupieran, que se vea
   que no caben. */
.tar-gantt-cab-izq > span { overflow: visible; text-overflow: clip; }
/* Y la fecha, entera y sin partir. */
.tar-gantt-fila .tar-gantt-col-fecha { text-overflow: clip; }

/* La raya de un día no laborable ya no lleva cursor de interrogación:
   lo que tiene que decir lo dice el pop-up de WERP, y un signo «?»
   pegado al puntero solo prometía un globo que no llegaba. */
.tar-gantt-franja.tar-franja-dice { pointer-events: auto; cursor: default; }
.tar-gantt-celda.tar-celda-tiene-festivo { cursor: default; }

/* EN PANTALLA ESTRECHA SE QUITAN COLUMNAS ENTERAS, NO SE ESTRECHAN.
   Hasta la v0.30 aquí se dejaba el coordinador en 34 px —su cara sin el
   nombre— pero la CABECERA seguía diciendo «COORDINADOR», que pide 110.
   O sea: una columna cuya cabecera nunca se podía leer. Estrechar una
   columna por debajo de su título no ahorra sitio, lo gasta en algo que
   no se entiende. Así que en 1.200 se va el coordinador entero y quedan
   las personas asignadas, que es quien hace el trabajo; y en 900 se
   quedan solo el número y el nombre de la tarea, que es lo único que se
   puede leer en un móvil.
   Las medidas salen de medir las palabras en el navegador:
   «COORDINADOR» 110 px, «ASIGNADA A» 92, «DURACIÓN» 78 y una fecha
   entera 70. Cada columna tiene el ancho de su palabra más el aire. */
@media (max-width: 1200px) {
  .tar-gantt-marco { --ancho-izq: 596px; }
  .tar-gantt-fila, .tar-gantt-cab-izq {
    grid-template-columns: 38px minmax(0, 1fr) 40px 96px 84px 82px 84px;
  }
  .tar-gantt-col-quien { display: none; }
}
@media (max-width: 900px) {
  .tar-gantt-marco { --ancho-izq: 240px; }
  .tar-gantt-fila, .tar-gantt-cab-izq { grid-template-columns: 34px minmax(0, 1fr); }
  .tar-gantt-col-fecha, .tar-gantt-col-anidar, .tar-gantt-col-gente,
  .tar-gantt-col-dura, .tar-gantt-col-quien { display: none; }
}

/* Personas con cara en las tablas: la carga, el maestro de proyectos y
   el equipo de un proyecto */
.tar-carga-quien { display: flex; align-items: center; gap: 9px; }
.tar-celda-persona { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.tar-celda-persona > span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tar-equipo-cara { display: inline-flex; align-items: center; flex: none; }

/* =====================================================================
   M-12 · v0.27 · PRODUCCIÓN · la hoja de procesos
   La paleta arriba, la hoja debajo, los cables por debajo de las cajas
   y el reloj del tiempo total en una esquina.
   ===================================================================== */

.prd-lote { display: inline-flex; align-items: center; gap: 6px; font-size: var(--t-13); color: var(--texto-suave); }
.prd-lote input { width: 82px; }
.prd-lote .ayuda { margin: 0; }

/* --- La paleta --- */
.prd-paleta {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 10px 0 12px;
  border-bottom: 1px solid var(--linea-suave);
}
.prd-pieza {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px 5px 6px; cursor: grab;
  border: 1px solid var(--linea); border-radius: var(--radio-sm);
  background: var(--superficie); color: var(--texto-suave);
  font: 500 var(--t-12)/1.15 var(--f-ui); text-align: left;
}
.prd-pieza:hover:not(:disabled) { border-color: var(--laton-oscuro); background: var(--laton-velo); color: var(--texto); }
.prd-pieza:disabled { cursor: default; opacity: .55; }
.prd-pieza:focus-visible { outline: 2px solid var(--laton); outline-offset: 2px; }
.prd-pieza.arrastrando { opacity: .45; }
.prd-pieza-texto { max-width: 160px; }
.prd-glifo { display: inline-flex; flex: none; width: 18px; height: 18px; }
.prd-glifo svg { width: 100%; height: 100%; }

/* Cada familia de procesos, con su color, para reconocerlas de un golpe */
.prd-grupo-extremo     { --prd-color: var(--laton-oscuro); }
.prd-grupo-compra      { --prd-color: #6E7F8D; }
.prd-grupo-transporte  { --prd-color: #8A7B5E; }
.prd-grupo-fabricacion { --prd-color: #5F7A6B; }
.prd-grupo-montaje     { --prd-color: #7B6A86; }
.prd-grupo-calidad     { --prd-color: #8C6A63; }
.prd-pieza .prd-glifo, .prd-caja .prd-glifo { color: var(--prd-color, var(--texto-mudo)); }

/* --- La hoja --- */
.prd-tablero { position: relative; }
.prd-zona-hoja { margin-top: 10px; }
.prd-hoja-marco {
  position: relative; overflow: auto;
  height: min(62vh, 660px);
  border: 1px solid var(--linea); border-radius: var(--radio-sm);
  background: var(--superficie-2);
}
.prd-hoja {
  position: relative;
  background-image:
    radial-gradient(circle, var(--linea) 1px, transparent 1px);
  background-size: 24px 24px;
}
.prd-hoja-recibiendo { box-shadow: inset 0 0 0 2px var(--laton); }
.prd-cables, .prd-cable-vivo { position: absolute; inset: 0; overflow: visible; }
.prd-cable-vivo { pointer-events: none; }

.prd-cable {
  fill: none; stroke: var(--linea-fuerte); stroke-width: 2;
  marker-end: none;
}
.prd-cable-critico { stroke: var(--laton); stroke-width: 3; }
.prd-cable-pinchable { pointer-events: stroke; cursor: pointer; stroke-width: 3; }
.prd-cable-pinchable:hover { stroke: var(--peligro); }
.prd-cable-tirando { stroke-dasharray: 5 4; stroke: var(--texto-mudo); }
.prd-cable-tirando.prd-cable-vale { stroke: var(--ok); stroke-dasharray: none; }

/* --- LAS TRES CLASES DE CABLE · v0.65.0 ------------------------------
   Se distinguen a propósito, y no por adorno: el plazo que sale en la
   esquina **solo cuenta el camino entero**. Una rama que se ve igual que
   las demás y que no está contada es un número que miente sin avisar. */
.prd-cable-alterno { stroke-dasharray: 6 5; stroke: var(--texto-mudo); }
.prd-cable-retorno { stroke-dasharray: 3 4; stroke: var(--aviso); }
.prd-cable-rotulo {
  font: 600 10px/1 var(--f-ui); fill: var(--texto-suave);
  text-anchor: middle; paint-order: stroke;
  stroke: var(--fondo); stroke-width: 3px; stroke-linejoin: round;
}

/* --- Una caja --- */
.prd-caja {
  position: absolute; z-index: 2;
  display: flex; flex-direction: column; justify-content: space-between; gap: 4px;
  min-height: 76px; padding: 8px 10px;
  border: 1px solid var(--linea-fuerte); border-left: 3px solid var(--prd-color, var(--linea-fuerte));
  border-radius: var(--radio-sm); background: var(--superficie);
  cursor: grab; user-select: none;
  box-shadow: 0 1px 2px rgb(0 0 0 / .06);
}
.prd-caja:hover { border-color: var(--laton-oscuro); box-shadow: 0 2px 8px rgb(0 0 0 / .10); }
.prd-caja:focus-visible { outline: 2px solid var(--laton); outline-offset: 2px; }
.prd-caja.prd-moviendo { cursor: grabbing; opacity: .85; z-index: 5; }
.prd-caja.prd-critico { box-shadow: 0 0 0 2px var(--laton-velo), 0 1px 3px rgb(0 0 0 / .10); }
.prd-caja.prd-destino { border-color: var(--laton); box-shadow: 0 0 0 3px var(--laton-velo); }
.prd-caja-cab { display: flex; align-items: flex-start; gap: 6px; }
.prd-caja-titulo {
  font: 600 var(--t-12)/1.25 var(--f-ui); color: var(--texto);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.prd-caja-pie { font: 500 var(--t-12)/1 var(--f-datos); color: var(--texto-suave); }
.prd-caja-pie.prd-sin-tiempo { color: var(--aviso); }

/* =====================================================================
   LAS FIGURAS DEL DIAGRAMA DE FLUJO · v0.65.0
   ---------------------------------------------------------------------
   Lo pidió Javier: «que el diagrama de procesos pueda acabar siendo un
   diagrama de flujo completo (…) usando BPMN/BPD».

   Y la forma no es decoración: **un diagrama de flujo se entiende antes
   por las formas que por los nombres.** Círculo lo que empieza y lo que
   acaba, rombo donde el camino se parte, caja lo que es trabajo. Quince
   cajas iguales con texto dentro no son un diagrama, son una lista con
   cables.

   El rombo es un cuadrado girado 45°, y el dibujo de dentro se gira -45°
   para que quede derecho. Es la manera de tener un rombo de verdad sin
   recortar el texto por las esquinas, que es lo que pasa con `clip-path`.

   Y EL NOMBRE VA DEBAJO DE LA FIGURA, no dentro. Es lo que hace BPMN, y
   por un motivo práctico: «¿Pasa la inspección del chasis?» no cabe
   dentro de un rombo de cuarenta y seis píxeles ni cabrá nunca. */
.prd-caja.prd-forma-circulo,
.prd-caja.prd-forma-circulo-grueso,
.prd-caja.prd-forma-rombo {
  border: 0; background: none; box-shadow: none; padding: 4px 0 0;
  align-items: center; justify-content: flex-start; min-height: 76px;
}
.prd-caja.prd-forma-circulo:hover,
.prd-caja.prd-forma-circulo-grueso:hover,
.prd-caja.prd-forma-rombo:hover { box-shadow: none; }
.prd-forma-circulo .prd-caja-cab,
.prd-forma-circulo-grueso .prd-caja-cab,
.prd-forma-rombo .prd-caja-cab {
  flex-direction: column; align-items: center; gap: 3px; text-align: center;
}
.prd-forma-circulo .prd-caja-titulo,
.prd-forma-circulo-grueso .prd-caja-titulo,
.prd-forma-rombo .prd-caja-titulo { max-width: 78px; text-align: center; }
.prd-forma-circulo .prd-caja-pie,
.prd-forma-circulo-grueso .prd-caja-pie,
.prd-forma-rombo .prd-caja-pie { display: none; }

.prd-forma-circulo .prd-glifo,
.prd-forma-circulo-grueso .prd-glifo,
.prd-forma-rombo .prd-glifo {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; flex: none;
  background: var(--superficie); box-shadow: 0 1px 2px rgb(0 0 0 / .08);
}
.prd-forma-circulo .prd-glifo,
.prd-forma-circulo-grueso .prd-glifo { border-radius: 50%; }
/* El inicio con marco fino y el fin con marco grueso, que es como se
   distinguen en BPMN sin leer nada. */
.prd-forma-circulo .prd-glifo { border: 2px solid var(--ok); color: var(--ok); }
.prd-forma-circulo-grueso .prd-glifo { border: 4px solid var(--texto); color: var(--texto); }
.prd-forma-rombo .prd-glifo {
  border: 2px solid var(--laton-oscuro); border-radius: 5px;
  transform: rotate(45deg); color: var(--laton-texto);
}
.prd-forma-rombo .prd-glifo svg { transform: rotate(-45deg); }
.prd-caja.prd-forma-rombo.prd-critico,
.prd-caja.prd-forma-circulo.prd-critico,
.prd-caja.prd-forma-circulo-grueso.prd-critico { box-shadow: none; }
.prd-forma-rombo.prd-critico .prd-glifo,
.prd-forma-circulo.prd-critico .prd-glifo,
.prd-forma-circulo-grueso.prd-critico .prd-glifo { box-shadow: 0 0 0 3px var(--laton-velo); }

/* Lo que se hace en China lleva su marca. Es la caja que se para una
   semana entera en el Año Nuevo chino, y verlo en el mapa evita la
   pregunta de por qué la fecha se va tanto. */
.prd-caja.prd-en-china { border-left-color: var(--peligro); }
.prd-grupo-diagrama { --prd-color: var(--texto-mudo); }

/* Las bolitas: huecas hasta que el ratón las mira */
.prd-bolita {
  position: absolute; top: 50%; width: 12px; height: 12px; margin-top: -6px;
  border: 2px solid var(--linea-fuerte); border-radius: 50%;
  background: var(--superficie); opacity: 0; transition: opacity .12s ease;
}
.prd-bolita-salida { right: -7px; cursor: crosshair; }
.prd-bolita-entrada { left: -7px; }
.prd-caja:hover .prd-bolita, .prd-caja:focus-within .prd-bolita { opacity: 1; }
.prd-bolita-salida:hover { background: var(--laton); border-color: var(--laton-oscuro); transform: scale(1.25); }

/* --- El reloj del tiempo total --- */
.prd-reloj {
  position: absolute; right: 16px; top: 22px; z-index: 6;
  display: flex; flex-direction: column; align-items: flex-end; gap: 4px;
  pointer-events: none;
}
.prd-reloj-caja {
  padding: 9px 14px; text-align: right;
  border: 1px solid var(--laton-oscuro); border-radius: var(--radio-sm);
  background: var(--superficie); box-shadow: 0 2px 10px rgb(0 0 0 / .10);
}
.prd-reloj-rotulo {
  font: 600 10px/1 var(--f-datos); letter-spacing: .12em; text-transform: uppercase;
  color: var(--texto-mudo);
}
.prd-reloj-cifra { font: 700 var(--t-22)/1.2 var(--f-datos); color: var(--laton-texto); margin-top: 3px; }
.prd-reloj-sub { font: 400 var(--t-12)/1.3 var(--f-ui); color: var(--texto-mudo); max-width: 260px; }
.prd-reloj-ruta { font: 400 var(--t-12)/1.3 var(--f-ui); color: var(--texto-mudo); }

@media (max-width: 900px) {
  .prd-reloj { position: static; align-items: flex-start; margin-top: 10px; }
  .prd-hoja-marco { height: 56vh; }
}

/* v0.27.1 · asignar arrastrando en las dos direcciones: la tarjeta se
   enciende cuando se le lleva una persona encima, y mientras se lleva
   una persona se marcan con un borde punteado las tarjetas que pueden
   recibirla —las de los proyectos en los que se puede escribir—. */
.tar-carta-recibe {
  outline: 2px solid var(--laton); outline-offset: 2px;
  background: var(--laton-velo);
}
.tar-llevando-persona .tar-carta[draggable="true"] {
  outline: 1px dashed color-mix(in srgb, var(--laton-oscuro) 60%, transparent);
  outline-offset: 2px;
}
.tar-empleado[draggable="true"] { cursor: grab; }
/* La cara que no abre nada (v0.62.0): sin las cifras de otro, pinchar no
   lleva a ninguna parte. Deja de parecer un botón y sigue pudiendo
   recibir una tarjeta encima. */
.tar-empleado-mudo { cursor: default; }
.tar-empleado-mudo[draggable="true"] { cursor: grab; }
.tar-empleado.arrastrando { opacity: .45; }

/* v0.27.2 · sacar a alguien de una tarea devolviéndolo a la tira. La
   tira es el almacén de gente: se ilumina ENTERA, porque lo que importa
   es volver al almacén y no sobre qué cara se suelte. */
.tar-avatar-cogible { cursor: grab; }
.tar-avatar-cogible.arrastrando { opacity: .4; }
.tar-sacando-persona .tar-equipo-tira {
  outline: 2px dashed var(--laton-oscuro); outline-offset: 3px;
  border-radius: var(--radio-sm);
}
.tar-equipo-tira.tar-tira-recibe {
  outline: 2px solid var(--laton); outline-offset: 3px;
  background: var(--laton-velo);
}

/* =====================================================================
   v0.28 · LAS FERIAS DE AUDIO, colgando del calendario
   ===================================================================== */

.tar-calendario-barra {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-bottom: var(--e-3);
}
.fer-boton { gap: 7px; }
.fer-boton-cuenta {
  min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 9px; background: var(--laton); color: var(--laton-tinta);
  font: 700 10px/18px var(--f-datos); text-align: center;
}

.fer-ventana { display: flex; flex-direction: column; gap: 4px; }
.fer-mandos { margin-top: 10px; }
.fer-resumen {
  display: flex; gap: 16px; flex-wrap: wrap;
  padding: 6px 0 10px; border-bottom: 1px solid var(--linea-suave);
}

.fer-mes {
  font: 700 10px/1 var(--f-datos); letter-spacing: .14em; text-transform: uppercase;
  color: var(--laton-texto);
  margin: 16px 0 8px; padding-top: 8px;
  border-top: 1px solid var(--linea);
}
.fer-mes:first-child { margin-top: 8px; border-top: none; padding-top: 0; }

.fer-ficha {
  display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 12px;
  padding: 10px 12px; margin-bottom: 7px;
  border: 1px solid var(--linea); border-radius: var(--radio-sm);
  background: var(--superficie);
}
/* Lo pasado no se esconde, se apaga: hace falta para escribir la memoria
   del año, pero no compite con lo que todavía se puede hacer. */
.fer-pasada { opacity: .55; background: var(--superficie-2); }
.fer-clave { border-left: 3px solid var(--laton-oscuro); }
.fer-en-marcha {
  border-color: var(--ok);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--ok) 18%, transparent);
}

.fer-cuando { display: flex; flex-direction: column; gap: 2px; }
.fer-dias { font: 700 var(--t-13)/1.2 var(--f-datos); color: var(--texto); white-space: nowrap; }
.fer-cuenta-atras { font: 400 var(--t-12)/1.2 var(--f-ui); color: var(--texto-mudo); }
.fer-cuenta-atras.fer-pronto { color: var(--laton-texto); font-weight: 600; }
.fer-cuenta-atras.fer-ahora { color: var(--ok); font-weight: 700; }

.fer-cuerpo { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.fer-cab { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.fer-nombre { font: 600 var(--t-14)/1.25 var(--f-ui); color: var(--texto); }
.fer-donde { font: 400 var(--t-12)/1.35 var(--f-ui); color: var(--texto-suave); }
.fer-nota { font: 400 var(--t-12)/1.45 var(--f-ui); color: var(--texto-mudo); }
.fer-pie { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 3px; }
.fer-web { font: 500 var(--t-12)/1 var(--f-datos); color: var(--laton-texto); }
.fer-web:hover { text-decoration: underline; }
.fer-dudosa { cursor: help; }

@media (max-width: 640px) {
  .fer-ficha { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  .fer-cuando { flex-direction: row; gap: 10px; align-items: baseline; }
}

/* =====================================================================
   v0.28.1 · las ferias EN el calendario, y el borde que dice el estado
   ===================================================================== */

.fer-interruptor .etiqueta { white-space: nowrap; }

/* El chip de una feria dentro de la celda de un día. Dorado y en
   versalitas: se distingue de un chip de tarea sin tener que leerlo,
   porque son dos cosas de naturaleza distinta —una se mueve de fecha y
   la otra no—. */
.tar-chip.tar-chip-feria {
  background: var(--laton-velo);
  border-color: var(--laton-oscuro);
  color: var(--laton-texto);
  font-weight: 600; letter-spacing: .02em;
}
.tar-chip.tar-chip-feria:hover { background: var(--laton); color: var(--laton-tinta); }
.tar-chip-feria-clave { box-shadow: inset 2px 0 0 0 var(--laton-oscuro); }
/* El día de en medio de una feria de tres: la misma cosa, no otra */
.tar-chip-feria-sigue { opacity: .8; border-style: dashed; }
.tar-chip-feria-mas {
  display: inline-block; cursor: pointer;
  padding: 1px 5px; border-radius: var(--radio-sm);
  border: 1px dashed var(--laton-oscuro);
  font: 600 10px/1.5 var(--f-datos); color: var(--laton-texto);
}
/* El día con feria se tiñe por debajo: se ve el mes de un vistazo */
.tar-dia.tar-dia-feria { background: color-mix(in srgb, var(--laton-velo) 60%, transparent); }
.tar-dia.tar-dia-feria.tar-dia-hoy { background: var(--laton-velo); }

/* --- El borde grueso que dice el estado de una tarjeta --- */
.kanban-carta.tar-borde-pendiente { border: 3px solid var(--linea-fuerte); }
.kanban-carta.tar-borde-en_curso   { border: 3px solid var(--ok); }
.kanban-carta.tar-borde-bloqueada  { border: 3px solid #E8C33F; }
/* Y encima de todo eso, la alarma: lo vencido y lo de hoy siguen mandando,
   porque una fecha incumplida importa más que un estado. */
.kanban-carta.tarea-pendiente { border: 3px solid var(--peligro); }

/* =====================================================================
   M-11 · v0.29 · EL HILO DE MENSAJES de una tarea
   ===================================================================== */

/* --- El icono en la tarjeta --- */
.tar-chat {
  display: flex; align-items: center; gap: 6px; width: 100%;
  margin-top: 6px; padding: 4px 7px;
  border: 1px solid var(--linea); border-radius: var(--radio-sm);
  background: var(--superficie-2); cursor: pointer;
  font: 500 var(--t-12)/1.2 var(--f-ui); color: var(--texto-suave);
  text-align: left;
}
.tar-chat:hover { border-color: var(--laton-oscuro); background: var(--laton-velo); color: var(--texto); }
.tar-chat:focus-visible { outline: 2px solid var(--laton); outline-offset: 1px; }
.tar-chat-icono { display: inline-flex; width: 15px; height: 15px; flex: none; }
.tar-chat-icono svg { width: 100%; height: 100%; }
.tar-chat-cuenta { font: 700 var(--t-12)/1 var(--f-datos); color: var(--laton-texto); }
.tar-chat-texto { color: var(--texto-mudo); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Sin mensajes no desaparece: se apaga. Si solo saliera cuando ya hay
   conversación, nadie encontraría dónde empezarla. */
.tar-chat-vacio { opacity: .55; }
.tar-chat-vacio:hover { opacity: 1; }
/* Sin leer: el punto a la derecha y el icono en dorado */
.tar-chat-sin-leer { border-color: var(--laton-oscuro); background: var(--laton-velo); }
.tar-chat-sin-leer .tar-chat-icono { color: var(--laton-texto); }
.tar-chat-punto {
  margin-left: auto; flex: none;
  width: 9px; height: 9px; border-radius: 50%; background: var(--laton-oscuro);
}

/* --- La ventana del hilo --- */
.tar-hilo { display: flex; flex-direction: column; gap: 10px; }
.tar-hilo-lista {
  display: flex; flex-direction: column; gap: 10px;
  max-height: min(52vh, 460px); overflow-y: auto;
  padding: 10px 4px; border-top: 1px solid var(--linea-suave);
  border-bottom: 1px solid var(--linea-suave);
}
/* Un mensaje no se encoge: la lección de BUG-2026-007. */
.tar-hilo-lista > * { flex: none; }
.tar-hilo-dia {
  align-self: center;
  font: 600 10px/1 var(--f-datos); letter-spacing: .1em; text-transform: uppercase;
  color: var(--texto-mudo); background: var(--superficie-2);
  padding: 4px 10px; border-radius: 999px;
}

.tar-msg { display: flex; gap: 8px; align-items: flex-start; }
.tar-msg-cuerpo {
  flex: 1; min-width: 0;
  padding: 8px 11px;
  border: 1px solid var(--linea); border-radius: var(--radio-sm);
  background: var(--superficie);
}
/* Lo mío se distingue sin tener que leer quién lo escribió */
.tar-msg-mio .tar-msg-cuerpo { background: var(--laton-velo); border-color: var(--laton-oscuro); }
.tar-msg-cab { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.tar-msg-quien { font: 600 var(--t-12)/1.3 var(--f-ui); color: var(--texto); }
.tar-msg-cuando { font: 400 11px/1.3 var(--f-datos); color: var(--texto-mudo); cursor: help; }
.tar-msg-editado {
  font: 400 10px/1.3 var(--f-ui); color: var(--texto-mudo);
  font-style: italic; cursor: help;
}
.tar-msg-texto {
  margin-top: 3px; white-space: pre-wrap; overflow-wrap: anywhere;
  font: 400 var(--t-13)/1.45 var(--f-ui); color: var(--texto);
}
.tar-msg-botones { display: flex; gap: 4px; margin-top: 5px; opacity: 0; transition: opacity .12s ease; }
.tar-msg:hover .tar-msg-botones, .tar-msg:focus-within .tar-msg-botones { opacity: 1; }
.tar-msg-editor { margin-top: 6px; }
.tar-msg-editor textarea { width: 100%; }
.tar-msg-editor-pie { display: flex; gap: 6px; justify-content: flex-end; margin-top: 5px; }

.tar-hilo-escribir textarea { width: 100%; }
.tar-hilo-pie { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 6px; }
.tar-hilo-pie .ayuda { margin: 0; }

.tar-panel-caja { padding: 10px 0; }
.tar-panel-titulo { font: 600 var(--t-14)/1.2 var(--f-ui); color: var(--texto); margin: 0 0 2px; }

/* =====================================================================
   FERIAS · lo que trae la v0.30: novedades, avisos y edición
   ---------------------------------------------------------------------
   La lista dejó de estar escrita en el código y ahora se toca desde la
   pantalla. Eso añade tres cosas que antes no existían: una feria que es
   NOVEDAD, un aviso de que TOCA REPASAR y los botones de cambiarla.
   ===================================================================== */

/* La novedad se ve por el borde y por la palabra, nunca solo por color:
   «nueva» y «cambió de fecha» son dos cosas distintas y la segunda es la
   que obliga a rehacer un billete. */
.fer-ficha.fer-novedad { border-left: 3px solid var(--laton); background: var(--laton-velo); }
.fer-insignia-novedad {
  border: 1px solid color-mix(in srgb, var(--laton) 55%, transparent);
  background: var(--superficie); color: var(--laton-texto);
  font-weight: 700; letter-spacing: .02em;
}

/* El aviso de repaso lleva su botón dentro: decir «hace 41 días que no
   se repasa» y obligar a buscar dónde se apaga es media ayuda. */
.fer-aviso { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: var(--e-3); }
.fer-aviso > span { flex: 1 1 320px; }

/* El punto del botón del calendario: hay algo nuevo que mirar. Sin
   número, porque el número ya está dentro. */
.fer-boton-punto {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--laton); flex: none; margin-left: 2px;
}

.fer-cab .fer-editar { margin-left: auto; flex: none; }
.fer-form .formulario-rejilla { margin-bottom: var(--e-3); }
.fer-form .interruptor.fer-interruptor-form { margin-top: var(--e-2); }
.fer-form .texto-mudo { font-size: var(--t-12); margin: 2px 0 var(--e-2); }
.fer-form .error-texto { margin: 2px 0; }

/* --- El sumario de toda la casa, en la banda del escritorio (v0.30.3) ---
   Va en la MISMA línea que las cifras de lo que se está viendo, así que
   lo único que impide leer unas por otras es la separación: una raya y un
   rótulo. Sin eso, «12 pendientes» junto a «3 abiertas» solo se puede
   leer como una contradicción. */
.tar-resumen-raya {
  width: 1px; height: 20px; align-self: center;
  background: var(--linea); margin: 0 4px; flex: none;
}
.tar-resumen-rotulo {
  font-size: var(--t-12); font-weight: 600; color: var(--texto-mudo);
  text-transform: uppercase; letter-spacing: .05em; white-space: nowrap;
  cursor: help;
}

/* =====================================================================
   EL VÚMETRO DE LA CARGA (v0.31.0)
   ---------------------------------------------------------------------
   Una aguja contesta «¿voy bien?» sin leer, porque la respuesta es una
   POSICIÓN y no una longitud. Y en una casa que fabrica audio de gama
   muy alta, el instrumento que todo el mundo sabe leer es un vúmetro.
   Todo lo de aquí busca que parezca un aparato y no un gráfico: cara de
   marfil con su cristal, escala impresa en tinta, zona roja a partir del
   100 %, aguja fina y un tornillo de latón en el eje.
   ===================================================================== */
.vu { display: flex; align-items: center; gap: 8px; }
.vu svg { display: block; flex: none; }

/* La cara: marfil cálido, no blanco. El blanco puro es de pantalla; el
   marfil es de aparato. El degradado hace de cristal. */
.vu-cara {
  fill: #F6F1E4;
  stroke: var(--linea-fuerte); stroke-width: .8;
}
.vu-escala { fill: none; stroke: #6B5F49; stroke-width: 1; opacity: .55; }
.vu-escala-roja { stroke: var(--peligro); stroke-width: 2.4; opacity: .9; }
.vu-marca { stroke: #6B5F49; stroke-width: .7; opacity: .7; }
.vu-marca-larga { stroke-width: 1.1; opacity: .9; }
.vu-marca-roja { stroke: var(--peligro); }
.vu-cifra {
  font: 600 5.5px var(--f-datos); fill: #6B5F49;
  text-anchor: middle; opacity: .85;
}
/* La unidad impresa en la cara, como en cualquier aparato de medida.
   Cuesta nada y es la mitad de lo que hace que parezca un instrumento. */
.vu-unidad {
  font: 600 5px var(--f-ui); fill: #6B5F49; opacity: .6;
  text-anchor: end; letter-spacing: .04em;
}
/* El reflejo del cristal. Muy tenue: si se nota, estorba. */
.vu-cristal { fill: #FFFFFF; opacity: .34; pointer-events: none; }
/* La cola de la aguja, al otro lado del eje. Es lo que hace que se lea
   como una aguja con contrapeso y no como una raya que sale de un punto. */
.vu-aguja-cola { stroke: #241C10; stroke-width: 1.6; stroke-linecap: round; opacity: .8; }
.vu-cifra-roja { fill: var(--peligro); }

/* La aguja. El eje de giro es el tornillo, y se dice aquí para que la
   posición en reposo (el `transform` del propio SVG) y la animación de
   asentamiento giren exactamente sobre el mismo punto. */
.vu-aguja-eje { transform-origin: 54px 50px; transform-box: view-box; }
.vu-aguja {
  stroke: #241C10; stroke-width: 1.2; stroke-linecap: round;
}
.vu-tornillo { fill: var(--laton-oscuro); stroke: #241C10; stroke-width: .5; }
.vu-tornillo-luz { fill: var(--laton-claro); opacity: .9; }

/* Cuando la aguja está clavada en el tope, la cara lo dice: si no, un
   200 % y un 150 % se verían igual. */
.vu-topado .vu-cara { stroke: var(--peligro); stroke-width: 1.4; }

.vu-lectura { font: 700 var(--t-13)/1 var(--f-datos); white-space: nowrap; }
.vu-verde { color: var(--ok); }
.vu-naranja { color: var(--aviso); }
.vu-rojo { color: var(--peligro); }
.vu-gris { color: var(--texto-mudo); }

/* La carga pico: días en los que no cabe la jornada. */
.tar-pico { font: 600 var(--t-14)/1 var(--f-datos); color: var(--aviso); white-space: nowrap; }
.tar-pico-grave { color: var(--peligro); }

@media (prefers-reduced-motion: reduce) {
  .vu-aguja-eje { transition: none; }
}

/* =====================================================================
   M-13 · SOPORTE (v0.32)
   ---------------------------------------------------------------------
   Dos mundos con la misma paleta: la CONSOLA, que ve el equipo de
   WADAX, y el PORTAL, que ve el cliente. El portal no comparte ni una
   clase de chasis con el ERP a propósito: quien entra desde fuera no
   tiene por qué intuir que detrás hay un sistema de gestión.
   ===================================================================== */

/* Rejilla de dos columnas para los formularios largos de las fichas */
.rejilla-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--e-3);
}

/* Faltaba el tono neutro-frío de la familia de badges */
.badge-info {
  background: var(--info-velo);
  color: var(--texto);
  border-color: var(--linea);
}

/* Una fila de tabla que pide atención: se ha pasado un compromiso.
   Es un velo, no un fondo sólido: la tabla se sigue leyendo. */
.fila-alerta { background: var(--peligro-velo) !important; }

/* --- La banda de cifras de arriba --- */
.sop-sumario { margin-top: var(--e-4); }
.sop-cifras {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--e-3);
}
.sop-cifra {
  background: var(--superficie);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  padding: var(--e-3) var(--e-4);
  display: flex; flex-direction: column; gap: 2px;
}
.sop-cifra .n { font: 700 var(--t-28)/1 var(--f-datos); color: var(--texto); }
.sop-cifra .t { font: 500 var(--t-12)/1.3 var(--f-ui); color: var(--texto-mudo); }
.sop-cifra.aviso   { border-color: var(--aviso);   background: var(--aviso-velo); }
.sop-cifra.peligro { border-color: var(--peligro); background: var(--peligro-velo); }
.sop-cifra.peligro .n { color: var(--peligro); }
.sop-cifra.ok .n { color: var(--ok); }

.sop-vistas { margin-top: 0; border-bottom: 0; }

/* --- Columnas de la cola --- */
.sop-hilo, .sop-reloj {
  display: inline-flex; align-items: center; gap: 6px;
  font: 500 var(--t-13)/1 var(--f-ui); color: var(--texto-suave);
}
.sop-hilo svg, .sop-reloj svg { width: 15px; height: 15px; }
.sop-hilo.espera { color: var(--laton-texto); font-weight: 700; }
.sop-reloj.peligro { color: var(--peligro); font-weight: 700; }

/* --- La ventana de un parte --- */
.sop-ficha { display: flex; flex-direction: column; gap: var(--e-3); }
.sop-ficha-cabecera {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-3); flex-wrap: wrap;
}
.sop-ficha-titulo { display: flex; align-items: center; gap: var(--e-2); flex-wrap: wrap; }
.sop-ficha-reloj {
  display: inline-flex; align-items: center; gap: 6px;
  font: 500 var(--t-13)/1 var(--f-ui); color: var(--texto-suave);
}
.sop-ficha-reloj svg { width: 16px; height: 16px; }
.sop-ficha-reloj.peligro { color: var(--peligro); font-weight: 700; }
.sop-panel { display: flex; flex-direction: column; gap: var(--e-4); }

/* --- Escribir en el hilo ---
   El fondo cambia entero al pasar a nota interna. No es adorno: es lo
   que evita que alguien le escriba al cliente lo que no debe. */
.sop-escribir {
  display: flex; flex-direction: column; gap: var(--e-2);
  background: var(--superficie-2);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  padding: var(--e-3);
}
.sop-escribir.es-interno {
  background: var(--aviso-velo);
  border-color: var(--aviso);
}
.sop-escribir textarea {
  width: 100%; resize: vertical;
  font: 400 var(--t-14)/1.5 var(--f-ui);
}
.sop-escribir-pie {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-2); flex-wrap: wrap;
}
.sop-tipo-mensaje { margin-top: 0; border-bottom: 0; }

/* --- Las burbujas --- */
.sop-hilo-lista { display: flex; flex-direction: column; gap: var(--e-3); }
.sop-burbuja {
  border: 1px solid var(--linea);
  border-left: 3px solid var(--linea-fuerte);
  border-radius: var(--radio-sm);
  padding: var(--e-3);
  background: var(--superficie);
}
.sop-burbuja.cliente { border-left-color: var(--texto-mudo); }
.sop-burbuja.wadax   { border-left-color: var(--laton); background: var(--laton-velo); }
.sop-burbuja.agente  { border-left-color: var(--laton-claro); }
.sop-burbuja.interno {
  border-left-color: var(--aviso);
  background: var(--aviso-velo);
  border-style: dashed;
}
.sop-burbuja-cab {
  display: flex; align-items: center; gap: var(--e-2);
  flex-wrap: wrap; margin-bottom: 6px;
  font: 500 var(--t-12)/1.3 var(--f-ui);
}
.sop-burbuja-cuerpo {
  font: 400 var(--t-14)/1.55 var(--f-ui);
  color: var(--texto);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* --- Datos del parte y del RMA --- */
.sop-datos, .sop-rma-datos { display: flex; flex-direction: column; gap: var(--e-3); }
.sop-datos-pie {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-2); flex-wrap: wrap;
  border-top: 1px solid var(--linea-suave);
  padding-top: var(--e-3);
}

/* --- Parte nuevo y lectura de la agente --- */
.sop-nuevo { display: flex; flex-direction: column; gap: var(--e-3); }
.sop-lectura {
  display: flex; flex-direction: column; gap: var(--e-3);
  border: 1px solid var(--laton);
  border-radius: var(--radio);
  background: var(--laton-velo);
  padding: var(--e-3);
}
.sop-lectura-cab { display: flex; align-items: center; gap: var(--e-2); flex-wrap: wrap; }

/* --- El RMA --- */
.sop-rma { display: flex; flex-direction: column; gap: var(--e-4); }
.sop-rma-barra { display: flex; justify-content: flex-end; }
.sop-rma-tarjeta {
  display: flex; flex-direction: column; gap: var(--e-3);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  padding: var(--e-4);
  background: var(--superficie);
}
.sop-rma-cab { display: flex; align-items: center; gap: var(--e-2); flex-wrap: wrap; }
.sop-rma-pasos { display: flex; gap: var(--e-2); flex-wrap: wrap; }

/* La escalera del RMA: dónde está la unidad y qué le queda.
   Se envuelve en varias líneas a propósito: son once pasos y forzarlos
   en una sola línea los dejaría ilegibles en un portátil. */
.sop-escalera { display: flex; flex-wrap: wrap; gap: 4px; }
.sop-peldano {
  font: 500 var(--t-12)/1.2 var(--f-ui);
  color: var(--texto-mudo);
  background: var(--superficie-2);
  border: 1px solid var(--linea-suave);
  border-radius: 999px;
  padding: 5px 10px;
}
.sop-peldano.hecho { color: var(--texto-suave); background: var(--ok-velo); border-color: var(--ok); }
.sop-peldano.aqui {
  color: var(--laton-tinta); background: var(--laton); border-color: var(--laton-oscuro);
  font-weight: 700;
}

/* =====================================================================
   EL PORTAL DEL CLIENTE
   Casa aparte: sin menú, sin módulos y sin nada que huela a ERP.
   ===================================================================== */
.portal {
  min-height: 100vh;
  display: flex; flex-direction: column;
  background: var(--fondo);
}
.portal-cab {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-3); flex-wrap: wrap;
  padding: var(--e-4) var(--e-5);
  border-bottom: 1px solid var(--linea);
  background: var(--superficie);
}
.portal-logo { height: 34px; width: auto; }
.portal-cab-der { display: flex; align-items: center; gap: var(--e-3); }
.portal-quien { font: 500 var(--t-13)/1 var(--f-ui); color: var(--texto-suave); }
.portal-cuerpo {
  flex: 1;
  width: min(900px, 94vw);
  margin: 0 auto;
  padding: var(--e-6) 0 var(--e-8);
  display: flex; flex-direction: column; gap: var(--e-4);
}
.portal-intro h1 { font: 700 var(--t-28)/1.2 var(--f-titulos); color: var(--texto); margin-bottom: var(--e-2); }
.portal-intro p { font: 400 var(--t-14)/1.6 var(--f-ui); color: var(--texto-suave); max-width: 62ch; }
.portal-barra { display: flex; justify-content: flex-end; }
.portal-pie {
  padding: var(--e-4) var(--e-5);
  border-top: 1px solid var(--linea-suave);
  font: 400 var(--t-12)/1 var(--f-ui);
  color: var(--texto-mudo);
  text-align: center;
}
.portal-vacio { text-align: center; }

.portal-parte {
  display: flex; flex-direction: column; gap: 6px;
  width: 100%; text-align: left; cursor: pointer;
  appearance: none;
  background: var(--superficie);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  padding: var(--e-4);
}
.portal-parte:hover { border-color: var(--laton); box-shadow: var(--sombra-1); }
.portal-parte-cab { display: flex; align-items: center; gap: var(--e-2); flex-wrap: wrap; }
.portal-parte-asunto { font: 600 var(--t-15)/1.35 var(--f-ui); color: var(--texto); }
.portal-parte-pie { font: 400 var(--t-12)/1.4 var(--f-ui); }

.portal-detalle { display: flex; flex-direction: column; gap: var(--e-4); }
.portal-detalle-cab { display: flex; align-items: center; gap: var(--e-2); flex-wrap: wrap; }
.portal-rma {
  display: flex; flex-direction: column; gap: var(--e-2);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  padding: var(--e-3);
  background: var(--superficie-2);
}
.portal-rma-cab { display: flex; align-items: center; gap: var(--e-2); font: 600 var(--t-13)/1 var(--f-ui); }

.portal-valorar { display: flex; flex-direction: column; gap: var(--e-2); align-items: center; }
.portal-estrellas { display: flex; gap: var(--e-2); }
.portal-estrella {
  appearance: none; cursor: pointer;
  width: 40px; height: 40px;
  border-radius: 999px;
  border: 1px solid var(--linea);
  background: var(--superficie);
  font: 600 var(--t-15)/1 var(--f-datos);
  color: var(--texto-suave);
}
.portal-estrella:hover { background: var(--laton); color: var(--laton-tinta); border-color: var(--laton-oscuro); }

/* La puerta del cliente, en la pantalla de acceso */
.acceso-cliente .acceso-caja { max-width: 460px; }

/* =====================================================================
   v0.33 · Soporte: el buzón, los ficheros, los avisos y las repetidas
   ===================================================================== */

/* --- Ficheros de un parte ------------------------------------------
   Rejilla que se adapta sola: en la ficha del personal caben cuatro por
   fila y en el portal del cliente, dos. La miniatura tiene alto fijo
   para que la fila no baile según la foto que suba cada uno. */
.sop-adjuntos { margin-top: var(--e-3); }
.sop-adjuntos-rejilla {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--e-3);
  margin-top: var(--e-2);
}
.sop-adjunto {
  display: flex; flex-direction: column; gap: 6px;
  border: 1px solid var(--linea-suave); border-radius: var(--r-2);
  background: var(--superficie); overflow: hidden;
}
.sop-adjunto-cara {
  appearance: none; cursor: pointer; padding: 0;
  border: 0; border-bottom: 1px solid var(--linea-suave);
  background: var(--superficie-2);
  height: 112px;
  display: flex; align-items: center; justify-content: center;
}
.sop-adjunto-cara:hover { background: var(--laton-velo); }
.sop-adjunto-mini { width: 100%; height: 112px; object-fit: cover; display: block; }
.sop-adjunto-icono { color: var(--texto-mudo); display: inline-flex; }
.sop-adjunto-pie {
  display: flex; flex-direction: column; gap: 2px;
  padding: 0 var(--e-2) var(--e-2); font-size: var(--t-12);
}
.sop-adjunto-nombre {
  font-size: var(--t-13); font-weight: 500; color: var(--texto);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* --- El buzón ------------------------------------------------------- */
.sop-buzon-item { cursor: pointer; }
.sop-buzon-cab {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--e-3);
}
/* El correo, tal y como llegó: se respetan los saltos de línea porque un
   correo con la sangría perdida deja de parecer un correo, y hay que
   poder leerlo como lo escribió quien lo escribió. */
.sop-buzon-texto {
  margin-top: var(--e-3);
  padding: var(--e-3);
  border: 1px solid var(--linea-suave); border-radius: var(--r-2);
  background: var(--superficie-2);
  font: 400 var(--t-14)/1.55 var(--f-ui);
  white-space: pre-wrap; word-break: break-word;
  max-height: 320px; overflow-y: auto;
}

/* --- La banda de avisos --------------------------------------------- */
.sop-avisos { display: flex; align-items: flex-start; gap: var(--e-3); justify-content: space-between; }
.sop-avisos-lista { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; }
.sop-aviso-fila { display: flex; flex-wrap: wrap; gap: var(--e-2); align-items: baseline; }
.sop-aviso-titulo { font-weight: 600; }

/* --- Unidades repetidas --------------------------------------------- */
.sop-repetidos-enlaces { display: inline-flex; flex-wrap: wrap; gap: 6px; margin-left: var(--e-2); }

/* Un vídeo o un PDF no tienen miniatura. Una tarjeta con un hueco gris
   parece que se ha subido mal, así que la cara dice qué es (v0.33.2). */
.sop-adjunto-cara { flex-direction: column; gap: 6px; }
.sop-adjunto-ext {
  font: 600 var(--t-12)/1 var(--f-datos);
  letter-spacing: .08em;
  color: var(--texto-mudo);
}

/* =====================================================================
   M-90 · AJUSTES → ESTRUCTURA INTERNA (16/08/2026) · el diagrama
   ---------------------------------------------------------------------
   Un diagrama de bloques que se mira y no se toca. Las cuatro capas van
   apiladas y los cables van en una capa SVG POR DEBAJO de ellas, como
   en la hoja de procesos de Producción.

   EL COLOR SEPARA CAPAS, NO DECORA. Son las mismas cuatro familias de
   color apagado que ya usa la hoja de procesos para sus grupos de
   proceso —no se estrena paleta—, y el dorado de la casa se reserva
   entero para una sola cosa: las tres puertas al exterior. Si el dorado
   marcara también otra cosa, dejaría de marcar las puertas.

   Y EL TRAZO DICE DE DÓNDE SALE EL DATO: continuo, leído del propio
   sistema al abrir la pestaña; discontinuo, escrito a mano. Se ve sin
   leer una palabra, que es de lo que se trata.
   ===================================================================== */

.est-panel { display: block; }

/* --- Las dos tiras de arriba --- */
.est-tiras { display: flex; flex-direction: column; gap: var(--e-2); margin-bottom: var(--e-3); }
.est-tira { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-2) var(--e-3); }
.est-tira-rotulo {
  font: 700 10px/1 var(--f-datos); letter-spacing: .18em; text-transform: uppercase;
  color: var(--texto-mudo);
}
.est-puerta-chip {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 4px 10px 4px 5px; border-radius: 999px;
  border: 1px solid var(--laton-oscuro); background: var(--laton-velo);
  font-size: var(--t-12); color: var(--laton-texto);
}
.est-puerta-chip strong { color: var(--texto); font-weight: 700; }
.est-puerta-que { color: var(--texto-suave); }
.est-puerta-num {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 17px; height: 17px; border-radius: 50%;
  background: var(--laton); color: var(--laton-tinta);
  font: 700 11px/1 var(--f-datos); align-self: center;
}
.est-muestra { display: inline-flex; align-items: center; gap: 6px; font-size: var(--t-12); color: var(--texto-suave); }
.est-muestra-caja {
  width: 24px; height: 14px; flex: none; border-radius: 4px;
  border: 1px solid var(--linea-fuerte); border-left: 3px solid var(--texto-mudo);
  background: var(--superficie-2);
}
.est-muestra-caja.est-muestra-mano { border-style: dashed; }

/* --- La hoja --- */
/* El pasillo de la derecha (128px) es para el cable que va de la capa 1
   a la capa 3 saltándose la 2: un cable que cruzara por encima de la
   base de datos diría que pasa por ella, y no pasa. */
.est-hoja-marco {
  position: relative; overflow: auto;
  border: 1px solid var(--linea); border-radius: var(--radio-sm);
  background: var(--superficie-2);
}
.est-hoja {
  position: relative; min-width: 940px;
  padding: var(--e-4) 128px var(--e-4) var(--e-4);
  background-image: radial-gradient(circle, var(--linea) 1px, transparent 1px);
  background-size: 24px 24px;
}
.est-cables { position: absolute; inset: 0; z-index: 1; overflow: visible; pointer-events: none; }
.est-cable { fill: none; stroke: var(--linea-fuerte); stroke-width: 2; }
.est-cable-laton { stroke: var(--laton-oscuro); stroke-width: 2.5; }
.est-cable-texto { font-family: var(--f-ui); font-size: 11px; font-weight: 500; fill: var(--texto-mudo); }
.est-cable-texto-laton { fill: var(--laton-texto); font-weight: 700; }

/* --- Una capa --- */
.est-capa {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: 148px minmax(0, 1fr); gap: var(--e-3);
  padding: var(--e-3); border: 1px solid var(--linea);
  border-left: 4px solid var(--est-color, var(--linea-fuerte));
  border-radius: var(--radio-sm); background: var(--superficie);
  box-shadow: 0 1px 2px rgb(0 0 0 / .05);
}
.est-capa + .est-capa { margin-top: 42px; }
.est-capa-1 { --est-color: #6E7F8D; }   /* azul pizarra */
.est-capa-2 { --est-color: #5F7A6B; }   /* verde apagado */
.est-capa-3 { --est-color: #7B6A86; }   /* morado apagado */
.est-capa-4 { --est-color: #8A7B5E; }   /* tierra */

.est-rail { display: flex; flex-direction: column; gap: 3px; }
.est-rail-num { font: 700 var(--t-28)/1 var(--f-titulos); color: var(--est-color); }
.est-rail-nombre {
  font: 700 11px/1.1 var(--f-datos); letter-spacing: .16em; text-transform: uppercase;
  color: var(--est-color);
}
.est-rail-sub { font: 400 var(--t-12)/1.35 var(--f-ui); color: var(--texto-mudo); }
.est-rail-marca { margin-top: 2px; }

/* --- Una caja --- */
/* Rejilla y no flujo libre: con `flex-wrap` la última fila se estira y
   quedan filas de cuatro cajas anchas donde caben cinco, y el diagrama
   crece a lo alto sin ganar nada. Con `auto-fill` las columnas salen
   solas del ancho que haya y las cajas de una fila miden lo mismo, que
   es lo que hace que un diagrama se lea de un barrido. */
.est-cuerpo {
  display: grid; gap: var(--e-2); align-content: start;
  grid-template-columns: repeat(auto-fill, minmax(184px, 1fr));
}
/* La capa 1 pide columnas más anchas: sus cajas no llevan una frase,
   llevan la lista de módulos del grupo en pastillas, y en una columna
   estrecha cada pastilla se come una línea entera. */
.est-capa-1 .est-cuerpo { grid-template-columns: repeat(auto-fill, minmax(232px, 1fr)); }
.est-caja {
  display: flex; flex-direction: column; gap: 3px;
  padding: 6px 9px;
  border: 1px solid var(--linea-fuerte);
  border-left: 3px solid var(--est-color, var(--linea-fuerte));
  border-radius: var(--radio-sm); background: var(--superficie-2);
}
/* Escrito a mano: se ve sin leer nada. */
.est-caja-mano {
  border: 1px dashed var(--linea-fuerte);
  border-left: 3px dashed var(--est-color, var(--linea-fuerte));
  background: var(--superficie);
}
/* Una puerta al exterior. El único dorado del diagrama. */
.est-caja-puerta {
  border-color: var(--laton-oscuro);
  background: var(--laton-velo);
  box-shadow: 0 0 0 2px var(--laton-velo);
}
.est-caja-pendiente { border-color: color-mix(in srgb, var(--aviso) 55%, transparent); }

.est-caja-cab { display: flex; align-items: flex-start; gap: 6px; }
.est-glifo { display: inline-flex; flex: none; width: 17px; height: 17px; color: var(--est-color, var(--texto-mudo)); }
.est-glifo svg { width: 100%; height: 100%; }
.est-caja-titulo { font: 600 var(--t-13)/1.25 var(--f-ui); color: var(--texto); flex: 1; min-width: 0; word-break: break-word; }
.est-caja-titulo.est-mono { font-family: var(--f-datos); font-size: var(--t-12); letter-spacing: .01em; }
.est-cifra { font: 700 var(--t-13)/1.3 var(--f-datos); color: var(--texto); }
.est-caja-texto { font: 400 var(--t-12)/1.35 var(--f-ui); color: var(--texto-suave); }

/* --- Chips --- */
.est-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 1px; }
.est-chip {
  display: inline-flex; align-items: center;
  padding: 2px 7px; border-radius: 999px;
  border: 1px solid var(--linea); background: var(--superficie);
  font: 500 10px/1.4 var(--f-datos); letter-spacing: .02em; color: var(--texto-suave);
}
.est-chip-modulo { background: var(--superficie); border-color: var(--linea-fuerte); color: var(--texto); }
.est-chip-prox { border-style: dashed; color: var(--texto-mudo); background: transparent; }
.est-chip-leido { border-color: color-mix(in srgb, var(--ok) 45%, transparent); background: var(--ok-velo); color: var(--ok); }
.est-chip-mano { border-style: dashed; border-color: var(--linea-fuerte); color: var(--texto-mudo); }
.est-chip-mudo { background: var(--info-velo); border-color: transparent; color: var(--texto-mudo); }
.est-chip-fallo { border-color: color-mix(in srgb, var(--peligro) 45%, transparent); background: var(--peligro-velo); color: var(--peligro); }
.est-chip-pendiente { border-color: color-mix(in srgb, var(--aviso) 55%, transparent); background: var(--aviso-velo); color: var(--aviso); }
.est-chip-sesion { border-color: color-mix(in srgb, var(--ok) 45%, transparent); background: var(--ok-velo); color: var(--ok); }
.est-chip-sinsesion { background: var(--info-velo); border-color: transparent; color: var(--texto-suave); }

/* --- Cuando la base no contesta --- */
.est-fallo { grid-column: 1 / -1; }
.est-detalle { margin-top: 6px; font-size: var(--t-12); }
.est-esperando { font-size: var(--t-13); margin: 2px 0; }

/* SI NO CABE, LA QUE SE DESPLAZA ES LA CAPA DE FUERA, no el diagrama
   entero. Pero con cuidado, y por eso el umbral es bajo: este diagrama
   se mira sobre todo en una CAPTURA DE PANTALLA, y una capa recortada
   se fotografía a medias sin avisar de que falta algo —que es la misma
   familia de mentira que un cero en lugar de un error—. Así que en una
   pantalla normal esto no se activa nunca y la página se desplaza como
   cualquier otra; solo en una pantalla muy baja, donde si no la capa 4
   dejaría el resto del diagrama fuera de la vista, se le pone tope y se
   marca el borde para que se vea que ahí dentro hay más. */
@media (max-height: 720px) {
  .est-capa-4 .est-cuerpo {
    max-height: 240px; overflow-y: auto;
    border-bottom: 1px dashed var(--linea-fuerte);
  }
}

/* NO hay variante estrecha, y es a propósito. La hoja tiene un ancho
   mínimo y el marco se desplaza en horizontal, que es lo que hace WERP
   con las tablas. Se probó apilar el raíl bajo 900 px y salía peor: la
   media query mira el ancho de la VENTANA y la hoja sigue midiendo lo
   que mide, así que el raíl se reorganizaba dentro de una capa que no
   se había estrechado y el rótulo de la capa se cortaba. Un diagrama de
   bloques no se hace responsive: se mueve. */

/* =====================================================================
   M-13 Soporte · el escritorio y las normas de ARIA (v0.40)
   ===================================================================== */

/* --- El escritorio ------------------------------------------------- */
/* El borde de la tarjeta dice en qué columna está, igual que en Tareas:
   así un parte se lee igual esté donde esté. «Resueltos» no lleva borde
   —ya lo dice la columna verde— y añadir un cuarto color solo restaría
   fuerza a los tres que hay que mirar. */
.sop-carta.sop-borde-sin_mirar { border-left: 3px solid var(--peligro); }
.sop-carta.sop-borde-en_curso  { border-left: 3px solid var(--ok); }
.sop-carta.sop-borde-esperando { border-left: 3px solid var(--aviso); }

/* ARIA no es una persona y su ficha en la tira no lo disimula: va con el
   hilo de latón de la casa, que es como se marca en WERP lo que hace la
   máquina. */
.sop-empleado-aria .avatar {
  background: var(--laton-velo);
  color: var(--laton-texto);
  border: 1px dashed var(--laton-oscuro);
}
.sop-empleado-aria .tar-empleado-apellido { font-style: italic; color: var(--texto-mudo); }

/* Un aro rojo alrededor de la cara: esa persona tiene algún parte fuera
   del plazo comprometido. Se ve de lejos y no compite con los tres
   números, que viven en sitios fijos para poder leerse sin leerlos. */
.sop-cara-fuera .avatar { box-shadow: 0 0 0 2px var(--peligro); }

/* --- Las normas de ARIA -------------------------------------------- */
.sop-aria { display: flex; flex-direction: column; gap: var(--e-4); }
.sop-aria-cabecera { line-height: 1.5; }
.sop-aria-mando {
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  padding: var(--e-3);
  background: var(--superficie-2);
  display: flex; flex-direction: column; gap: var(--e-2);
}
.sop-aria-mando .interruptor .etiqueta { font-size: var(--t-15); color: var(--texto); }
.sop-aria-ayuda { line-height: 1.5; margin-top: 4px; }
/* Cuando ARIA queda suelta con cualquier cliente, el aviso NO es texto
   mudo: es lo único de esta ventana que hay que leer antes de cerrarla. */
.sop-aria-alerta {
  color: var(--peligro);
  font-size: var(--t-13);
  font-weight: 600;
  line-height: 1.5;
  margin-top: 4px;
}
.sop-aria-historial { display: flex; flex-direction: column; gap: 4px; margin-top: var(--e-2); }
.sop-aria-version {
  display: flex; gap: var(--e-3); align-items: baseline;
  font-size: var(--t-13); color: var(--texto-suave);
  padding: 4px 0; border-bottom: 1px solid var(--linea-suave);
}
.sop-aria-boton .badge { margin-left: 4px; }

/* ---------------------------------------------------------------------
   EL IDIOMA, EN LA ESQUINA DE LAS DOS PUERTAS (D-108, D-127)
   Dos banderas arriba a la izquierda, en la pantalla de acceso de WERP y
   en la del cliente. Lo pidió Javier el 26/08/2026.

   Antes era un desplegable debajo de la tarjeta con la etiqueta «Idioma»
   escrita —en español—, y ahí había un círculo tonto: quien no entiende
   la palabra «Idioma» es exactamente quien necesita leerla.

   Pegadas a la esquina de la PANTALLA y no de la tarjeta, porque el
   idioma es de todo lo que se ve, no del formulario. Y por eso `.acceso`
   lleva `position: relative`.
   --------------------------------------------------------------------- */
/* La etiqueta de PRUEBAS, en la esquina de enfrente de las banderas: las
   dos cosas son de la pantalla y no del formulario, y así no se pisan. */
.puerta-pruebas {
  position: absolute; top: var(--e-4); right: var(--e-4);
  z-index: 2; font-family: var(--f-datos); font-size: 11px;
}

.puerta-idioma {
  position: absolute; top: var(--e-4); left: var(--e-4);
  display: flex; gap: 8px; z-index: 2;
}
.puerta-idioma-bandera {
  /* Un botón de verdad, sin parecerlo: el borde y el fondo del navegador
     se quitan aquí y no en un `div`, para que el tabulador y el lector de
     pantalla sigan funcionando. */
  appearance: none; background: none; border: 0; padding: 0; cursor: pointer;
  width: 30px; height: 20px; border-radius: 3px; overflow: hidden;
  line-height: 0;
  /* LA QUE NO ESTÁ PUESTA, A MEDIA LUZ PERO RECONOCIBLE. Si se viera
     igual de viva no se sabría en qué idioma estás sin leer la pantalla,
     y quien viene a estos botones es justamente quien no la entiende.
     El número está mirado con lupa: con `.45` y un `saturate(.7)` —el
     primer intento— la bandera de España se convertía en una mancha
     marrón a 30 px y no se distinguía de nada, y eso rompe lo otro que
     tiene que cumplir: que se vea DÓNDE hay que pulsar. Con `.6` y sin
     filtro se reconoce y sigue estando claramente apagada. */
  opacity: .6;
  outline: 1px solid var(--borde); outline-offset: 0;
  transition: opacity .15s ease, box-shadow .15s ease;
}
.puerta-idioma-bandera svg { width: 100%; height: 100%; display: block; }
.puerta-idioma-bandera:hover { opacity: .85; }
.puerta-idioma-bandera.es-la-puesta {
  opacity: 1;
  outline-color: var(--laton);
  box-shadow: 0 0 0 2px rgba(199, 177, 111, .28);
}
.puerta-idioma-bandera:focus-visible {
  outline: 2px solid var(--laton); outline-offset: 2px;
}

/* En el móvil, más pequeñas y más pegadas a la esquina: la pantalla de
   acceso ya va justa de alto y el logotipo tiene que caber entero. */
@media (max-width: 480px) {
  .puerta-pruebas { top: var(--e-3); right: var(--e-3); }
  .puerta-idioma { top: var(--e-3); left: var(--e-3); gap: 6px; }
  .puerta-idioma-bandera { width: 26px; height: 17px; }
}

/* ---------------------------------------------------------------------
   VOLVER A DONDE ESTABAS (D-107)
   Flotante abajo a la izquierda, y no en la cabecera del módulo, por una
   razón práctica: la cabecera se va con el scroll y este botón tiene que
   estar cuando termines de leer, que es abajo. En el móvil sube un poco
   para no taparse con la barra del navegador.
   --------------------------------------------------------------------- */
.volver-flotante {
  position: fixed; left: 18px; bottom: 18px; z-index: 60;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 16px; border-radius: 999px;
  border: 1px solid var(--linea-fuerte); background: var(--superficie);
  color: var(--texto); font-family: var(--f-ui); font-size: var(--t-14);
  box-shadow: var(--sombra-2); cursor: pointer;
}
.volver-flotante:hover { border-color: var(--laton); }
.volver-icono { display: inline-flex; width: 18px; height: 18px; }
.volver-icono svg { width: 100%; height: 100%; }

@media (max-width: 640px) {
  .volver-flotante { left: 12px; bottom: 68px; padding: 9px 14px; }
}

/* ---------------------------------------------------------------------
   EL PARTE DEL DÍA EN INICIO (D-106)
   Los mismos tres niveles que el correo —rojo, ámbar, gris— y el mismo
   subrayado dorado en los enlaces: quien lo lee por los dos sitios tiene
   que reconocerlo. El punto de color va en un `::before` para que al
   copiar el texto no se lleve el bolo.
   --------------------------------------------------------------------- */
.parte-cabecera {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--e-3); flex-wrap: wrap;
}
.parte-veredicto { font-size: var(--t-18); line-height: 1.35; }
.parte-cuando { font-size: var(--t-12); line-height: 1.5; margin-top: 4px; max-width: 70ch; }
.parte-bloque { margin-top: var(--e-4); }
.parte-titulo {
  font-size: var(--t-12); letter-spacing: .12em; text-transform: uppercase;
  color: var(--texto-mudo); padding-bottom: 6px; border-bottom: 1px solid var(--linea);
}
.parte-lineas { list-style: none; margin: 0; padding: 0; }
.parte-linea { position: relative; padding: 8px 0 0 18px; line-height: 1.5; font-size: var(--t-14); }
.parte-linea::before {
  content: "\2022"; position: absolute; left: 2px; top: 8px; font-weight: 700;
  color: var(--texto-mudo);
}
.parte-linea.nivel-rojo::before { color: var(--peligro); }
.parte-linea.nivel-ambar::before { color: var(--aviso); }
.parte-enlace {
  color: var(--texto); text-decoration: underline;
  text-decoration-color: var(--laton); text-underline-offset: 2px;
}
.parte-enlace:hover { text-decoration-color: var(--laton-oscuro); }
.parte-pie { margin-top: var(--e-4); line-height: 1.5; font-size: var(--t-12); max-width: 78ch; }

/* ---------------------------------------------------------------------
   CON QUÉ HABLA ARIA (D-105)
   Los dos selectores de cada trabajo van EN LA MISMA LÍNEA: modelo y
   esfuerzo son una sola decisión y separarlos haría leer dos veces.
   --------------------------------------------------------------------- */
.sop-modelo { display: flex; flex-direction: column; gap: var(--e-2); margin-top: var(--e-4); }
.sop-modelo-titulo { font-size: var(--t-15); margin: 0; }
.sop-modelo-fila { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-4); }
.sop-modelo-par { display: flex; gap: var(--e-2); }
.sop-modelo-par select { flex: 1 1 0; min-width: 0; }
.sop-modelo-gasto {
  padding: var(--e-3); border: 1px solid var(--linea); border-radius: var(--radio-sm);
  background: var(--superficie-2);
}
.sop-modelo-cifra { font-family: var(--f-datos); font-size: var(--t-22); }
.sop-modelo-detalle { line-height: 1.5; margin-top: 4px; font-size: var(--t-12); }

@media (max-width: 640px) {
  .sop-modelo-fila { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------
   HABLAR CON ARIA SIN CORREO (D-104)
   El hilo tiene ALTURA FIJA y scroll propio a propósito: si creciera
   hacia abajo, la caja de escribir se iría fuera de la pantalla justo
   cuando la conversación se pone interesante, y habría que buscarla.
   --------------------------------------------------------------------- */
.sop-prueba { display: flex; flex-direction: column; gap: var(--e-3); margin-top: var(--e-4); }
.sop-prueba-barra {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-2); flex-wrap: wrap;
}
.sop-prueba-acciones { display: flex; gap: var(--e-2); }
.sop-prueba-hilo {
  height: 340px; overflow-y: auto; padding: var(--e-3);
  border: 1px solid var(--linea); border-radius: var(--radio-sm);
  background: var(--superficie-2);
  display: flex; flex-direction: column; gap: var(--e-3);
}
.sop-prueba-vacio { margin: auto; text-align: center; max-width: 34ch; line-height: 1.5; }
.sop-prueba-msg { max-width: 80%; display: flex; flex-direction: column; gap: 2px; }
.sop-prueba-msg.es-cliente { align-self: flex-start; }
.sop-prueba-msg.es-aria,
.sop-prueba-msg.es-interno { align-self: flex-end; }
.sop-prueba-quien { font-size: var(--t-12); color: var(--texto-mudo); }
.sop-prueba-cuerpo {
  padding: var(--e-2) var(--e-3); border-radius: var(--radio-sm);
  white-space: pre-wrap; line-height: 1.5; font-size: var(--t-14);
  border: 1px solid var(--linea);
}
.es-cliente .sop-prueba-cuerpo { background: var(--superficie); }
.es-aria .sop-prueba-cuerpo { background: var(--laton-velo); }
/* La nota interna se pinta DISTINTA porque el cliente no la ve: si se
   pareciera a una respuesta, se leería como algo que se le ha dicho. */
.es-interno .sop-prueba-cuerpo {
  background: transparent; border-style: dashed; font-style: italic;
}
.sop-prueba-pie-msg { font-size: var(--t-12); }
.sop-prueba-escribir { display: flex; flex-direction: column; gap: var(--e-2); }
.sop-prueba-escribir textarea { width: 100%; resize: vertical; }
.sop-prueba-pie {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-2); flex-wrap: wrap;
}
.sop-prueba-lista { display: flex; flex-direction: column; gap: 4px; margin-top: var(--e-2); }
.sop-prueba-vieja {
  display: flex; align-items: center; justify-content: space-between; gap: var(--e-2);
  padding: var(--e-2); border: 1px solid var(--linea); border-radius: var(--radio-sm);
}
.sop-prueba-vieja-titulo { font-size: var(--t-14); }
.sop-prueba-vieja-pie { font-size: var(--t-12); }
.sop-prueba-vieja-botones { display: flex; gap: 4px; flex-shrink: 0; }

@media (max-width: 640px) {
  .sop-prueba-hilo { height: 260px; }
  .sop-prueba-msg { max-width: 100%; }
}

/* --- Borrar un parte ------------------------------------------------ */
.sop-borrar { display: flex; flex-direction: column; gap: var(--e-3); }
.sop-borrar-lista { margin: 0; padding-left: var(--e-5); line-height: 1.6; color: var(--texto-suave); }

/* =====================================================================
   M-14 · ALMACÉN · v0.47.0
   ---------------------------------------------------------------------
   La idea: el almacén se MIRA. Un hueco con material se rellena con el
   dorado del logo; uno vacío deja ver el papel. Así «¿dónde hay?» se
   contesta antes de leer una sola cifra, que es lo que hace falta cuando
   hay poca gente para muchas referencias.

   Y el dorado se administra con avaricia, como manda DISEÑO.md: se usa
   para «aquí hay algo» y para el botón principal, y para nada más. Si
   todos los huecos fueran dorados, ninguno lo sería.
   ===================================================================== */

.aviso.aviso-aviso { border-color: color-mix(in srgb, var(--aviso) 45%, transparent); background: var(--aviso-velo); color: var(--aviso); }

.alm-mandos { display: flex; gap: var(--e-2); align-items: center; margin-left: auto; flex-wrap: wrap; }
.alm-cargando { padding: var(--e-6); color: var(--texto-mudo); font-size: var(--t-14); }

.alm-rejilla {
  display: grid; gap: var(--e-4); margin-top: var(--e-4);
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}

.alm-caja {
  background: var(--superficie); border: 1px solid var(--linea); border-radius: var(--radio);
  box-shadow: var(--sombra-1); padding: var(--e-4); display: flex; flex-direction: column; gap: var(--e-3);
}
.alm-caja-fuera { background: var(--superficie-2); }
.alm-caja-vacia { border-style: dashed; }
.alm-caja-cab { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--e-2); cursor: pointer; }
.alm-caja-nombre { font-family: var(--f-titulos); font-weight: 700; font-size: var(--t-18); letter-spacing: .02em; }
.alm-caja-donde { color: var(--texto-mudo); font-size: var(--t-13); }
.alm-caja-cifras { display: flex; gap: var(--e-4); border-top: 1px solid var(--linea-suave); border-bottom: 1px solid var(--linea-suave); padding: var(--e-2) 0; }
.alm-cifra { display: flex; flex-direction: column; }
.alm-cifra-num { font-family: var(--f-datos); font-weight: 700; font-size: var(--t-18); }
.alm-cifra-rot { color: var(--texto-mudo); font-size: var(--t-12); text-transform: uppercase; letter-spacing: .06em; }
.alm-caja-pie { color: var(--texto-mudo); font-size: var(--t-12); }

.alm-huecos { display: flex; flex-wrap: wrap; gap: var(--e-2); min-height: var(--e-6); }
.alm-hueco {
  border: 1px solid var(--linea-fuerte); background: var(--superficie-2); color: var(--texto);
  border-radius: var(--radio-sm); padding: var(--e-2) var(--e-3); cursor: pointer;
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 62px;
  font-family: var(--f-datos); transition: transform .12s ease, background .12s ease;
}
.alm-hueco:hover { transform: translateY(-1px); background: var(--laton-velo); }
.alm-hueco-zona { border-radius: 999px; }
.alm-hueco-lleno { background: var(--laton); border-color: var(--laton-oscuro); color: var(--laton-tinta); }
.alm-hueco-lleno:hover { background: var(--laton-claro); }
.alm-hueco-suelto { border-style: dashed; }
.alm-hueco-mas { align-items: center; justify-content: center; color: var(--laton-texto); border-style: dashed; min-width: 44px; }
.alm-hueco-cod { font-weight: 700; font-size: var(--t-13); letter-spacing: .04em; }
.alm-hueco-cant { font-size: var(--t-12); opacity: .8; }

.alm-reparto { display: flex; flex-wrap: wrap; gap: var(--e-2); margin-bottom: var(--e-3); }
.alm-reparto-chip { border: 1px solid var(--linea); border-radius: 999px; padding: 3px var(--e-3); font-size: var(--t-12); display: flex; gap: var(--e-2); }
.alm-reparto-donde { font-weight: 700; }
.alm-reparto-num { color: var(--texto-mudo); font-family: var(--f-datos); }

/* --- La ventana del movimiento ------------------------------------- */
.alm-pie { display: flex; gap: var(--e-2); justify-content: flex-end; width: 100%; }
.alm-pie .btn-peligro { margin-right: auto; }
.alm-mov { display: flex; flex-direction: column; gap: var(--e-4); }
.alm-mov-cab { display: flex; align-items: baseline; gap: var(--e-3); }
.alm-mov-codigo { font-weight: 700; font-size: var(--t-18); }
.alm-mov-que { color: var(--texto-mudo); font-size: var(--t-13); }

.alm-sitio { border: 1px solid var(--linea-suave); border-radius: var(--radio); padding: var(--e-3); background: var(--superficie-2); }
.alm-sitio-rotulo { font-size: var(--t-12); text-transform: uppercase; letter-spacing: .06em; color: var(--texto-mudo); margin-bottom: var(--e-2); }
.alm-sitio-almacenes, .alm-sitio-huecos { display: flex; flex-wrap: wrap; gap: var(--e-2); }
.alm-sitio-huecos { margin-top: var(--e-2); }
.alm-mov-sitios { display: grid; gap: var(--e-3); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

/* Los chips son grandes a propósito: esto se pulsa de pie y con guantes. */
.alm-chip {
  border: 1px solid var(--linea-fuerte); background: var(--superficie); color: var(--texto);
  border-radius: var(--radio-sm); padding: var(--e-2) var(--e-3); cursor: pointer;
  font-family: var(--f-ui); font-size: var(--t-14); min-height: 40px;
}
.alm-chip:hover:not(:disabled) { border-color: var(--laton-oscuro); }
.alm-chip-activo { background: var(--laton); border-color: var(--laton-oscuro); color: var(--laton-tinta); font-weight: 700; }
.alm-chip-hueco { font-family: var(--f-datos); min-height: 34px; padding: 4px var(--e-3); }
.alm-chip-espera { opacity: .45; }
.alm-chip:disabled { cursor: default; }

.alm-mov-lineas { border: 1px solid var(--linea); border-radius: var(--radio); overflow: hidden; }
.alm-mov-lineas-cab {
  display: flex; justify-content: space-between; align-items: center; gap: var(--e-2);
  padding: var(--e-2) var(--e-3); background: var(--superficie-2); border-bottom: 1px solid var(--linea-suave);
  font-size: var(--t-12); text-transform: uppercase; letter-spacing: .06em; color: var(--texto-mudo);
}
.alm-mov-lineas-botones { display: flex; gap: var(--e-2); }
.alm-vacio { padding: var(--e-5); text-align: center; color: var(--texto-mudo); font-size: var(--t-14); }
.alm-linea { display: flex; align-items: center; gap: var(--e-3); padding: var(--e-2) var(--e-3); border-bottom: 1px solid var(--linea-suave); }
.alm-linea:last-child { border-bottom: 0; }
.alm-linea-txt { flex: 1; min-width: 0; }
.alm-linea-sku { font-weight: 700; font-size: var(--t-13); }
.alm-linea-nombre { color: var(--texto-suave); font-size: var(--t-13); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.alm-linea-dato { display: flex; align-items: center; gap: var(--e-2); }
.alm-linea-serie, .alm-linea-cant { font-weight: 700; }
.alm-linea-cant { font-size: var(--t-18); }

/* --- Las dos fotos (D-110) ----------------------------------------- */
.alm-fotos-ayuda { font-size: var(--t-12); margin: 0 0 var(--e-2); }
.alm-fotos-rejilla { display: grid; gap: var(--e-3); grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.alm-foto-bloque { border: 1px dashed var(--linea-fuerte); border-radius: var(--radio); padding: var(--e-3); display: flex; flex-direction: column; gap: var(--e-2); }
.alm-foto-ok { border-style: solid; border-color: color-mix(in srgb, var(--ok) 45%, transparent); background: var(--ok-velo); }
.alm-foto-falta { border-color: color-mix(in srgb, var(--aviso) 55%, transparent); background: var(--aviso-velo); }
.alm-foto-rotulo { font-size: var(--t-13); font-weight: 700; }
.alm-foto-tiras { display: flex; flex-wrap: wrap; gap: var(--e-2); }
.alm-foto-chip { display: flex; align-items: center; gap: 4px; background: var(--superficie); border: 1px solid var(--linea); border-radius: 999px; padding: 2px 2px 2px var(--e-3); font-size: var(--t-12); }
.alm-foto-nombre { max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.alm-foto-btn { min-height: 46px; justify-content: center; cursor: pointer; }

/* --- Lo que falta, siempre a la vista ------------------------------ */
.alm-falta-caja { border-color: color-mix(in srgb, var(--aviso) 45%, transparent); background: var(--aviso-velo); color: var(--aviso); }
.alm-falta-titulo { font-weight: 700; margin-bottom: 4px; }
.alm-falta-lista { margin: 0; padding-left: var(--e-5); }
.alm-falta-lista li { margin: 2px 0; }
.alm-listo { font-weight: 700; }
.alm-ayuda-serie { font-size: var(--t-12); margin-top: var(--e-2); }

/* =====================================================================
   EL ESCÁNER · pensado para un iPad en la mano
   ---------------------------------------------------------------------
   Poco texto, todo grande, y el resultado en el sitio donde ya está
   mirando el ojo: justo debajo del visor.
   ===================================================================== */
.esc { display: flex; flex-direction: column; gap: var(--e-3); }
.esc-visor { position: relative; background: #000; border-radius: var(--radio); overflow: hidden; aspect-ratio: 4 / 3; max-height: 52vh; }
.esc-video { width: 100%; height: 100%; object-fit: cover; display: block; }
.esc-mira {
  position: absolute; inset: 18% 12%; border: 3px solid var(--laton);
  border-radius: var(--radio); box-shadow: 0 0 0 9999px rgba(0, 0, 0, .28); pointer-events: none;
}
.esc-estado {
  position: absolute; left: 0; right: 0; bottom: 0; padding: var(--e-2) var(--e-3);
  background: rgba(0, 0, 0, .55); color: #fff; font-size: var(--t-14); text-align: center;
}
.esc-estado-listo { color: var(--laton-claro); }
.esc-ayuda { font-size: var(--t-12); margin: 0; }

.esc-ok { border: 1px solid var(--laton-oscuro); background: var(--laton-velo); border-radius: var(--radio); padding: var(--e-3) var(--e-4); }
.esc-ok-sku { font-size: var(--t-28); font-weight: 700; letter-spacing: .02em; }
.esc-ok-nombre { font-size: var(--t-15); color: var(--texto-suave); }
.esc-ok-serie { font-size: var(--t-22); font-weight: 700; margin-top: var(--e-2); }
.esc-ok-donde { font-size: var(--t-13); color: var(--texto-mudo); margin-top: 2px; }
.esc-ok-fuera { color: var(--peligro); font-weight: 700; }

.esc-fallo { border: 1px solid color-mix(in srgb, var(--peligro) 45%, transparent); background: var(--peligro-velo); border-radius: var(--radio); padding: var(--e-3) var(--e-4); }
.esc-fallo-titulo { font-weight: 700; color: var(--peligro); font-size: var(--t-18); }
.esc-fallo-codigo { font-size: var(--t-15); margin: 4px 0; word-break: break-all; }
.esc-fallo-ayuda { font-size: var(--t-12); color: var(--texto-suave); }

.esc-manual-caja { display: flex; flex-direction: column; gap: var(--e-2); }
.esc-campo input { font-family: var(--f-datos); font-size: var(--t-22); text-transform: uppercase; }
.esc-hist { border-top: 1px solid var(--linea-suave); padding-top: var(--e-2); }
.esc-hist-rotulo { font-size: var(--t-12); text-transform: uppercase; letter-spacing: .06em; color: var(--texto-mudo); }
.esc-hist-lista { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.esc-hist-chip { border: 1px solid var(--linea); border-radius: 999px; padding: 1px var(--e-2); font-size: var(--t-12); }
.esc-pie { display: flex; justify-content: flex-end; width: 100%; }

/* =====================================================================
   LA VIDEOLLAMADA
   ===================================================================== */
.vid-timbre { display: flex; flex-direction: column; align-items: center; gap: var(--e-2); padding: var(--e-4) 0; }
.vid-timbre-quien { font-family: var(--f-titulos); font-weight: 700; font-size: var(--t-22); }
.vid-timbre-que { color: var(--texto-mudo); font-size: var(--t-14); }

.vid-persona { display: flex; align-items: center; gap: var(--e-3); }
.vid-persona-nombre { flex: 1; text-align: left; }
.vid-persona-rol { font-size: var(--t-12); }

.vid-ultimas { margin-top: var(--e-3); border-top: 1px solid var(--linea-suave); padding-top: var(--e-2); }
.vid-ultimas-rotulo { font-size: var(--t-12); text-transform: uppercase; letter-spacing: .06em; color: var(--texto-mudo); margin-bottom: 4px; }
.vid-ultima { display: flex; gap: var(--e-3); font-size: var(--t-13); padding: 2px 0; }
.vid-ultima-quien { font-weight: 700; min-width: 130px; }
.vid-ultima-que { flex: 1; color: var(--texto-suave); }
.vid-ultima-cuando { color: var(--texto-mudo); font-family: var(--f-datos); font-size: var(--t-12); }
.vid-ultima-perdida .vid-ultima-que { color: var(--peligro); }

.vid-sala { display: flex; flex-direction: column; gap: var(--e-3); }
.vid-escena { position: relative; background: #000; border-radius: var(--radio); overflow: hidden; aspect-ratio: 16 / 9; max-height: 56vh; }
.vid-remoto { position: absolute; inset: 0; }
.vid-video { width: 100%; height: 100%; object-fit: cover; display: block; }
.vid-yo {
  position: absolute; right: var(--e-3); bottom: var(--e-3); width: 26%; max-width: 190px;
  aspect-ratio: 4 / 3; border: 2px solid var(--laton); border-radius: var(--radio-sm); overflow: hidden; background: #111;
}
.vid-esperando { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #fff; text-align: center; padding: var(--e-4); font-size: var(--t-15); }
.vid-mandos { display: flex; gap: var(--e-2); justify-content: center; }
.vid-nota { font-size: var(--t-12); }
.vid-con { font-weight: 700; align-self: center; }

@media (max-width: 700px) {
  .alm-rejilla { grid-template-columns: 1fr; }
  .alm-linea { flex-wrap: wrap; }
  .esc-visor { aspect-ratio: 3 / 4; max-height: 60vh; }
}

/* =====================================================================
   LA PRESENCIA · v0.48.0
   ---------------------------------------------------------------------
   El anillo va POR FUERA del avatar y no como un punto dentro, y no es
   por gusto: `.avatar` lleva `overflow: hidden` para recortar la foto en
   redondo, así que cualquier punto colocado dentro se recortaría con
   ella. Un `box-shadow` de dos anillos —uno del color del fondo y otro
   del estado— se dibuja fuera de la caja, no la agranda, no mueve nada
   de su sitio y sirve igual en un avatar de 20 píxeles que en uno de 56.

   Y el color no es la información: cada lucecita lleva el estado escrito
   en su `title`, y donde se decide algo sale la palabra entera.
   ===================================================================== */

.pres-anillo { box-shadow: 0 0 0 2px var(--fondo), 0 0 0 4px var(--linea-fuerte); }
.pres-anillo-presente   { box-shadow: 0 0 0 2px var(--fondo), 0 0 0 4px var(--ok); }
.pres-anillo-ausente    { box-shadow: 0 0 0 2px var(--fondo), 0 0 0 4px var(--aviso); }
.pres-anillo-en_llamada { box-shadow: 0 0 0 2px var(--fondo), 0 0 0 4px var(--peligro); }
.pres-anillo-fuera      { box-shadow: 0 0 0 2px var(--fondo), 0 0 0 4px var(--linea-fuerte); }

/* El anillo sobresale: donde los avatares van pegados hay que dejarles
   sitio, o el de al lado se le come el borde. */
.tar-tira-personas .pres-anillo, .tar-avatar.pres-anillo, .tar-equipo-tira .pres-anillo { margin: 3px; }

.pres-punto { width: 9px; height: 9px; border-radius: 50%; flex: none; background: var(--linea-fuerte); }
.pres-punto-presente   { background: var(--ok); }
.pres-punto-ausente    { background: var(--aviso); }
.pres-punto-en_llamada { background: var(--peligro); }
.pres-punto-fuera      { background: var(--linea-fuerte); }

.pres-texto-presente   { color: var(--ok); }
.pres-texto-ausente    { color: var(--aviso); }
.pres-texto-en_llamada { color: var(--peligro); }
.pres-texto-fuera      { color: var(--texto-mudo); }

/* --- El contador, encima del teléfono ------------------------------- */
.pres-boton { position: relative; }
.pres-cuenta {
  position: absolute; top: -2px; right: -2px; min-width: 16px; height: 16px;
  border-radius: 999px; background: var(--linea-fuerte); color: var(--texto);
  font-family: var(--f-datos); font-size: 10px; font-weight: 700; line-height: 16px;
  text-align: center; padding: 0 3px; border: 1.5px solid var(--fondo);
}
.pres-cuenta-vivo { background: var(--ok); color: #fff; }
.pres-cuenta-mudo { background: var(--aviso); color: #fff; }

/* --- La lista del teléfono ------------------------------------------ */
.vid-persona-estado { font-size: var(--t-12); font-weight: 700; white-space: nowrap; }

/* --- Ajustes → Presencia -------------------------------------------- */
.pres-aviso { display: block; margin-bottom: var(--e-4); }
.pres-aviso-titulo { font-weight: 700; margin-bottom: 4px; }
.pres-aviso-lista { margin: 0; padding-left: var(--e-5); }
.pres-aviso-lista li { margin: 3px 0; }

.pres-ahora { margin-bottom: var(--e-3); }
.pres-ahora-caja { border: 1px solid var(--linea-suave); border-radius: var(--radio); padding: var(--e-3); background: var(--superficie-2); }
.pres-ahora-rotulo { font-size: var(--t-12); text-transform: uppercase; letter-spacing: .06em; color: var(--texto-mudo); margin-bottom: var(--e-2); }
.pres-ahora-tira { display: flex; flex-wrap: wrap; gap: var(--e-2); align-items: center; }
.pres-chip {
  display: inline-flex; align-items: center; gap: 6px; background: var(--superficie);
  border: 1px solid var(--linea); border-radius: 999px; padding: 3px var(--e-3); font-size: var(--t-13);
}
.pres-chip-quien { color: var(--texto); font-weight: 500; }
.pres-chip-que { font-size: var(--t-12); }

.pres-cargando { padding: var(--e-5); color: var(--texto-mudo); font-size: var(--t-14); }
.pres-fila { cursor: pointer; }
.pres-supuesto {
  margin-left: 6px; font-size: 10px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--aviso); border: 1px solid color-mix(in srgb, var(--aviso) 45%, transparent);
  border-radius: 999px; padding: 0 5px; white-space: nowrap;
}
.pres-abierta {
  margin-left: 6px; font-size: 10px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ok); border: 1px solid color-mix(in srgb, var(--ok) 45%, transparent);
  border-radius: 999px; padding: 0 5px; white-space: nowrap;
}

/* =====================================================================
   M-93 · MENSAJES · v0.49.0
   ---------------------------------------------------------------------
   Dos columnas: la bandeja a la izquierda, el hilo a la derecha. Y el
   hilo es una columna de tres piezas —cabecera, mensajes, escribir— con
   el scroll SOLO en la de en medio: si el scroll fuera de toda la
   página, escribir un mensaje largo empujaría el campo fuera de la
   pantalla, que es el defecto clásico de un chat mal montado.
   ===================================================================== */

/* LOS DOS BOTONES, UNO POR FILA DE CARAS (v0.63.0).
   Javier lo pidió así: «Canales» a la altura de la primera fila de
   avatares y «Nuevo grupo» a la de la segunda.

   Se alinean POR CONSTRUCCIÓN y no a ojo: esta columna y la tira de
   caras usan las mismas dos filas, `--msj-fila`, y las dos arrancan en
   el borde de arriba de la cabecera. Cuadrar dos alturas a mano funciona
   hasta el día que cambie la tipografía, y ese día no da ningún error:
   simplemente los botones dejan de estar donde estaban. */
.msj-mandos {
  display: grid;
  grid-template-rows: var(--msj-fila) var(--msj-fila);
  gap: 2px 0; align-items: center; justify-items: stretch;
  flex: none; margin-left: var(--e-3);
}
/* Los dos, del mismo ancho —el del más largo—, que es lo que hace que se
   lean como una columna y no como dos botones sueltos que coinciden. */
.msj-mandos .btn { width: 100%; justify-content: center; }

/* La sección de Mensajes reparte el alto que le dan: lo que sobra va al
   tablero, y el título, la barra y la tira se quedan quietos (v0.54.0). */
.msj-seccion { display: flex; flex-direction: column; min-height: 0; }
.msj-seccion .modulo-cabecera,
.msj-seccion .crm-barra,
.msj-seccion .msj-tira { flex: none; }
/* LAS PESTAÑAS SUBEN (v0.63.0). `.pestanas` trae 16 px de margen por
   arriba, que es lo que necesita cuando va sola debajo de un título. Aquí
   va DENTRO de la barra de filtros, alineada con el buscador, y ese
   margen no separaba de nada: era un renglón en blanco dentro de la
   propia barra. Y la barra se pega más al tablero, que es quien se queda
   con lo que sobra.
   Es el mismo hallazgo que en Tareas (v0.55.5), y por eso está escrito
   dos veces: un margen puesto para un sitio viaja con la clase al
   siguiente. */
.msj-seccion .crm-barra > .pestanas { margin-top: 0; }
.msj-seccion .crm-barra { margin-bottom: 0; }
/* Y la tira, si algún día no cabe, se encoge ELLA en vez de comerse las
   listas. Es una válvula: con doce personas no salta nunca.
   Desde la v0.62.0 esto es solo para la tira SUELTA: la que vive en la
   cabecera tiene su propio tope, más abajo, y midiendo dos filas
   exactas. Si esta regla la alcanzara también, ganaría por ir antes en
   el fichero y la de arriba mediría 22vh en vez de dos filas. */
.msj-seccion .msj-tira:not(.msj-tira-arriba) { max-height: 22vh; overflow-y: auto; }

.msj-tablero {
  display: grid; grid-template-columns: minmax(280px, 360px) 1fr; gap: var(--e-3);
  /* Ocho píxeles y no doce (v0.63.0): todo lo que se le quita al hueco
     se lo queda el tablero, que es lo que pidió Javier. */
  margin-top: var(--e-2);
  /* NADA DE `calc(100vh - 260px)`, que era un número adivinado y dejó de
     salir el día que la tira de caras pasó a dos filas: el tablero se iba
     por debajo del borde y el que hacía scroll era el documento, que se
     llevaba fuera el título y la tira. Ahora coge lo que le den. */
  flex: 1; min-height: 0;
}

/* --- La bandeja ------------------------------------------------------ */
.msj-lista {
  border: 1px solid var(--linea); border-radius: var(--radio); background: var(--superficie);
  overflow-y: auto; display: flex; flex-direction: column; min-height: 0;
}
.msj-lista-cab {
  display: flex; align-items: center; justify-content: space-between; gap: var(--e-2);
  padding: var(--e-2) var(--e-3); border-bottom: 1px solid var(--linea-suave);
  background: var(--superficie-2); font-size: var(--t-12); color: var(--texto-suave);
  position: sticky; top: 0; z-index: 1;
}
.msj-vacio { padding: var(--e-6) var(--e-4); color: var(--texto-mudo); font-size: var(--t-14); text-align: center; }
.msj-item {
  display: flex; gap: var(--e-2); align-items: flex-start; text-align: left;
  padding: var(--e-3); border: 0; border-bottom: 1px solid var(--linea-suave);
  background: transparent; cursor: pointer; width: 100%; font-family: var(--f-ui);
}
.msj-item:hover { background: var(--superficie-2); }
.msj-item-abierto { background: var(--laton-velo); }
.msj-item-sin-leer .msj-item-nombre { font-weight: 700; }
.msj-item-icono {
  width: 26px; height: 26px; flex: none; border-radius: var(--radio-sm);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--superficie-2); color: var(--laton-texto); font-weight: 700; font-size: var(--t-13);
}
.msj-item-icono svg { width: 15px; height: 15px; }
.msj-item-textos { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.msj-item-arriba { display: flex; justify-content: space-between; gap: var(--e-2); align-items: baseline; }
.msj-item-nombre { font-size: var(--t-14); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msj-item-cuando { font-size: 10px; color: var(--texto-mudo); font-family: var(--f-datos); flex: none; }
.msj-item-adelanto { font-size: var(--t-12); color: var(--texto-suave); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msj-item-pie { font-size: 10px; color: var(--texto-mudo); text-transform: uppercase; letter-spacing: .05em; }
.msj-item-marcas { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; flex: none; }
/* QUITAR LA CONVERSACIÓN DE MI LISTA (v0.70.0, D-133).
   Se enseña al pasar el ratón por la línea y NO antes: una aspa fija en
   veinte líneas es una lista llena de aspas, y la primera que se pulsa
   sin querer es la conversación que sí importaba. Con el teclado sí está
   siempre disponible —al recibir el foco se ve—, porque quien navega con
   Tab no tiene «pasar el ratón por encima». */
.msj-item-quitar {
  width: 18px; height: 18px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--texto-mudo); font-size: 13px; line-height: 1; cursor: pointer;
  opacity: 0; transition: opacity .12s ease;
}
.msj-item:hover .msj-item-quitar,
.msj-item-quitar:focus-visible { opacity: 1; }
.msj-item-quitar:hover { background: var(--peligro-velo); color: var(--peligro); }
.msj-cuenta {
  min-width: 18px; height: 18px; border-radius: 999px; background: var(--laton);
  color: var(--laton-tinta); font-size: 10px; font-weight: 700; line-height: 18px;
  text-align: center; padding: 0 5px; font-family: var(--f-datos);
}
/* En soporte no es un «sin leer»: se distingue a la vista y se explica al
   pasar el ratón. */
.msj-cuenta-estimada { background: transparent; color: var(--aviso); border: 1px solid var(--aviso); line-height: 16px; }
.msj-mencion-marca {
  width: 18px; height: 18px; border-radius: 999px; background: var(--peligro); color: #fff;
  font-size: 11px; font-weight: 700; line-height: 18px; text-align: center;
}

/* --- El hilo -------------------------------------------------------- */
.msj-hilo { border: 1px solid var(--linea); border-radius: var(--radio); background: var(--superficie); overflow: hidden; min-height: 0; }
.msj-hilo-vacio { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--texto-mudo); font-size: var(--t-14); }
.msj-hilo-marco { display: grid; grid-template-rows: auto 1fr auto; height: 100%; }
.msj-cargando { padding: var(--e-5); color: var(--texto-mudo); }

.msj-cab {
  display: flex; align-items: center; justify-content: space-between; gap: var(--e-3);
  padding: var(--e-3); border-bottom: 1px solid var(--linea); background: var(--superficie-2);
}
.msj-cab-nombre { font-family: var(--f-titulos); font-weight: 700; font-size: var(--t-18); }
.msj-cab-sub { font-size: var(--t-12); color: var(--texto-mudo); }
.msj-cab-mandos { display: flex; gap: var(--e-2); align-items: center; }

/* LA CONVERSACIÓN, SOBRE PAPEL (v0.64.0). Las burbujas blancas necesitan
   un fondo del que despegarse; sobre blanco no serían burbujas, serían
   párrafos con sombra. */
.msj-hilo-cuerpo {
  overflow-y: auto; padding: var(--e-3) var(--e-4);
  display: flex; flex-direction: column; gap: 2px;
  background: var(--superficie-2);
}
.msj-dia { display: flex; align-items: center; justify-content: center; margin: var(--e-3) 0 var(--e-2); }
.msj-dia span {
  font-size: 10px; text-transform: uppercase; letter-spacing: .08em; color: var(--texto-mudo);
  background: var(--superficie-2); border: 1px solid var(--linea-suave); border-radius: 999px; padding: 2px var(--e-3);
}

/* =====================================================================
   LAS BURBUJAS · v0.64.0
   ---------------------------------------------------------------------
   Lo pidió Javier: «los mensajes que escribe quien tiene la cuenta
   abierta salen a la derecha de la ventana, como en WhatsApp; clona el
   aspecto de una conversación de grupo de WhatsApp».

   Lo tuyo a la derecha y lo de los demás a la izquierda no es decoración:
   es lo que permite seguir un hilo **sin leer quién escribe cada línea**,
   que es la mitad del trabajo de leer un chat de dieciséis personas.
   ===================================================================== */
/* La cara se alinea ARRIBA, con el nombre y con el pico de la burbuja, y
   no abajo: abajo se queda a media altura entre dos mensajes seguidos y
   parece de ninguno de los dos. */
.msj-msg { display: flex; gap: var(--e-2); padding: 2px 0; align-items: flex-start; }
.msj-msg-mio { flex-direction: row-reverse; }
/* Mensajes seguidos de la misma persona: más juntos, como en WhatsApp. */
.msj-msg-pegado { padding-top: 0; }

/* LA CARA: solo en un grupo y solo de otro. La tuya no hace falta —sabes
   quién eres— y en una conversación de dos tampoco: el lado ya lo dice.
   Y en los mensajes seguidos SE RESERVA EL HUECO aunque no se pinte, o la
   segunda burbuja se iría a la izquierda de la primera y la columna se
   rompería. Ese hueco es lo que antes no se reservaba. */
.msj-msg-cara { flex: none; width: 0; }
.msj-msg-con-cara > .msj-msg-cara { width: 28px; }
.msj-msg-con-cara.msj-msg-pegado > .msj-msg-cara { visibility: hidden; }

/* LA BURBUJA. Se ajusta al texto y no pasa de tres cuartos del ancho: una
   burbuja que llega de borde a borde deja de decir de quién es. */
.msj-msg-caja {
  position: relative; min-width: 0; flex: 0 1 auto;
  max-width: min(74%, 640px);
  /* Un suelo, para que la hora no estruje un «Ok» hasta dejarlo en
     columna de una letra. */
  min-width: 96px;
  padding: 5px var(--e-2) 4px;
  border-radius: var(--radio);
  background: var(--burbuja); box-shadow: var(--burbuja-sombra);
}
.msj-msg-mio .msj-msg-caja { background: var(--burbuja-mia); }
/* La esquina del pico va cuadrada, como en WhatsApp. Y solo en el primero
   de una tanda: los seguidos van redondeados por los cuatro lados. */
.msj-msg:not(.msj-msg-mio):not(.msj-msg-pegado) .msj-msg-caja { border-top-left-radius: 3px; }
.msj-msg-mio:not(.msj-msg-pegado) .msj-msg-caja { border-top-right-radius: 3px; }
/* EL PICO. Un triángulo hecho con bordes: dos lados del mismo color que
   la burbuja y el resto transparente. Se dibuja con un pseudo-elemento
   para que no haya un nodo más por mensaje —en un canal con mil, eso se
   nota— y no lleva sombra a propósito: la sombra de un triángulo de ocho
   píxeles se ve como una mancha. */
.msj-msg:not(.msj-msg-pegado) .msj-msg-caja::after {
  content: ""; position: absolute; top: 0; width: 0; height: 0;
  border-top: 8px solid var(--burbuja);
}
.msj-msg:not(.msj-msg-mio):not(.msj-msg-pegado) .msj-msg-caja::after {
  left: -7px; border-right: 8px solid transparent;
}
.msj-msg-mio:not(.msj-msg-pegado) .msj-msg-caja::after {
  right: -7px; border-left: 8px solid transparent; border-top-color: var(--burbuja-mia);
}

/* EL NOMBRE DE QUIEN ESCRIBE, con SU color y siempre el mismo. En un
   canal de dieciséis personas el color se reconoce antes que el nombre.
   Los ocho tonos viven en `tokens.css` y los reparte `colorDeQuien()`. */
.msj-msg-cab:empty { display: none; }
.msj-msg-quien { display: block; font-weight: 700; font-size: var(--t-12); margin-bottom: 1px; }
.msj-quien-1 { color: var(--quien-1); }
.msj-quien-2 { color: var(--quien-2); }
.msj-quien-3 { color: var(--quien-3); }
.msj-quien-4 { color: var(--quien-4); }
.msj-quien-5 { color: var(--quien-5); }
.msj-quien-6 { color: var(--quien-6); }
.msj-quien-7 { color: var(--quien-7); }
.msj-quien-8 { color: var(--quien-8); }

/* EL TEXTO Y LA HORA, EN EL MISMO PÁRRAFO, y ese es el truco de WhatsApp:
   si la hora cabe al final de la última línea, se pone ahí; si no, baja
   sola. Un «Ok» con la hora debajo gasta dos renglones para tres letras, y
   la mayoría de los mensajes de un chat son «Ok».

   `flow-root` es lo que hace que la hora flotada quede DENTRO de la
   burbuja: sin él, un elemento flotante no cuenta para el alto de su caja
   y se saldría por abajo. */
.msj-msg-texto { display: flow-root; }
.msj-msg-cuerpo {
  display: inline; font-size: var(--t-14); line-height: 1.4;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.msj-msg-oculto .msj-msg-cuerpo { color: var(--texto-mudo); font-style: italic; }
.msj-oculto-nota { color: var(--texto-mudo); }

/* LA HORA, DENTRO DE LA BURBUJA Y ABAJO A LA DERECHA. */
.msj-msg-pie {
  float: right; display: inline-flex; align-items: baseline;
  gap: var(--e-1); margin: 3px 0 0 var(--e-3);
}
.msj-msg-hora { font-size: 10px; color: var(--texto-mudo); font-family: var(--f-datos); flex: none; white-space: nowrap; }
.msj-editado { font-size: 10px; color: var(--texto-mudo); font-style: italic; }

/* RESPONDER Y EDITAR, FUERA DE LA BURBUJA Y SOLO AL PASAR EL RATÓN.
   Antes vivían dentro y con `opacity: 0`, así que **ocupaban su renglón
   siempre**: dieciocho píxeles en blanco al final de cada mensaje, en
   todos los mensajes de la conversación. Dentro de una burbuja eso se ve.
   Ahora van en una chapa flotante encima de la burbuja, que es donde las
   pone WhatsApp, y no ocupan nada mientras no hagan falta. */
.msj-msg-acciones {
  position: absolute; top: -13px; z-index: 2;
  display: flex; gap: var(--e-2); align-items: center;
  padding: 1px var(--e-2);
  border: 1px solid var(--linea); border-radius: 999px;
  background: var(--superficie-3); box-shadow: var(--sombra-1);
  opacity: 0; pointer-events: none; transition: opacity .12s ease;
}
.msj-msg:not(.msj-msg-mio) .msj-msg-acciones { right: var(--e-1); }
.msj-msg-mio .msj-msg-acciones { left: var(--e-1); }
.msj-msg:hover .msj-msg-acciones, .msj-msg:focus-within .msj-msg-acciones { opacity: 1; pointer-events: auto; }
.msj-msg-acciones:empty { display: none; }
.msj-msg-acciones .btn-enlace { font-size: var(--t-12); }

.msj-mencion { background: var(--laton-velo); color: var(--laton-texto); border-radius: var(--radio-sm); padding: 0 3px; font-weight: 500; }
.msj-mencion-yo { background: var(--laton); color: var(--laton-tinta); font-weight: 700; }
.msj-codigo {
  border: 1px solid var(--linea-fuerte); background: var(--superficie-2); color: var(--laton-texto);
  border-radius: var(--radio-sm); padding: 0 4px; font-family: var(--f-datos); font-size: var(--t-13);
  cursor: pointer; font-weight: 700;
}
.msj-codigo:hover { border-color: var(--laton-oscuro); background: var(--laton-velo); }
.msj-enlace { color: var(--laton-texto); text-decoration: underline; overflow-wrap: anywhere; }

/* A LO QUE RESPONDE, dentro de la burbuja y con su propio fondo, como en
   WhatsApp. `--info-velo` y no `--superficie-2`: dentro de la burbuja
   propia, que ya es crema, el papel no se distinguiría del fondo. */
.msj-msg-responde {
  border-left: 3px solid var(--laton); padding: 3px var(--e-2); margin-bottom: 3px;
  background: var(--info-velo); border-radius: 0 var(--radio-sm) var(--radio-sm) 0;
  font-size: var(--t-12); display: block;
}
.msj-msg-responde .msj-responde-quien { display: block; }
.msj-responde-rotulo { color: var(--texto-mudo); margin-right: 4px; }
.msj-responde-quien { font-weight: 700; margin-right: var(--e-2); }
.msj-responde-texto { color: var(--texto-suave); }

.msj-msg-adjuntos { display: flex; flex-wrap: wrap; gap: var(--e-2); margin-top: 4px; }
.msj-msg-mio .msj-msg-adjuntos { justify-content: flex-end; }
/* Dentro de una burbuja, el adjunto se pega a sus bordes y no lleva marco
   propio: dos marcos concéntricos separados por cuatro píxeles es lo que
   hace que una pantalla parezca una maqueta. */
.msj-msg-caja .msj-adjunto { border-color: var(--linea-suave); background: transparent; }
.msj-adjunto {
  border: 1px solid var(--linea); border-radius: var(--radio-sm); padding: 4px;
  display: flex; flex-direction: column; gap: 3px; max-width: 260px; background: var(--superficie-2);
}
.msj-adjunto-imagen img { max-width: 240px; max-height: 200px; border-radius: var(--radio-sm); display: block; }
.msj-adjunto-nombre {
  border: 0; background: transparent; color: var(--laton-texto); cursor: pointer;
  font-size: var(--t-12); text-align: left; text-decoration: underline; padding: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 240px;
}

/* --- Escribir ------------------------------------------------------- */
.msj-hilo-pie { border-top: 1px solid var(--linea); padding: var(--e-2) var(--e-3) var(--e-3); background: var(--superficie-2); }
.msj-solo-lectura { color: var(--texto-mudo); font-size: var(--t-13); padding: var(--e-2) 0; }
.msj-escribir { position: relative; display: flex; flex-direction: column; gap: var(--e-2); }
.msj-respondiendo {
  display: flex; align-items: center; gap: var(--e-2); font-size: var(--t-12);
  border-left: 3px solid var(--laton); padding: 2px var(--e-2); background: var(--superficie);
}
.msj-adjuntos-puestos { display: flex; flex-wrap: wrap; gap: var(--e-2); }
.msj-adjunto-chip {
  display: inline-flex; align-items: center; gap: 4px; background: var(--superficie);
  border: 1px solid var(--linea); border-radius: 999px; padding: 2px 2px 2px var(--e-3); font-size: var(--t-12);
}
.msj-adjunto-chip > span { max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msj-escribir-fila { display: flex; gap: var(--e-2); align-items: flex-end; }
.msj-texto {
  flex: 1; resize: none; font-family: var(--f-ui); font-size: var(--t-14); line-height: 1.4;
  border: 1px solid var(--linea-fuerte); border-radius: var(--radio); padding: var(--e-2) var(--e-3);
  background: var(--fondo); color: var(--texto); min-height: 40px; max-height: 160px;
}
.msj-texto:focus { outline: none; border-color: var(--laton-oscuro); }
.msj-clip { cursor: pointer; }
.msj-sugerencias {
  position: absolute; bottom: calc(100% + 4px); left: 0; z-index: 5;
  background: var(--superficie); border: 1px solid var(--linea-fuerte); border-radius: var(--radio);
  box-shadow: var(--sombra-2); overflow: hidden; min-width: 200px; max-height: 220px; overflow-y: auto;
}
.msj-sug { display: block; width: 100%; text-align: left; border: 0; background: transparent; cursor: pointer; padding: 6px var(--e-3); font-size: var(--t-13); }
.msj-sug-elegida, .msj-sug:hover { background: var(--laton-velo); }

/* --- Grupos y canales ----------------------------------------------- */
.msj-elige-gente { display: flex; flex-wrap: wrap; gap: var(--e-2); max-height: 220px; overflow-y: auto; }
.msj-chip-persona {
  border: 1px solid var(--linea-fuerte); background: var(--superficie); border-radius: 999px;
  padding: 3px var(--e-3); cursor: pointer; font-size: var(--t-13); font-family: var(--f-ui); color: var(--texto);
}
.msj-chip-elegido { background: var(--laton); border-color: var(--laton-oscuro); color: var(--laton-tinta); font-weight: 700; }
.msj-canal { display: flex; align-items: center; justify-content: space-between; gap: var(--e-3); padding: var(--e-2) 0; border-bottom: 1px solid var(--linea-suave); }
.msj-canal-nombre { font-weight: 700; font-size: var(--t-14); }
.msj-canal-desc { font-size: var(--t-12); color: var(--texto-mudo); }

/* --- El contador del menú ------------------------------------------- */
.nav-cuenta {
  margin-left: auto; min-width: 18px; height: 18px; border-radius: 999px;
  background: var(--laton); color: var(--laton-tinta); font-family: var(--f-datos);
  font-size: 10px; font-weight: 700; line-height: 18px; text-align: center; padding: 0 5px; flex: none;
}
.nav-cuenta-mencion { background: var(--peligro); color: #fff; }

@media (max-width: 900px) {
  /* EN EL MÓVIL SE VUELVE AL SCROLL DE LA PÁGINA, y es a propósito: dos
     columnas apiladas, cada una con su propio scroll, dentro de una
     pantalla de mano, son tres barras de scroll compitiendo por el mismo
     dedo. Aquí manda la página y las dos listas se estiran. */
  .vista.vista-a-medida { height: auto; overflow: visible; }
  .msj-tablero { grid-template-columns: 1fr; height: auto; flex: none; }
  .msj-lista { max-height: 45vh; }
  .msj-hilo { min-height: 60vh; }
  .msj-seccion .msj-tira { max-height: none; overflow-y: visible; }
  /* Lo de la tira mudada a la cabecera NO está aquí, y no es un
     descuido: va al final de su propio bloque, más abajo. Puesto aquí
     perdería, porque las reglas de escritorio se escriben después y con
     la misma especificidad gana la última. */
}

/* =====================================================================
   EL MENÚ CUANDO HAY ALGO SIN LEER · v0.50.0
   ---------------------------------------------------------------------
   Lo pidió Javier así: un marco que se queda puesto mientras quede algo
   sin leer. El ámbar es el color de «esto te está esperando» en todo
   WERP (los avisos, las fotos que faltan, el material sin colocar), así
   que aquí significa lo mismo y no hay que aprender nada nuevo.

   Y el marco NO parpadea. Un marco que parpadea se ignora en dos días y
   además marea a quien haya pedido menos movimiento en su sistema.
   ===================================================================== */
.nav-item-sin-leer {
  border: 2px solid var(--aviso);
  background: var(--aviso-velo);
  border-radius: var(--radio-sm);
}
.nav-item-sin-leer span { font-weight: 700; }
/* Una mención es algo que te han dicho A TI: el marco se pone rojo. */
.nav-item-mencion { border-color: var(--peligro); background: var(--peligro-velo); }

/* =====================================================================
   M-93 · LA TIRA DE PERSONAL Y LA VENTANA DE LO QUE LLEGA · v0.50.0
   ---------------------------------------------------------------------
   La tira reutiliza las clases de Tareas (`tar-empleado`, su cara y sus
   dos líneas de nombre) a propósito: es la misma cosa y tiene que verse
   igual. Aquí solo se pone lo que cambia.
   ===================================================================== */

.msj-tira {
  display: flex; align-items: flex-start; gap: 3px; flex-wrap: wrap;
  margin-top: var(--e-3); padding: var(--e-2) var(--e-3);
  border: 1px solid var(--linea-suave); border-radius: var(--radio); background: var(--superficie-2);
}
.msj-tira-rotulo {
  font-size: var(--t-12); text-transform: uppercase; letter-spacing: .06em;
  color: var(--texto-mudo); align-self: center; margin-right: var(--e-2);
}
.msj-persona { padding-top: 6px; }
.msj-persona.arrastrando { opacity: .45; }

/* --- LAS CARAS, ARRIBA Y EN DOS FILAS · v0.62.0 ----------------------
   Lo pidió Javier: «los avatares ocupan una fila entera; ponlos en dos
   filas a la derecha de Mensajes, que hay un espacio vacío».

   LA CUENTA DE LO QUE SE GANA, medida con un navegador de verdad a
   1.200 px de ancho y con las once personas de la casa, no calculada a
   ojo: la franja de antes ocupaba 110 px —98 de alto más 12 de margen—.
   Arriba, la cabecera pasa de 77 px a 114, o sea 37 más, porque las dos
   filas de caras son más altas que el título. 110 que se van y 37 que
   vienen: **73 px netos para las conversaciones**, que es un mensaje y
   medio de los largos.

   Y el ahorro sale de que la ficha va sin el hueco de 22 px que Tareas
   guarda encima de la cara para sus tres números, que aquí no existen.

   Y el título se centra contra las caras en vez de alinearse por abajo,
   que es lo que hace la cabecera de módulo: contra una caja de dos filas,
   alinear por abajo deja todo el blanco encima del título. */
/* EL ALTO DE UNA FILA DE CARAS, EN UN SOLO SITIO (v0.63.0). Lo usan la
   tira y la columna de los dos botones, y por eso están alineados. Si
   algún día hay que tocarlo, se toca aquí y las dos cosas se mueven
   juntas.

   46 px desde la v0.63.1, y antes eran 56. Javier señaló en una captura
   la banda en blanco que quedaba entre el subtítulo y las pestañas y
   pidió **la mitad**: eran 45 px y ahora son 21. Ese hueco no es un
   margen que se pueda quitar —es lo que le sobra a la cabecera por
   debajo del título, y la cabecera mide lo que miden las dos filas de
   caras—, así que la única manera de bajarlo es que las filas midan
   menos. De ahí que la cara pase de 30 a 26 px y el nombre de 11 a 10:
   una ficha entera cabe hoy en 43, con tres de sobra. */
.msj-seccion { --msj-fila: 46px; }

/* EL TÍTULO, ARRIBA DEL TODO (v0.63.0). Lo pidió Javier: «sube la
   cabecera M-93 más arriba, que hay espacio vacío». Estaba centrado
   contra las dos filas de caras, así que le sobraban diecinueve píxeles
   por encima y otros diecinueve por debajo sin nada dentro. Ahora los
   tres bloques —título, caras y botones— empiezan en la misma línea. */
.msj-cabecera { align-items: flex-start; margin-bottom: var(--e-1); }
.msj-cab-titulo { flex: 0 1 auto; min-width: 0; }
.msj-cab-equipo { flex: 1 1 340px; min-width: 0; max-width: 100%; }

/* DOS FILAS DE VERDAD, Y POR ESO ES UNA REJILLA Y NO UNA FILA QUE
   ENVUELVE. Con `flex-wrap` el número de filas lo decide el ancho de la
   ventana: en un monitor grande las once caras de WADAX caben en una y
   quedaría una sola fila muy larga —que es justo lo que Javier pidió
   cambiar—, y en un portátil saldrían dos. La misma pantalla se vería
   distinta en cada mesa.

   `grid-auto-flow: column` sobre dos filas fijas llena de arriba abajo y
   luego a la derecha, así que siempre son dos, con once personas y con
   veinte. La primera columna es del rótulo y se mide por su contenido;
   las demás valen 62 px, que es lo que ocupa una cara con su nombre. */
.msj-tira.msj-tira-arriba {
  display: grid;
  grid-auto-flow: column;
  /* Las dos filas, medidas y no adivinadas: son las mismas que usa la
     columna de los dos botones (v0.63.0). */
  grid-template-rows: var(--msj-fila) var(--msj-fila);
  grid-template-columns: max-content;
  grid-auto-columns: 62px;
  /* Pegadas a la derecha, como en Tareas, y con el hueco entre el título
     y ellas. Aquí `justify-content: end` no tiene el problema que tenía
     allí —que en una caja que rueda a lo ancho empuja el principio fuera
     por la izquierda, donde el scroll no llega— porque el ancho que
     ocupan estas dos filas es menos de la mitad del hueco: no rueda
     nunca. Y si algún día WADAX fuera mucha más gente, rodaría, así que
     queda dicho por qué se acepta. */
  justify-content: end; align-content: start;
  gap: 2px 0; margin: 0; padding: 0;
  border: 0; border-radius: 0; background: none;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: thin;
}
/* El rótulo ocupa la primera columna entera, las dos filas, y va
   centrado contra ellas: si se dejara en una celda normal, empujaría una
   cara a la fila de abajo y las columnas dejarían de cuadrar. */
.msj-tira.msj-tira-arriba .msj-tira-rotulo {
  grid-row: 1 / -1; align-self: center; margin: 0 var(--e-2) 0 0;
}
/* La ficha compacta: sin el hueco de 22 px que Tareas guarda encima de
   la cara para sus tres números, que aquí no existen. Y desde la v0.63.1
   un punto más apretada, para que quepa en los 46 px de fila.
   El anillo de presencia también se estrecha: son 3 px por arriba y 3
   por abajo que en una fila de 46 sí se notan. */
.msj-tira.msj-tira-arriba .msj-persona { width: auto; padding: 1px 1px; gap: 0; }
.msj-tira.msj-tira-arriba .avatar { width: 26px; height: 26px; font-size: 10px; }
.msj-tira.msj-tira-arriba .pres-anillo { margin: 2px; }
.msj-tira.msj-tira-arriba .tar-empleado-nombre { font: 600 10px/1.1 var(--f-ui); max-width: 60px; }
/* Y arriba no va el apellido: el nombre de pila basta para reconocer a
   alguien de la casa, y el nombre completo sigue saliendo al pasar el
   ratón. */
.msj-tira.msj-tira-arriba .tar-empleado-apellido { display: none; }

/* EN UNA PANTALLA DE MANO MANDA EL ANCHO. Dos filas fijas obligarían a
   rodar a lo ancho para ver a media casa, y con el dedo eso es un
   destino móvil dentro de una página que también se mueve.
   La cabecera de módulo ya envuelve sola, así que las caras caen debajo
   del título y se reparten.

   VA AQUÍ, AL FINAL, Y NO EN EL BLOQUE DE MÓVIL DE MÁS ARRIBA. Las
   reglas de arriba tienen la misma especificidad que estas y se
   escribieron después, así que allí este `@media` no ganaría — y no
   daría ningún error: simplemente el móvil se vería como el escritorio.
   Es la clase de fallo que solo se ve estrechando la ventana. */
@media (max-width: 900px) {
  .msj-cab-equipo { flex-basis: 100%; }
  /* Y los dos botones vuelven a ser dos botones en fila: una columna de
     dos alineada con unas filas que en el móvil ya no son dos no alinea
     con nada, y ocupa el doble de alto. */
  .msj-mandos {
    display: flex; align-items: center; gap: var(--e-2);
    flex-wrap: wrap; margin: var(--e-2) 0 0; width: 100%;
  }
  .msj-mandos .btn { width: auto; }
  .msj-tira.msj-tira-arriba {
    display: flex; flex-wrap: wrap; justify-content: flex-start;
    align-content: flex-start; overflow-x: visible;
    margin-top: var(--e-2); gap: 0;
  }
  .msj-tira.msj-tira-arriba .msj-tira-rotulo { align-self: center; }
  .msj-tira.msj-tira-arriba .msj-persona { width: 62px; flex: none; }
}

/* MIENTRAS SE LLEVA A ALGUIEN, SE VE DÓNDE SE PUEDE SOLTAR. Sin esto hay
   que descubrir los destinos con el ratón apretado, que es la parte que
   hace que un arrastre parezca que no funciona. */
.msj-llevando-persona .msj-item { outline: 1px dashed var(--linea-fuerte); outline-offset: -3px; }
.msj-llevando-persona .msj-soltar-grupo { border-color: var(--laton-oscuro); color: var(--laton-texto); }
.msj-item-no-cabe { outline: 2px dashed var(--peligro) !important; background: var(--peligro-velo); }

.msj-soltar-grupo {
  display: flex; align-items: center; justify-content: center; text-align: center;
  margin: var(--e-2); padding: var(--e-3); border: 2px dashed var(--linea-fuerte);
  border-radius: var(--radio); color: var(--texto-mudo); font-size: var(--t-12);
}
.msj-soltar-grupo.sobre-destino { border-color: var(--laton-oscuro); background: var(--laton-velo); color: var(--laton-texto); }

.msj-escribir-a { display: flex; flex-direction: column; gap: var(--e-2); }
.msj-escribir-a-quien { display: flex; align-items: center; gap: var(--e-3); font-weight: 700; font-size: var(--t-15); }

/* --- La ventana de lo que llega ------------------------------------- */
.msj-pop { display: flex; flex-direction: column; gap: var(--e-2); }
.msj-pop-lista { display: flex; flex-direction: column; gap: var(--e-2); max-height: 46vh; overflow-y: auto; }
.msj-pop-uno {
  border: 1px solid var(--linea); border-left: 3px solid var(--laton);
  border-radius: 0 var(--radio-sm) var(--radio-sm) 0; padding: var(--e-2) var(--e-3); background: var(--superficie-2);
}
.msj-pop-cab { display: flex; gap: var(--e-2); align-items: baseline; flex-wrap: wrap; margin-bottom: 2px; }
.msj-pop-quien { font-weight: 700; font-size: var(--t-14); }
.msj-pop-donde { font-size: var(--t-12); color: var(--texto-suave); }
.msj-pop-cuando { font-size: 10px; color: var(--texto-mudo); font-family: var(--f-datos); margin-left: auto; }
.msj-pop-cuerpo { font-size: var(--t-14); line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere; }
.msj-pop-pie { display: flex; gap: var(--e-2); justify-content: flex-end; width: 100%; }

/* =====================================================================
   EL MEGÁFONO · v0.52.0
   ---------------------------------------------------------------------
   El «thaser» y el aviso a toda la casa. Lo que hay que respetar aquí:

   `prefers-reduced-motion` NO es opcional en esta pantalla. Zarandear la
   pantalla a quien tiene puesto «reducir movimiento» en su sistema no es
   una llamada de atención: es marearle. A esa persona se le enseña el
   mismo aviso, igual de imposible de ignorar, pero QUIETO — y por eso el
   velo tiene su propia variante en vez de apagarse sin más: quitar el
   movimiento no puede quitar el mensaje.
   ===================================================================== */

@keyframes werp-sacude {
  0%, 100% { transform: translate(0, 0); }
  10% { transform: translate(-9px, 3px) rotate(-.5deg); }
  20% { transform: translate(8px, -4px) rotate(.5deg); }
  30% { transform: translate(-7px, -3px) rotate(-.4deg); }
  40% { transform: translate(7px, 4px) rotate(.4deg); }
  50% { transform: translate(-5px, 2px) rotate(-.3deg); }
  60% { transform: translate(5px, -2px) rotate(.3deg); }
  70% { transform: translate(-3px, -1px); }
  80% { transform: translate(3px, 1px); }
  90% { transform: translate(-1px, 0); }
}
.thaser-sacude { animation: werp-sacude 1.6s cubic-bezier(.36, .07, .19, .97) both; }

@keyframes werp-destello {
  0%, 100% { background: rgba(194, 69, 81, 0); }
  15%, 45%, 75% { background: rgba(194, 69, 81, .30); }
  30%, 60%, 90% { background: rgba(194, 69, 81, .06); }
}
.thaser-velo {
  position: fixed; inset: 0; z-index: 9000; display: flex;
  align-items: flex-start; justify-content: center; padding-top: 12vh;
  animation: werp-destello 1.6s linear both;
  cursor: pointer;
}
/* Sin movimiento: un marco rojo grueso y quieto, y el aviso más tiempo. */
.thaser-velo.thaser-quieto {
  animation: none;
  background: rgba(194, 69, 81, .18);
  box-shadow: inset 0 0 0 8px var(--peligro);
}
.thaser-caja {
  display: flex; align-items: center; gap: var(--e-4);
  background: var(--superficie); border: 2px solid var(--peligro);
  border-radius: var(--radio); box-shadow: var(--sombra-2);
  padding: var(--e-4) var(--e-5); max-width: 460px;
}
.thaser-icono {
  width: 48px; height: 48px; flex: none; border-radius: 50%;
  background: var(--peligro); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--f-titulos); font-weight: 700; font-size: var(--t-28);
}
.thaser-quien { font-family: var(--f-titulos); font-weight: 700; font-size: var(--t-22); }
.thaser-que { color: var(--texto-suave); font-size: var(--t-13); margin-top: 2px; }
.msj-thaser-btn { color: var(--peligro); border-color: color-mix(in srgb, var(--peligro) 45%, transparent); }
.msj-thaser-btn:hover:not(:disabled) { background: var(--peligro-velo); }

/* --- El aviso a toda la casa --------------------------------------- */
.mega-aviso { display: flex; flex-direction: column; gap: var(--e-2); }
.mega-aviso-de { font-size: var(--t-12); color: var(--texto-mudo); }
.mega-aviso-cuerpo { font-size: var(--t-15); line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }

.mega-panel { margin-bottom: var(--e-3); }
.mega-panel-aviso { margin-bottom: var(--e-2); }
.mega-panel-pie { display: flex; justify-content: flex-end; margin-top: var(--e-2); }
.mega-ultimos { margin-top: var(--e-3); border-top: 1px solid var(--linea-suave); padding-top: var(--e-2); }
.mega-ultimo { display: flex; gap: var(--e-3); font-size: var(--t-12); padding: 2px 0; }
.mega-ultimo-cuando { font-family: var(--f-datos); color: var(--texto-mudo); flex: none; }
.mega-ultimo-quien { font-weight: 700; min-width: 110px; }
.mega-ultimo-texto { color: var(--texto-suave); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* =====================================================================
   LAS CARAS DE UN GRUPO, en la cabecera del hilo · v0.52.0
   ---------------------------------------------------------------------
   `flex-wrap` y sin tope de caras: Javier lo pidió así —«si son más de
   los que caben, ponlo en dos filas, no pasa nada»— y tiene razón.
   Recortarlas a «y otros 6 más» sería esconder justo lo que se ha venido
   a ver.
   ===================================================================== */
.msj-cab-caras { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; margin-top: 5px; }
.msj-cab-caras .avatar { margin: 2px; }
.msj-cara-yo { box-shadow: 0 0 0 2px var(--fondo), 0 0 0 4px var(--laton-oscuro); }
.msj-cab-caras-mas {
  border: 1px dashed var(--linea-fuerte); background: transparent; color: var(--texto-mudo);
  border-radius: 999px; padding: 1px var(--e-2); font-size: var(--t-12);
  cursor: pointer; font-family: var(--f-ui); margin-left: var(--e-2);
}
.msj-cab-caras-mas:hover { border-color: var(--laton-oscuro); color: var(--laton-texto); }

/* --- v0.53.0 · el hilo recibe gente, y el botón de la reunión -------- */
.msj-hilo-recibe { outline: 2px dashed var(--laton-oscuro); outline-offset: -4px; background: var(--laton-velo); }
.msj-llevando-persona .msj-hilo-marco { outline: 1px dashed var(--linea-fuerte); outline-offset: -4px; }
.msj-video-btn { color: var(--laton-texto); }
.msj-video-btn:hover { background: var(--laton-velo); }
/* Y una conversación de dos se enciende en rojo: no recibe a un tercero (v0.53.1). */
.msj-hilo-no-cabe { outline: 2px dashed var(--peligro); outline-offset: -4px; }

/* =====================================================================
   TAREAS · LAS CARAS ARRIBA Y EL TABLERO CON SU SCROLL · v0.55.0
   ---------------------------------------------------------------------
   Lo pidió Javier: las miniaturas del equipo en DOS FILAS, metidas en el
   blanco que quedaba a la derecha del título, y la cabecera quieta hasta
   el tablero, que es lo que hace scroll.
   ===================================================================== */

/* El hueco de la derecha del título. `min-width: 0` para que pueda
   encogerse: sin eso, una tira de dieciocho caras empujaría el título
   fuera de la pantalla en cuanto la ventana se hiciera estrecha. */
/* A LA ALTURA DEL TÍTULO. La cabecera alinea a sus hijos por abajo
   —bien para un botón—, pero una fila de caras al lado de un título de
   tres renglones se lee mejor centrada contra él. */
.tar-cab-equipo {
  /* `flex: 1 1 0` con `min-width: 0` es lo que la mantiene EN LA LÍNEA
     DEL TÍTULO. La cabecera de módulo envuelve a sus hijos, así que sin
     esto la tira se bajaba entera a un renglón propio en cuanto la
     ventana se estrechaba —1.150 px, un portátil— y volvíamos a lo de
     antes: una franja de caras empujando el tablero. Con esto la tira se
     encoge y hace scroll ella, y el título no se mueve a lo ancho.

     Y `position: relative` + `align-self: stretch` es lo que hace que no
     se mueva A LO ALTO (v0.55.4). Lo pidió Javier: la cabecera «Tareas y
     Proyectos» tiene que estar en el MISMO píxel en las cinco pestañas.
     Las caras solo salen en el Escritorio, y como eran más altas que el
     título, la cabecera crecía con ellas: al cambiar a Proyectos o al
     Gantt el título daba un salto de dieciséis píxeles. Un título que
     salta al cambiar de pestaña hace que la pantalla parezca inestable
     aunque todo funcione.

     La solución no es cuadrar alturas a mano —eso se descuadra el día que
     cambie la tipografía—: es que la tira NO CUENTE para el alto de la
     cabecera. Va colocada en absoluto dentro de este hueco, así que la
     cabecera mide lo que mide el título, con caras o sin ellas. */
  flex: 1 1 0; min-width: 0; max-width: 100%;
  align-self: stretch; position: relative;
}

/* UNA SOLA LÍNEA (v0.55.1). Javier lo pidió así después de verlo en dos:
   una fila de caras a la altura del título se lee de un barrido, y dos
   filas hacen recorrer la vista arriba y abajo para lo mismo.

   `nowrap` y no `wrap`: si no cupieran, lo que NO puede pasar es que se
   partan en dos filas otra vez ni que empujen el título. La tira hace
   scroll a lo ancho ELLA misma, que es lo que sobra por ese lado.

   Y las instrucciones ya no están aquí dentro: se fueron al pie de la
   pantalla, porque un párrafo de tres renglones delante de las caras se
   comía justo el sitio que hacía falta. */
.tar-equipo-tira.tar-equipo-arriba {
  /* En absoluto y unos píxeles más abajo, como pidió Javier: así la
     cabecera no crece con las caras y el título no se mueve al cambiar de
     pestaña. Los 6 px de más por abajo caen dentro del margen que ya
     había entre la cabecera y la fila de pestañas: no tapan nada. */
  position: absolute; left: 0; right: 0; bottom: -6px;
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: 0;
  padding: 0;
  border-bottom: 0;
  overflow-x: auto;
  overflow-y: hidden;
  max-width: 100%;
  /* Una barra de scroll fina y discreta: aquí aparece pocas veces y no
     puede robarle alto a las caras. */
  scrollbar-width: thin;
}
/* PEGADAS A LA DERECHA (v0.55.2), como pidió Javier: la última cara acaba
   donde acaba la cabecera, y el hueco queda entre el título y ellas.

   Y SE HACE CON `margin-left: auto` EN LA PRIMERA, no con
   `justify-content: flex-end`, que es lo que uno escribiría. La razón es
   el día que no caben: en una caja que hace scroll, `flex-end` empuja el
   contenido hacia fuera **por la izquierda**, y lo que se sale por ahí
   NO SE PUEDE ALCANZAR —el scroll no llega a números negativos—. Se
   perderían las primeras caras del equipo sin ningún aviso.

   Un margen automático no tiene ese problema: cuando sobra sitio, empuja
   todo a la derecha; cuando no sobra, vale cero y la tira se recorre de
   principio a fin con normalidad. */
.tar-equipo-tira.tar-equipo-arriba > *:first-child { margin-left: auto; }
/* Arriba las fichas van más juntas: no hay párrafo al lado peleando por
   el sitio, pero sí un título a la izquierda. */
.tar-equipo-tira.tar-equipo-arriba .tar-empleado { width: 74px; padding: 18px 1px 2px; flex: none; }
/* Y arriba no va el apellido: la cara tiene que caber en el alto del
   título, y el nombre de pila basta para reconocer a alguien de la casa.
   El nombre completo sigue estando al pasar el ratón, con sus cifras. */
.tar-equipo-tira.tar-equipo-arriba .tar-empleado-apellido { display: none; }

/* --- Y LA PANTALLA QUIETA HASTA EL TABLERO ------------------------- */
/* La sección reparte: lo que sobra va al cuerpo de la pestaña. Lo demás
   —la cabecera con las caras y la fila de pestañas— se queda quieto. */
.tar-seccion-fija { display: flex; flex-direction: column; min-height: 0; }
.tar-seccion-fija > .modulo-cabecera,
.tar-seccion-fija > .pestanas { flex: none; }
/* Y SIN EL DOBLE HUECO (v0.55.5). Esta línea arregla algo que se veía y
   no se entendía: la fila de pestañas —Escritorio, Proyectos, Gantt,
   Carga, Costes— salía **16 píxeles más abajo en el Escritorio** que en
   las otras cuatro.
   
   El motivo es de los que no se le ocurren a nadie mirando: `display:
   flex` **apaga el colapso de márgenes**. En las demás pestañas la
   sección es un bloque normal, así que los 20 px de debajo del título y
   los 16 de encima de las pestañas **se funden en 20**, que es como
   funciona el colapso. Aquí, al ser flex, se **suman**: 36. De ahí los 16
   de diferencia, y de ahí que el menú «bailara» solo al entrar y salir
   del Escritorio.
   
   Se quita el margen de arriba de las pestañas y queda el hueco del
   título: 20 en los dos casos, exactamente igual. */
.tar-seccion-fija > .pestanas { margin-top: 0; }
.tar-seccion-fija > #tar-cuerpo {
  flex: 1; min-height: 0; display: flex; flex-direction: column;
}
/* Dentro del cuerpo, el escritorio; y dentro del escritorio, el tablero
   es el único que crece y el único que hace scroll. `min-height: 0` en
   cada eslabón de la cadena: si falta en uno, el de abajo se niega a
   encogerse, el alto se desborda y volvemos a que haga scroll la página
   (es la línea que se olvidó en la v0.54.0 y no arreglaba nada). */
.tar-seccion-fija .tar-escritorio { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.tar-seccion-fija .tar-escritorio > .crm-barra,
.tar-seccion-fija .tar-escritorio > .tar-barra-vistas,
.tar-seccion-fija .tar-escritorio > .tar-resumen-linea,
.tar-seccion-fija .tar-escritorio > .tar-equipo-tira,
.tar-seccion-fija .tar-escritorio > .tar-pie-ayuda { flex: none; }
.tar-seccion-fija .tar-escritorio > [data-zona="tablero"] {
  flex: 1; min-height: 0; overflow: auto;
}
/* Y UN SOLO SCROLL, NO DOS. El kanban ya tenía el suyo a lo ancho; con
   el de arriba serían dos barras horizontales, una dentro de la otra, y
   arrastrar una tarjeta entre ellas es un pequeño infierno. Aquí manda
   la caja de fuera y el kanban se deja llevar. */
.tar-seccion-fija .tar-escritorio > [data-zona="tablero"] .kanban {
  overflow: visible; padding-bottom: 0;
}

@media (max-width: 1000px) {
  /* En pantalla estrecha vuelven abajo y a una fila, y manda la página:
     dos filas de caras y un tablero recortado en una pantalla de mano
     dejan las dos cosas ilegibles. */
  .tar-cab-equipo { width: 100%; }
  .tar-equipo-tira.tar-equipo-arriba {
    position: static; flex-wrap: wrap; overflow-x: visible;
    padding: 10px 2px 4px; border-bottom: 1px solid var(--linea-suave);
  }
  .tar-cab-equipo { align-self: auto; }
  .tar-equipo-tira.tar-equipo-arriba .tar-empleado-apellido { display: block; }
  .tar-equipo-tira.tar-equipo-arriba .tar-empleado { width: 86px; padding: 22px 2px 4px; }
  .tar-equipo-tira.tar-equipo-arriba > *:first-child { margin-left: 0; }
  .tar-seccion-fija .tar-escritorio > [data-zona="tablero"] { overflow: visible; flex: none; }
  .tar-seccion-fija .tar-escritorio > [data-zona="tablero"] .kanban { overflow-x: auto; }
}

/* --- LA TOTALIZACIÓN, DENTRO DE LA BARRA DE FILTROS · v0.55.3 --------
   Javier la movió aquí señalando el sitio en una captura: el blanco que
   quedaba a la derecha de «Nueva tarea». Antes ocupaba una franja propia
   entre las barras y el tablero — un renglón entero de pantalla para
   decir siete números.

   `margin-left: auto` la empuja a la derecha, y `flex-wrap: nowrap` con
   scroll la deja recorrerse si algún día no cupiera, en vez de partirse
   en dos líneas y volver a crecer a lo alto, que es de lo que veníamos.
   Las cifras van un punto más pequeñas: aquí compiten por el sitio con
   los filtros, no con el vacío. */
.tar-resumen-linea.tar-resumen-en-barra {
  /* `flex: 1 1 0` con `min-width: 0`, y NO `margin-left: auto`, que es lo
     primero que se escribe para empujar algo a la derecha. La razón: la
     barra de filtros ENVUELVE a sus hijos, y estas siete cifras miden
     ochocientos píxeles de ancho natural. Con un margen automático la
     barra contaba esos ochocientos, no le cabían, y **bajaba la
     totalización a un segundo renglón dentro de la propia barra**: o
     sea, volvíamos a gastar el renglón que este cambio venía a ahorrar,
     y encima disimulado.

     Con base cero no fuerza ningún salto: ocupa el hueco que quede a la
     derecha del botón —que es exactamente el sitio que señaló Javier— y
     si las cifras no caben se recorren ahí dentro. */
  flex: 1 1 0; min-width: 0; margin-bottom: 0;
  flex-wrap: nowrap; gap: var(--e-3);
  align-items: center; justify-content: flex-start;
  padding-left: var(--e-2); padding-bottom: 2px;
  /* Y el scroll empieza por el principio, no por el final: alinear a la
     derecha una caja que se recorre esconde su comienzo para siempre. */
  overflow-x: auto; overflow-y: hidden; scrollbar-width: thin;
}
.tar-resumen-linea.tar-resumen-en-barra .tar-resumen-dato { white-space: nowrap; }
.tar-resumen-linea.tar-resumen-en-barra .tar-resumen-dato strong {
  font-size: var(--t-14); margin-right: 2px;
}
.tar-resumen-linea.tar-resumen-en-barra .tar-resumen-raya { height: 16px; margin: 0 2px; }

@media (max-width: 1000px) {
  /* En pantalla estrecha vuelve a su renglón, debajo de los filtros: en
     la barra dejaría los desplegables del ancho de un dedal. */
  .tar-resumen-linea.tar-resumen-en-barra {
    flex: 1 1 100%; flex-wrap: wrap; overflow-x: visible; padding-left: 0;
  }
}

/* =====================================================================
   EL AVISO DE UN MENSAJE, EN LA ESQUINA · v0.57.0
   ---------------------------------------------------------------------
   Lo pidió Javier: «una ventana pop up que aparece en la esquina inferior
   derecha». Sustituye a la ventana del centro de la v0.50.0, que
   interrumpía todo lo que estuvieras haciendo.

   NO LLEVA TEMPORIZADOR, y es la parte importante: se queda hasta que se
   pincha o se pulsa Enter. Un aviso que se va solo a los cinco segundos
   es exactamente la objeción que hizo cambiarlo la vez anterior.

   Y no pelea con nadie por el sitio: se cuelga dentro de la columna que
   ya existe en esa esquina para los avisos cortos, así que los avisos de
   mensajes se quedan arriba y los «guardado» de cuatro segundos van
   debajo, sin taparse.
   ===================================================================== */
/* Va DENTRO de la columna de la esquina que ya existe para los avisos
   cortos, así que no necesita colocarse: la esquina la pone ella. Con eso
   se acaba el riesgo de que un «guardado» de cuatro segundos aparezca
   encima de un mensaje que hay que leer. */
.msj-avisos { display: flex; flex-direction: column; gap: var(--e-2); }

.msj-aviso {
  display: flex; align-items: flex-start; gap: var(--e-2);
  padding: var(--e-3);
  background: var(--superficie); color: var(--texto);
  border: 1px solid var(--linea);
  border-left: 3px solid var(--laton);
  border-radius: var(--radio);
  box-shadow: var(--sombra-2);
  cursor: pointer; text-align: left;
  animation: msj-aviso-entra .18s ease-out;
}
@keyframes msj-aviso-entra {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
/* A quien ha pedido menos movimiento no se le mueve: el aviso aparece y
   ya está. Quitar el movimiento no puede quitar el mensaje. */
@media (prefers-reduced-motion: reduce) {
  .msj-aviso { animation: none; }
}
.msj-aviso:hover { border-color: var(--laton-oscuro); background: var(--laton-velo); }
.msj-aviso:focus-visible { outline: 2px solid var(--laton); outline-offset: 2px; }
.msj-aviso-texto { min-width: 0; flex: 1; }
.msj-aviso-quien { font-size: var(--t-13); color: var(--texto-suave); }
.msj-aviso-frase { font-weight: 600; color: var(--texto); }
.msj-aviso-cuenta { color: var(--laton-texto); font-weight: 600; margin-left: 4px; }
/* Tres líneas y hasta ahí: el aviso dice de qué va, no sustituye a la
   conversación. Se pincha y se lee entera. */
.msj-aviso-cuerpo {
  margin-top: 2px; font-size: var(--t-14);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere;
}
.msj-aviso-x { flex: none; }
.msj-aviso-mas {
  border: 1px solid var(--linea); border-radius: var(--radio);
  background: var(--superficie-2); color: var(--texto-suave);
  font: inherit; font-size: var(--t-12); padding: var(--e-2) var(--e-3);
  cursor: pointer; text-align: left;
}
.msj-aviso-mas:hover { background: var(--laton-velo); color: var(--laton-texto); }

/* --- LA CARA Y LA MARCA EN LA LISTA DE MENSAJES · v0.57.0 -----------
   La cara ocupa todo el hueco del icono y se le quita el fondo: un
   avatar dentro de una pastilla gris parece una cara metida en una caja.
   La marca de WADAX va un poco más grande que un icono normal, porque es
   un trazo fino y a 15 px se pierde. */
.msj-item-icono.msj-item-icono-cara { background: none; padding: 0; }
.msj-item-icono.msj-item-icono-cara .avatar { width: 26px; height: 26px; font-size: 10px; }
.msj-item-icono.msj-item-icono-marca { background: var(--laton-velo); }
.msj-item-icono.msj-item-icono-marca svg { width: 19px; height: 19px; }

/* --- LOS INTERRUPTORES DE LOS AVISOS, UNO POR LÍNEA · v0.60.1 --------
   `.interruptor` es `inline-flex` porque en casi todas las pantallas va
   uno solo, dentro de una frase. Aquí van tres seguidos y se pegaban de
   dos en dos: «Avisarme con una notificación del sistema» acababa
   tocando el interruptor de al lado y no se sabía cuál era de cuál. Un
   interruptor que no se sabe qué apaga se deja sin tocar. */
#fu-avisos-cuerpo .interruptor { display: flex; margin: var(--e-2) 0; }
#fu-avisos-cuerpo .interruptor .etiqueta { font-size: var(--t-14); color: var(--texto); }
#fu-instalar { margin-top: var(--e-2); }

/* =====================================================================
   M-93 · LOS ICONOS PEGADOS AL MENSAJE · v0.61.0
   ---------------------------------------------------------------------
   «👍 5» tiene que ocupar poco y leerse de un barrido. Van debajo del
   cuerpo del mensaje y encima de «responder», porque es lo que más se usa
   y lo que menos cuesta: donde primero cae la vista.
   ===================================================================== */
.msj-reacciones { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
/* Dentro de una burbuja propia, los iconos se pegan a la derecha, como
   todo lo demás de ese lado (v0.64.0). */
.msj-msg-mio .msj-reacciones { justify-content: flex-end; }
.msj-msg-caja .msj-reaccion { background: var(--superficie-2); }
.msj-msg-mio .msj-msg-caja .msj-reaccion { background: var(--superficie); }
.msj-reaccion {
  display: inline-flex; align-items: center; gap: 3px;
  border: 1px solid var(--linea); border-radius: 999px;
  background: var(--superficie-2); color: var(--texto-suave);
  padding: 1px 7px 1px 5px; font: inherit; font-size: var(--t-12);
  cursor: pointer; line-height: 1.5;
}
.msj-reaccion:hover { border-color: var(--laton-oscuro); background: var(--laton-velo); }
.msj-reaccion:disabled { cursor: default; opacity: .8; }
/* LA MÍA SE DISTINGUE, y hace falta: sin esto no se sabe si el pulgar que
   hay puesto es el tuyo, y se acaba pulsando otra vez para averiguarlo
   —que es justo lo que lo quita—. */
.msj-reaccion-mia {
  border-color: var(--laton); background: var(--laton-velo); color: var(--laton-texto);
  font-weight: 600;
}
.msj-reaccion-icono { font-size: var(--t-14); line-height: 1; }
.msj-reaccion-cuenta { font-family: var(--f-datos); font-size: var(--t-12); }
/* El «más» solo se ve al pasar por encima del mensaje: si estuviera
   siempre a la vista, cada mensaje llevaría un botón que no hace nada la
   mayor parte del tiempo. */
.msj-reaccion-mas { opacity: 0; transition: opacity .12s ease; padding: 1px 6px; }
.msj-msg:hover .msj-reaccion-mas,
.msj-reaccion-mas:focus-visible { opacity: 1; }

/* --- El cuadro de elegir ------------------------------------------- */
/* Cuelga del `body` y se coloca a mano: dentro del mensaje lo recortaría
   la caja con scroll del hilo, que es el fallo clásico de un cuadro
   flotante (D-033). */
.msj-elegidor {
  position: fixed; z-index: 250;
  width: 260px; padding: var(--e-2);
  background: var(--superficie); border: 1px solid var(--linea);
  border-radius: var(--radio); box-shadow: var(--sombra-2);
}
.msj-elegidor-buscar { width: 100%; margin-bottom: var(--e-2); }
.msj-elegidor-rejilla {
  display: grid; grid-template-columns: repeat(6, 1fr); gap: 2px;
  max-height: 180px; overflow-y: auto;
}
.msj-elegidor-uno {
  border: 1px solid transparent; border-radius: var(--radio-sm);
  background: none; cursor: pointer; font-size: 19px; line-height: 1;
  padding: 4px 0;
}
.msj-elegidor-uno:hover { background: var(--laton-velo); border-color: var(--laton-oscuro); }
.msj-elegidor-uno:focus-visible { outline: 2px solid var(--laton); outline-offset: 1px; }
.msj-elegidor-pie { font-size: 11px; margin-top: var(--e-2); }

/* =====================================================================
   EL CALENDARIO LABORAL · v0.65.0
   ---------------------------------------------------------------------
   Dos cosas tienen que verse sin leer: el día que SÍ se trabaja aunque
   sea sábado, y la fecha que todavía no está confirmada. La segunda es
   la que importa: las chinas de 2026 entraron de una estimación, y una
   fecha con aire de oficial que no lo es mueve entregas.
   ===================================================================== */
.cal-fila { align-items: center; }
.cal-fila .tar-horas-fecha { flex: 0 0 190px; }
.cal-fila .tar-horas-quien { flex: 1 1 200px; }
.cal-marca {
  flex: none; font: 600 var(--t-12)/1 var(--f-ui); color: var(--texto-suave);
  border: 1px solid var(--linea); border-radius: 999px; padding: 3px 9px;
  background: var(--superficie-2);
}
.cal-si-trabaja .cal-marca { border-color: var(--ok); color: var(--ok); background: var(--ok-velo); }
.cal-sin-confirmar {
  flex: none; font: 700 10px/1 var(--f-ui); text-transform: uppercase; letter-spacing: .06em;
  color: var(--aviso); border: 1px dashed var(--aviso); border-radius: 999px; padding: 3px 8px;
  background: var(--aviso-velo);
}
.cal-fuente { flex: 1 1 220px; font-size: 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- Los recursos de una caja del mapa (v0.65.0) --- */
.prd-recurso { align-items: center; }
.prd-recurso .prd-recurso-puesto { flex: 1 1 140px; min-width: 110px; }
.prd-recurso select { flex: 1 1 170px; min-width: 130px; }
.prd-recurso input[type="number"] { max-width: 96px; }

/* Un día que no se trabaja FUERA (v0.65.0). Se marca y NO se atenúa: en
   Madrid ese día se trabaja, y pintarlo como festivo haría creer que el
   equipo libra. Lo que dice es «ojo, en China está parado». */
.tar-dia-fuera-marca {
  font: 700 9px/1 var(--f-ui); letter-spacing: .06em;
  color: var(--peligro); border: 1px solid var(--peligro);
  border-radius: 3px; padding: 1px 3px; vertical-align: middle;
}
.tar-dia-fuera { box-shadow: inset 2px 0 0 var(--peligro); }

/* Borrar un mapa de procesos (v0.66.0). Va en fantasma y no en rojo, y
   a la izquierda del todo: el botón rojo es «Archivar», que es lo que
   hay que hacer casi siempre. Si los dos fueran rojos, el que se pulsa
   por costumbre sería el que no se puede deshacer. */
.btn.prd-borrar { color: var(--peligro); }
.btn.prd-borrar:hover { border-color: var(--peligro); background: var(--peligro-velo); }
