/* ══════════════════════════════════════════════════════════════════════════════════════════════
 ERPY · Sistema de diseño — COMPONENTES
 Fase 2. Depende de `tokens.css`, que tiene que cargarse antes.

 Todo lleva prefijo `.ty-`, igual que los tokens, para que no colisione con las 1.479 clases que ya
 existen en `styles.css`. Los dos sistemas conviven durante la migración.

 NO hay ni un color, ni un radio, ni una sombra, ni un tamaño de letra escrito a mano: todo sale de
 los tokens. Lo comprueba `tools/lint_ui.py`, donde este fichero está en el ámbito SISTEMA y el
 límite es cero.

 Este es exactamente el CSS que renderiza `ui-kit.html`. No hay una copia para el escaparate y otra
 para la aplicación: si el kit se ve bien, la aplicación se verá bien.
 ══════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── BOTONES ───────────────────────────────────────────────────────────────────────────── */
.ty-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--ty-e-2);
  min-height: var(--ty-control); padding: 0 var(--ty-e-4);
  font-family: inherit; font-size: var(--ty-t-base); font-weight: var(--ty-peso-fuerte);
  line-height: 1; border-radius: var(--ty-r-pastilla);
  border: 1px solid var(--ty-raya-fuerte); background-color: var(--ty-panel); color: var(--ty-tinta);
  box-shadow: var(--ty-s-1); cursor: pointer;
  transition: background var(--ty-v-rapida) var(--ty-curva), border-color var(--ty-v-rapida) var(--ty-curva);
}
.ty-btn:hover { background-color: var(--ty-panel-hondo); }
.ty-btn:focus-visible { outline: 2px solid var(--ty-marca-accion); outline-offset: 2px; }
.ty-btn[disabled] { opacity: 0.45; cursor: not-allowed; box-shadow: none; }

.ty-btn--principal {
  background-color: var(--ty-marca-accion); border-color: transparent;
  color: var(--ty-sobre-marca); box-shadow: var(--ty-s-2);
}
.ty-btn--principal:hover { background-color: var(--ty-marca-accion-fuerte); }
.ty-btn--fantasma { background: transparent; border-color: transparent; box-shadow: none; color: var(--ty-tinta-media); }
.ty-btn--fantasma:hover { background-color: var(--ty-panel-hondo); color: var(--ty-tinta); }
.ty-btn--destructivo { background: transparent; border-color: var(--ty-peligro-borde); color: var(--ty-peligro-tinta); box-shadow: none; }
.ty-btn--destructivo:hover { background-color: var(--ty-peligro-fondo); }
.ty-btn--compacto { min-height: 32px; padding: 0 var(--ty-e-3); font-size: var(--ty-t-menor); }

/* ── ETIQUETAS DE ESTADO ───────────────────────────────────────────────────────────────── */
.ty-etiqueta {
  display: inline-flex; align-items: center; gap: var(--ty-e-1);
  padding: var(--ty-e-1) var(--ty-e-3); border-radius: var(--ty-r-pastilla);
  font-size: var(--ty-t-micro); font-weight: var(--ty-peso-fuerte); line-height: 1.4;
  border: 1px solid var(--ty-raya); background-color: var(--ty-panel-hondo); color: var(--ty-tinta-media);
}
.ty-etiqueta--exito   { color: var(--ty-exito-tinta);   background-color: var(--ty-exito-fondo);   border-color: var(--ty-exito-borde); }
.ty-etiqueta--aviso   { color: var(--ty-aviso-tinta);   background-color: var(--ty-aviso-fondo);   border-color: var(--ty-aviso-borde); }
.ty-etiqueta--peligro { color: var(--ty-peligro-tinta); background-color: var(--ty-peligro-fondo); border-color: var(--ty-peligro-borde); }
.ty-etiqueta--info    { color: var(--ty-info-tinta);    background-color: var(--ty-info-fondo);    border-color: var(--ty-info-borde); }

/* ── CHIPS DE FILTRO ───────────────────────────────────────────────────────────────────── */
.ty-chip {
  display: inline-flex; align-items: center; gap: var(--ty-e-2);
  min-height: 32px; padding: 0 var(--ty-e-3); border-radius: var(--ty-r-pastilla);
  border: 1px solid var(--ty-raya); background-color: var(--ty-panel);
  font-size: var(--ty-t-menor); font-weight: var(--ty-peso-medio); color: var(--ty-tinta-media);
  cursor: pointer;
}
.ty-chip b {
  font-family: var(--ty-fuente-dato); font-size: var(--ty-t-micro);
  background-color: var(--ty-panel-hondo); border-radius: var(--ty-r-pastilla); padding: 1px var(--ty-e-2);
}
.ty-chip[aria-pressed="true"] {
  border-color: var(--ty-marca); background-color: var(--ty-marca-velo); color: var(--ty-marca-tinta);
}
.ty-chip[aria-pressed="true"] b { background-color: var(--ty-marca-accion); color: var(--ty-sobre-marca); }

/* ── KPI ───────────────────────────────────────────────────────────────────────────────── */
.ty-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--ty-e-3); }
.ty-kpi {
  background-color: var(--ty-panel); border: 1px solid var(--ty-raya);
  border-radius: var(--ty-r-3); padding: var(--ty-e-4); box-shadow: var(--ty-s-1);
}
.ty-kpi dt {
  font-size: var(--ty-t-micro); font-weight: var(--ty-peso-fuerte);
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--ty-tinta-suave);
}
.ty-kpi dd {
  margin: var(--ty-e-2) 0 0; font-size: var(--ty-t-cifra); font-weight: var(--ty-peso-maximo);
  line-height: var(--ty-linea-apretada); font-variant-numeric: tabular-nums;
}
.ty-kpi small { display: block; margin-top: var(--ty-e-1); font-size: var(--ty-t-menor); color: var(--ty-tinta-media); }

/* ── TABLA ─────────────────────────────────────────────────────────────────────────────── */
.ty-tabla-marco {
  overflow-x: auto; background-color: var(--ty-panel);
  border: 1px solid var(--ty-raya); border-radius: var(--ty-r-3);
}
.ty-tabla { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.ty-tabla thead th {
  position: sticky; top: 0; z-index: var(--ty-z-pegado);
  text-align: left; white-space: nowrap;
  padding: var(--ty-celda-y) var(--ty-celda-x);
  font-size: var(--ty-t-micro); font-weight: var(--ty-peso-maximo);
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--ty-tinta-suave);
  background-color: var(--ty-panel); border-bottom: 1px solid var(--ty-raya-fuerte);
}
.ty-tabla tbody td {
  padding: var(--ty-celda-y) var(--ty-celda-x); height: var(--ty-fila);
  border-bottom: 1px solid var(--ty-raya-fina); color: var(--ty-tinta-media);
  font-size: var(--ty-t-menor);
}
.ty-tabla tbody tr:last-child td { border-bottom: none; }
.ty-tabla tbody tr:hover td { background-color: var(--ty-panel-hondo); }
.ty-tabla td:first-child, .ty-tabla th:first-child { color: var(--ty-tinta); font-weight: var(--ty-peso-fuerte); }
.ty-num { text-align: right; font-family: var(--ty-fuente-dato); }
.ty-tabla tfoot td {
  padding: var(--ty-celda-y) var(--ty-celda-x);
  border-top: 2px solid var(--ty-tinta); font-weight: var(--ty-peso-maximo); color: var(--ty-tinta);
}

/* ── ESTADO VACÍO Y CARGA ──────────────────────────────────────────────────────────────── */
.ty-vacio {
  text-align: center; padding: var(--ty-e-7) var(--ty-e-4);
  color: var(--ty-tinta-media); background-color: var(--ty-panel);
  border: 1px dashed var(--ty-raya-fuerte); border-radius: var(--ty-r-3);
}
.ty-vacio strong { display: block; color: var(--ty-tinta); font-size: var(--ty-t-medio); margin-bottom: var(--ty-e-1); }
.ty-vacio .acciones { display: flex; gap: var(--ty-e-2); justify-content: center; margin-top: var(--ty-e-4); }
.ty-esqueleto {
  height: var(--ty-e-3); border-radius: var(--ty-r-1);
  background: linear-gradient(90deg, var(--ty-panel-hondo) 25%, var(--ty-raya-fina) 37%, var(--ty-panel-hondo) 63%);
  background-size: 400% 100%; animation: ty-brillo 1.4s ease infinite;
}
@keyframes ty-brillo { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ── FORMULARIO ────────────────────────────────────────────────────────────────────────── */
.ty-campo { display: grid; gap: var(--ty-e-1); margin-bottom: var(--ty-e-4); max-width: 380px; }
.ty-campo > label { font-size: var(--ty-t-menor); font-weight: var(--ty-peso-fuerte); color: var(--ty-tinta); }
.ty-campo input, .ty-campo select, .ty-campo textarea {
  min-height: var(--ty-control); padding: 0 var(--ty-e-3);
  font-family: inherit; font-size: var(--ty-t-base); color: var(--ty-tinta);
  background-color: var(--ty-panel); border: 1px solid var(--ty-raya-fuerte); border-radius: var(--ty-r-2);
}
.ty-campo input:focus-visible, .ty-campo select:focus-visible {
  outline: 2px solid var(--ty-marca-accion); outline-offset: 1px; border-color: var(--ty-marca-accion);
}
.ty-campo .ayuda { font-size: var(--ty-t-micro); color: var(--ty-tinta-suave); }
.ty-campo .error { font-size: var(--ty-t-micro); color: var(--ty-peligro-tinta); font-weight: var(--ty-peso-fuerte); }
.ty-campo[data-invalido] input { border-color: var(--ty-peligro-tinta); background-color: var(--ty-peligro-fondo); }

/* ── AVISOS ────────────────────────────────────────────────────────────────────────────── */
.ty-aviso {
  display: flex; gap: var(--ty-e-3); padding: var(--ty-e-3) var(--ty-e-4);
  border-radius: var(--ty-r-2); border: 1px solid var(--ty-info-borde);
  background-color: var(--ty-info-fondo); color: var(--ty-info-tinta);
  font-size: var(--ty-t-menor); font-weight: var(--ty-peso-medio);
  margin-bottom: var(--ty-e-3);
}
.ty-aviso--exito   { border-color: var(--ty-exito-borde);   background-color: var(--ty-exito-fondo);   color: var(--ty-exito-tinta); }
.ty-aviso--aviso   { border-color: var(--ty-aviso-borde);   background-color: var(--ty-aviso-fondo);   color: var(--ty-aviso-tinta); }
.ty-aviso--peligro { border-color: var(--ty-peligro-borde); background-color: var(--ty-peligro-fondo); color: var(--ty-peligro-tinta); }

/* ── DIÁLOGO CANÓNICO ──────────────────────────────────────────────────────────────────────
   Estructura sacada del modal de PARTES, que es el que funciona y el que se usa a diario:
   cabecera con identidad y estado, cuerpo con su propio scroll, pie con las acciones siempre en
   el mismo sitio. Lo que cambia es que ahora es UNO, con `<dialog>` nativo: Escape, clic fuera,
   foco atrapado y foco devuelto salen gratis. Hoy Escape cierra 3 de 53 cosas. */
.ty-dialogo {
  padding: 0; border: 1px solid var(--ty-raya); border-radius: var(--ty-r-4);
  background-color: var(--ty-panel); color: var(--ty-tinta);
  box-shadow: var(--ty-s-4); width: var(--ty-dialogo-m); max-height: 88vh;
  display: grid; grid-template-rows: auto 1fr auto;
}
.ty-dialogo::backdrop { background-color: var(--ty-velo); backdrop-filter: blur(3px); }
.ty-dialogo[open] { animation: ty-entra var(--ty-v-media) var(--ty-curva-entrada); }
@keyframes ty-entra { from { opacity: 0; transform: translateY(8px) scale(0.99); } }
.ty-dialogo--s { width: var(--ty-dialogo-s); }
.ty-dialogo--l { width: var(--ty-dialogo-l); }
.ty-dialogo--xl { width: var(--ty-dialogo-xl); }
.ty-dialogo-cabeza {
  display: flex; align-items: flex-start; gap: var(--ty-e-3);
  padding: var(--ty-e-4) var(--ty-e-5); border-bottom: 1px solid var(--ty-raya);
}
.ty-dialogo-eyebrow {
  font-size: var(--ty-t-micro); font-weight: var(--ty-peso-maximo); letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ty-marca-tinta);
}
.ty-dialogo-cabeza h2 {
  margin: var(--ty-e-1) 0 0; padding: 0; border: none;
  font-size: var(--ty-t-titulo); line-height: var(--ty-linea-apretada);
}
.ty-dialogo-cuerpo { padding: var(--ty-e-5); overflow-y: auto; }
.ty-dialogo-pie {
  display: flex; justify-content: flex-end; gap: var(--ty-e-2);
  padding: var(--ty-e-3) var(--ty-e-5); border-top: 1px solid var(--ty-raya);
  background-color: var(--ty-panel-hondo);
}
/* Un pie DENTRO del cuerpo: lo usan los diálogos que llevan su propio <form> (el guardado exige un
   submit real, así que sus botones no pueden ser los del pie genérico). Se sangra en negativo para
   que llegue de borde a borde igual que el pie normal. */
.ty-dialogo-cuerpo .ty-dialogo-pie {
  margin: var(--ty-e-5) calc(-1 * var(--ty-e-5)) calc(-1 * var(--ty-e-5));
}

/* Variante INMERSIVA: oscura en los dos temas. Toda la paleta viene de `[data-tema-local]`, que
   vive en tokens.css — aquí no se escribe ni un color. Es la decisión abierta: ver apartado 8. */
.ty-dialogo--inmersivo {
  background-color: var(--ty-panel); color: var(--ty-tinta); border-color: var(--ty-raya);
}


/* Piezas de la cabecera del diálogo, en el orden en que se leen: tipo de documento, identificador,
   quién y cuándo, y el estado. Es la estructura del modal de partes, que es el que funciona. */
.ty-dialogo-identidad { flex: 1; min-width: 0; }
.ty-dialogo-subtitulo {
  margin: var(--ty-e-1) 0 0;
  font-size: var(--ty-t-menor);
  color: var(--ty-tinta-media);
}
.ty-dialogo-etiquetas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ty-e-2);
  margin-top: var(--ty-e-2);
}
/* El error de un guardado, DENTRO del diálogo: el banner de la carcasa queda tapado debajo de la
   capa superior y no se vería. Lo pinta `muestraErrorEnDialogo` (dialogo.js). */
.ty-dialogo-error {
  margin: 0 0 var(--ty-e-4);
  padding: var(--ty-e-3) var(--ty-e-4);
  border: 1px solid var(--ty-peligro-borde);
  border-radius: var(--ty-r-2);
  background-color: var(--ty-peligro-fondo);
  color: var(--ty-peligro-tinta);
  font-size: var(--ty-t-menor);
  font-weight: var(--ty-peso-fuerte);
  line-height: var(--ty-linea-normal);
}

.ty-dialogo-mensaje {
  margin: 0;
  font-size: var(--ty-t-medio);
  line-height: var(--ty-linea-normal);
  color: var(--ty-tinta-media);
  max-width: var(--ty-texto-comodo);
}

/* En móvil un diálogo ocupa la pantalla: pelearse con un cuadro de 880px en un teléfono, en planta y
   con guantes, no tiene sentido. El pie se queda abajo, que es donde llega el pulgar. */
@media (max-width: 640px) {
  .ty-dialogo,
  .ty-dialogo--s,
  .ty-dialogo--l,
  .ty-dialogo--xl {
    width: 100vw;
    max-width: 100vw;
    max-height: 100vh;
    border-radius: 0;
    border: none;
  }
  .ty-dialogo-cabeza,
  .ty-dialogo-cuerpo,
  .ty-dialogo-pie { padding-inline: var(--ty-e-4); }
}

/* ── FORMULARIO DENTRO DE UN DIÁLOGO ─────────────────────────────────────────────────────────────
   `.ty-campo` ya define un campo suelto. Esto es lo que hace falta cuando van varios dentro de un
   diálogo: que no queden anclados a 380px y que en un diálogo ancho puedan ir a dos columnas.
   El ERP tiene formularios de hasta doce campos (`appForm` con `wide: true`). */
.ty-formulario {
  display: grid;
  gap: var(--ty-e-4) var(--ty-e-4);
  grid-template-columns: 1fr;
}
.ty-formulario .ty-campo { max-width: none; margin-bottom: 0; }

/* Dos columnas solo si el diálogo es ancho Y hay sitio. En un móvil siempre una: un campo a media
   pantalla con guantes es inservible. */
@media (min-width: 720px) {
  .ty-dialogo--l .ty-formulario,
  .ty-dialogo--xl .ty-formulario { grid-template-columns: 1fr 1fr; }
  /* Un campo puede pedir la fila entera: textareas y cosas largas. */
  .ty-campo--ancho { grid-column: 1 / -1; }
}

/* Casilla: la etiqueta va al lado, no encima, y toda la fila es objetivo táctil. */
.ty-campo--casilla {
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--ty-e-3);
  padding: var(--ty-e-3);
  border: 1px solid var(--ty-raya);
  border-radius: var(--ty-r-2);
  cursor: pointer;
}
.ty-campo--casilla input[type="checkbox"] {
  width: 18px; height: 18px; min-height: 0; margin-top: 2px;
  padding: 0; accent-color: var(--ty-marca-accion);
}
.ty-campo--casilla > label { cursor: pointer; }

/* Un grupo con título, para formularios largos. */
.ty-grupo { grid-column: 1 / -1; display: grid; gap: var(--ty-e-3); }
.ty-grupo > legend,
.ty-grupo-titulo {
  font-size: var(--ty-t-micro);
  font-weight: var(--ty-peso-maximo);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ty-tinta-suave);
  padding: 0;
}

/* Lista de opciones para elegir una (el antiguo `picker`). Cada opción es un botón de fila
   completa: en un teléfono, un menú de acciones se usa con el pulgar. */
.ty-opciones { display: grid; gap: var(--ty-e-2); }
.ty-opcion {
  display: flex; align-items: center; justify-content: space-between; gap: var(--ty-e-3);
  width: 100%; min-height: var(--ty-control);
  padding: var(--ty-e-3) var(--ty-e-4);
  font-family: inherit; font-size: var(--ty-t-base); font-weight: var(--ty-peso-medio);
  text-align: left; color: var(--ty-tinta);
  background-color: var(--ty-panel); border: 1px solid var(--ty-raya);
  border-radius: var(--ty-r-2); cursor: pointer;
  transition: background-color var(--ty-v-rapida) var(--ty-curva),
              border-color var(--ty-v-rapida) var(--ty-curva);
}
.ty-opcion:hover { background-color: var(--ty-panel-hondo); border-color: var(--ty-raya-fuerte); }
.ty-opcion:focus-visible { outline: 2px solid var(--ty-marca-accion); outline-offset: 2px; }

/* La etiqueta de una casilla va dentro de un <span> porque el <label> envuelve al control: así toda
   la fila es objetivo táctil sin depender de que `for` e `id` coincidan. */
.ty-campo-etiqueta {
  display: block;
  font-size: var(--ty-t-menor);
  font-weight: var(--ty-peso-fuerte);
  color: var(--ty-tinta);
}

/* El aire entre el mensaje y lo que viene debajo se resuelve con un selector hermano, no con un
   `style=` en la plantilla. La regla 2 del sistema prohíbe estilos en línea nuevos, y el
   comprobador la hizo cumplir en cuanto metí dos. */
.ty-dialogo-mensaje + .ty-formulario,
.ty-dialogo-mensaje + .ty-opciones { margin-top: var(--ty-e-4); }

/* Grupo de casillas (`type: "checks"` del ERP). Cada casilla es una fila táctil completa: el caso
   real es elegir las dietas del día en un teléfono, en planta. */
.ty-casillas { display: grid; gap: var(--ty-e-2); }
.ty-casilla {
  display: flex; align-items: center; gap: var(--ty-e-3);
  min-height: var(--ty-control); padding: var(--ty-e-2) var(--ty-e-3);
  border: 1px solid var(--ty-raya); border-radius: var(--ty-r-2);
  font-size: var(--ty-t-base); color: var(--ty-tinta); cursor: pointer;
}
.ty-casilla:hover { background-color: var(--ty-panel-hondo); }
.ty-casilla input[type="checkbox"] {
  width: 18px; height: 18px; min-height: 0; padding: 0;
  accent-color: var(--ty-marca-accion); cursor: pointer;
}
.ty-grupo { border: none; padding: 0; margin: 0; }
