/* ============================================================
   CAPA 3 — COMPONENTES BASE, para TODA la aplicación
   Reviste los componentes que ya usan todas las pantallas (.panel, .btn,
   tablas, etiquetas, campos, cabeceras) con los tokens del sistema, para que
   cada módulo herede la misma densidad, tipografía y color sin reescribir su
   plantilla.

   Se carga DESPUÉS de estilos.css: lo que aquí se define manda.
   Regla de siempre: ni un hex ni una familia tipográfica literal.
   ============================================================ */

body { font-family: var(--ui-font-body); background: var(--ui-canvas); color: var(--ui-text); }

/* ---------- jerarquía tipográfica ---------- */
h1 { font: var(--ui-h1); color: var(--ui-text); letter-spacing: -.4px; }
.pagina-cab .pc-t h1 { font: var(--ui-h1); }
.pagina-cab .pc-t .sub { font: var(--ui-body); color: var(--ui-text-secondary);
  margin-top: var(--ui-sp-1); }
h2 { font: var(--ui-h2); color: var(--ui-text); letter-spacing: var(--ui-track-h2); }
/* El titular de PANEL tiene su propio nivel: 15 px en Arial Nova semibold. Antes usaba
   el mismo tamaño que el titular de página, así que la app tenía dos niveles donde
   necesita tres, y 76 paneles gastaban 6 px de alto cada uno en decir su nombre más
   fuerte de lo que hace falta. `--ui-card-title` ya existía y no lo usaba nadie. */
.panel h2 { font: var(--ui-card-title); color: var(--ui-text); letter-spacing: 0;
  margin-bottom: var(--ui-sp-2); }
h2.titulo-pagina { font: var(--ui-h2); color: var(--ui-text);
  margin: var(--ui-sp-6) 0 var(--ui-sp-3); }
.hint, .panel .hint { font: var(--ui-label); color: var(--ui-text-secondary);
  margin-bottom: var(--ui-sp-3); }
.mdm { font: var(--ui-meta); color: var(--ui-text-muted); }
.subh { font: var(--ui-label); font-weight: var(--brand-weight-medium);
  color: var(--ui-text-secondary); text-transform: none; letter-spacing: 0;
  border-bottom: 1px solid var(--ui-divider); padding-bottom: var(--ui-sp-1);
  margin-bottom: var(--ui-sp-2); }

/* ---------- superficies ---------- */
.panel {
  background: var(--ui-surface); border: 1px solid var(--ui-border);
  border-radius: var(--ui-radius-card); box-shadow: var(--ui-shadow-card);
  /* El aire va AQUÍ y en la separación entre paneles, no en la altura de fila: así se
     respira sin perder filas visibles. Y el margen deja de escribirse a mano en las
     plantillas, que llegaron a tener catorce valores distintos para lo mismo. */
  padding: var(--ui-pad-card);
}
.panel + .panel, .panel + .wrap > .panel { margin-top: var(--ui-gap-card); }

/* ---------- FAMILIA DE ESTADO: un solo componente, cinco tonos ----------
   Antes había tres tonos repartidos en dos hojas, con cuatro radios distintos, y
   —lo importante— el ÉXITO y el ERROR salían por la misma caja azul: la app dice
   «Usuario creado» y «No se pudo crear el usuario» con exactamente la misma pinta.
   Un aviso que no distingue una cosa de la otra obliga a leerlo entero para saber
   si algo salió bien, que es justo lo que un aviso debería ahorrar.

   El tono lo pone una variable local; el resto de la regla es común. Así añadir un
   tono son dos líneas y no una copia entera. */
.aviso {
  --t: var(--ui-link);                 /* color del tono */
  --tbg: var(--ui-info-bg);            /* fondo teñido del tono */
  display: flex; align-items: flex-start; gap: var(--ui-sp-2);
  background: var(--tbg); border: 1px solid var(--t);
  border-left-width: 3px;              /* el filo lleva el tono: se lee de reojo */
  border-radius: var(--ui-radius-input);
  padding: var(--ui-sp-3) var(--ui-sp-4);
  font: var(--ui-body); color: var(--ui-text);
  margin: var(--ui-gap-card) 0;
  max-width: var(--ui-medida);         /* 65-75 caracteres por línea, manual 8.4 */
}
.aviso--exito    { --t: var(--ui-success); --tbg: var(--ui-success-bg); }
.aviso--atencion { --t: var(--ui-warning); --tbg: var(--ui-warning-bg); }
.aviso--riesgo,
.error           { --t: var(--ui-danger);  --tbg: var(--ui-danger-bg); }
.aviso--neutro   { --t: var(--ui-border);  --tbg: var(--ui-canvas); }
/* `.error` hereda toda la caja: las plantillas viejas siguen funcionando sin tocarlas. */
.error { display: flex; align-items: flex-start; gap: var(--ui-sp-2);
  background: var(--tbg); border: 1px solid var(--t); border-left-width: 3px;
  border-radius: var(--ui-radius-input); padding: var(--ui-sp-3) var(--ui-sp-4);
  font: var(--ui-body); color: var(--ui-text); margin: var(--ui-gap-card) 0;
  max-width: var(--ui-medida); }
.aviso b, .error b { font-weight: var(--brand-weight-bold); }

/* ---------- ESTADO VACÍO ----------
   No es «una tabla sin filas»: es el momento de decirle a alguien qué puede hacer.
   Por eso admite una acción dentro y no solo una frase gris. */
.empty {
  text-align: center; padding: var(--ui-sp-8) var(--ui-sp-4);
  color: var(--ui-text-secondary); font: var(--ui-body);
  background: var(--ui-canvas); border-radius: var(--ui-radius-input);
}
.empty.compacto { padding: var(--ui-sp-4); background: none; }
.empty b { display: block; color: var(--ui-text); margin-bottom: var(--ui-sp-1); }
.empty .btn { margin-top: var(--ui-sp-3); }

/* ---------- MARCO DE TABLA ----------
   Once tablas anchas —hasta de diez columnas— no tenían contenedor de desplazamiento:
   la única red era una media query bajo 860 px, que deja fuera justo el rango de los
   portátiles del equipo (861-1180 px). `tabindex="0"` no es adorno: sin él, una tabla
   que se desplaza es inalcanzable por teclado. */
.tabla-marco { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tabla-marco:focus-visible { outline: var(--ui-focus-w) solid var(--ui-focus-ring);
  outline-offset: var(--ui-focus-offset); }

/* ---------- MODAL ----------
   La sombra de 50 px con 30 % de negro era el caso de libro del «diseño anticuado»
   del 8.7. Se usa la elevación del sistema, que existía y no consumía nadie. */
.modal-fondo { background: rgba(26, 26, 26, .45); }
.modal {
  background: var(--ui-surface); border-radius: var(--ui-radius-card);
  padding: var(--ui-sp-6); width: min(460px, 92vw);
  box-shadow: var(--ui-shadow-pop);
}
.modal h3 { font: var(--ui-card-title); color: var(--ui-text); margin: 0 0 var(--ui-sp-1); }
.modal .hint { font: var(--ui-label); color: var(--ui-text-secondary);
  margin-bottom: var(--ui-sp-4); }
.modal .modal-acciones { display: flex; gap: var(--ui-sp-2); justify-content: flex-end;
  margin-top: var(--ui-sp-4); }
/* Las versiones de un solo tono de `.aviso` y `.empty` vivían aquí. Las reemplaza la
   familia de estado de más arriba; se retiran porque, al venir DESPUÉS en el archivo,
   ganaban por orden y anulaban los cinco tonos sin que se notara en ningún error. */

/* ---------- acción ---------- */
.btn, .boton {
  font: var(--ui-button); border-radius: var(--ui-radius-pill);
  height: var(--ui-control-h); padding: 0 var(--ui-sp-4);
  background: var(--brand-primary); border: 1px solid var(--brand-primary);
  color: var(--ui-chrome-text);
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  text-decoration: none; cursor: pointer; transition: background .15s, color .15s;
}
.btn:hover, .boton:hover { background: var(--brand-primary-dark);
  border-color: var(--brand-primary-dark); filter: none; }
/* El CTA conserva el cian del manual y el MISMO texto en los dos estados: el hover
   aclara en vez de oscurecer, así el azul sube a 5,02:1 en lugar de caer a 3,69:1.
   El contorno le da silueta contra el fondo crema, donde el relleno solo llega a 2,55:1. */
.btn.cta { background: var(--ui-btn-primary); border-color: var(--ui-btn-primary-bd);
  color: var(--ui-btn-primary-tx); }
.btn.cta:hover { background: var(--ui-btn-primary-hv);
  border-color: var(--ui-btn-primary-bd); color: var(--ui-btn-primary-tx); filter: none; }
.btn.ghost, .boton.secundario {
  background: var(--ui-surface); color: var(--ui-link);
  border-color: var(--ui-btn-ghost-bd);
}
.btn.ghost:hover, .boton.secundario:hover {
  /* Antes el hover repetía el mismo borde: el botón no daba señal de estar vivo. */
  background: var(--ui-row-hover); border-color: var(--ui-link);
  color: var(--ui-link-hover);
}
.btn.rojo { background: var(--ui-surface); color: var(--ui-danger);
  border-color: var(--ui-danger); }
.btn.rojo:hover { background: var(--ui-danger-bg); color: var(--ui-danger); }
.btn.sm, .boton.pequeno { height: 28px; padding: 0 var(--ui-sp-3); font: var(--ui-label);
  font-weight: var(--brand-weight-medium); }

/* ---------- campos ---------- */
/* SE SELECCIONA POR EXCLUSIÓN, NO POR ENUMERACIÓN. La lista por atributo dejaba fuera
   33 campos de la app que no declaran `type` —el atributo ausente NO casa con
   [type=text]—, entre ellos el usuario del ingreso: se quedaban con el borde decorativo
   de la hoja vieja y sin el sistema. Enumerar tipos obliga además a acordarse de añadir
   cada tipo nuevo; excluir los que se ven distintos (casilla, radio, deslizador…) cubre
   solo lo que hay que cubrir y no se olvida de nada.

   Va en la forma de LISTA —:not(a, b, c)— y no encadenada —:not(a):not(b)—: encadenada
   sumaría una clase por cada exclusión y dejaría el selector en 0-10-1, una especificidad
   que ninguna hoja futura podría ajustar sin pelear. En lista pesa 0-1-1, empata con
   `.formulario input` de la hoja vieja y gana por orden de carga, que es exactamente
   como está pensado que mande la Capa 3. */
select, textarea,
input:not([type=checkbox], [type=radio], [type=range], [type=color], [type=file],
           [type=hidden], [type=submit], [type=button], [type=image], [type=reset]) {
  font: var(--ui-body); color: var(--ui-text);
  border: 1px solid var(--ui-field-border); border-radius: var(--ui-radius-input);
  background: var(--ui-surface); padding: 0 var(--ui-sp-3);
  height: var(--ui-control-h);
}
textarea { height: auto; padding: var(--ui-sp-2) var(--ui-sp-3); line-height: 20px; }
select:focus-visible, input:focus-visible, textarea:focus-visible,
button:focus-visible, a:focus-visible, summary:focus-visible,
[tabindex]:focus-visible {
  outline: var(--ui-focus-w) solid var(--ui-focus-ring);
  outline-offset: var(--ui-focus-offset);
}
/* Sobre la barra lateral azul, un anillo azul da 1:1. Ahí el anillo es blanco. */
.sidebar a:focus-visible, .sidebar summary:focus-visible {
  outline-color: var(--ui-focus-ring-inv);
}
/* Un campo enfocado además se delinea: el anillo dice «aquí estoy», el borde dice
   «esto es lo que vas a escribir». */
select:focus-visible, input:focus-visible, textarea:focus-visible {
  border-color: var(--ui-link);
}
/* La búsqueda de la barra superior tenía 20 px de radio en la hoja vieja, justo el valor
   que el 8.7 prohíbe. Vive sobre el cromo, así que además lleva su propio fondo. */
.busqueda-global input { border-radius: var(--ui-radius-pill);
  border-color: var(--ui-field-border); }
label { font: var(--ui-label); color: var(--ui-text-secondary); }

/* ---------- tablas densas ---------- */
table { width: 100%; border-collapse: collapse; font: var(--ui-body); }
th {
  font: var(--ui-label); font-weight: var(--brand-weight-medium);
  color: var(--ui-text-secondary); text-transform: none; letter-spacing: 0;
  text-align: left; padding: var(--ui-sp-2) var(--ui-sp-3);
  border-bottom: 1px solid var(--ui-border);
}
td {
  padding: var(--ui-sp-2) var(--ui-sp-3); border-bottom: 1px solid var(--ui-divider);
  vertical-align: middle; color: var(--ui-text);
}
th.num, td.num { text-align: right; font-variant-numeric: tabular-nums; }
tbody tr:hover { background: var(--ui-row-hover); }
table.tabla { background: var(--ui-surface); border: 1px solid var(--ui-border);
  border-radius: var(--ui-radius-card); box-shadow: var(--ui-shadow-card); }
table.tabla th { background: var(--ui-surface); }

/* ---------- etiquetas ---------- */
.tag {
  font: var(--ui-label); font-weight: var(--brand-weight-medium);
  text-transform: none; letter-spacing: 0;
  color: var(--brand-primary); background: var(--ui-info-bg);
  padding: 2px 10px; border-radius: var(--ui-radius-pill);
}
/* .chipseg lleva su color de fondo en línea (es un dato del modelo, no una
   decisión de marca): aquí solo se le da la forma del sistema */
.chipseg { border-radius: var(--ui-radius-pill); font: var(--ui-label);
  font-weight: var(--brand-weight-medium); padding: 2px 10px; }

/* ---------- indicadores ---------- */
.statcard { gap: var(--ui-sp-3); }
.stat {
  background: var(--ui-surface); border: 1px solid var(--ui-border);
  border-radius: var(--ui-radius-card); box-shadow: var(--ui-shadow-card);
  padding: var(--ui-sp-3) var(--ui-sp-4);
}
.stat .sv { font: var(--ui-h1); color: var(--ui-text);
  font-variant-numeric: tabular-nums; }
.stat .sl { font: var(--ui-label); color: var(--ui-text-secondary); }

/* ---------- pares dato/valor ---------- */
.dkv { display: flex; justify-content: space-between; gap: var(--ui-sp-3);
  padding: 7px 0; border-bottom: 1px solid var(--ui-divider); font: var(--ui-body); }
.dkv:last-child { border-bottom: none; }
.dkv .k { font: var(--ui-label); color: var(--ui-text-secondary); }
.dkv .v { text-align: right; font-variant-numeric: tabular-nums; }
/* Separa un grupo de renglones que viene de OTRA fuente: en la ficha, las cifras del
   modelo comercial, que llegan congeladas en el maestro y abarcan los dos canales. Sin
   esta marca se leian como si fueran del mismo momento que las de arriba, que son vivas. */
.dkv-sep { margin-top: var(--ui-sp-3); border-top: 2px solid var(--ui-divider);
  padding-top: 10px; }

/* ---------- cromo de navegación ---------- */
.topbar { background: var(--ui-surface); border-bottom: 1px solid var(--ui-border); }
.sidebar { background: var(--ui-chrome-bg); }
.snav a { font: var(--ui-body); font-weight: var(--brand-weight-medium);
  color: var(--ui-chrome-dim); }
.snav a.activa { background: var(--ui-chrome-active); color: var(--ui-chrome-text);
  border-left-color: var(--ui-chrome-marker); }
.snav a:hover:not(.activa) { background: var(--ui-chrome-hover);
  color: var(--ui-chrome-text); }

/* --- grupo desplegable de la barra lateral (módulo Puntos de venta) ------------
   Un módulo con submenú, vistiendo el mismo cromo que los enlaces planos. Sin JS:
   <details> nativo, abierto cuando la vista activa vive dentro del grupo. */
.snav-grupo summary { display: flex; align-items: center; gap: 11px;
  color: var(--ui-chrome-dim); font: var(--ui-body); font-weight: var(--brand-weight-medium);
  font-size: 13px; padding: 11px 18px; border-left: 3px solid transparent;
  cursor: pointer; list-style: none; }
.snav-grupo summary::-webkit-details-marker { display: none; }
.snav-grupo summary:hover { background: var(--ui-chrome-hover); color: var(--ui-chrome-text); }
.snav-grupo summary svg { width: 16px; height: 16px; flex: none; stroke: currentColor;
  fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.snav-flecha { margin-left: auto; font-size: 10px; transition: transform .15s ease; }
.snav-grupo[open] .snav-flecha { transform: rotate(180deg); }
.snav-grupo[open] summary { color: var(--ui-chrome-text); }
.snav-grupo > a { padding-left: 45px; font-size: 12.5px; }
@media (prefers-reduced-motion: reduce) { .snav-flecha { transition: none; } }

/* Pestañas que son ENLACES y no botones: la vista se elige por la URL, así el
   filtro se puede compartir y funciona sin JavaScript. */
a.tab { text-decoration: none; }

/* ---------------------------------------------------------------------------
   MODO VISTA — el letrero de «está mirando como otra persona» (24-ago-2026)
   ---------------------------------------------------------------------------
   Va FIJO arriba de todo y empuja el cromo hacia abajo: la barra superior y la lateral
   son `position:fixed`, así que un letrero en el flujo del documento quedaria tapado
   justo por lo que tiene que estar por encima.
   Alto FIJO de 40 px y una sola linea (`nowrap`): si el texto envolviera, la barra
   creceria y el desplazamiento de abajo dejaria de cuadrar.
   Ocre de atencion sobre blanco: 5,05:1, cumple AA para texto normal. */
.barra-vista {
  position: fixed; top: 0; left: 0; right: 0; height: 40px; z-index: 40;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--ui-sp-4); padding: 0 22px;
  background: var(--ui-warning); color: #fff;
  font: var(--ui-body);
}
.barra-vista > span {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.barra-vista b { font-weight: var(--brand-weight-bold); }
.barra-vista .bv-solo {
  border: 1px solid rgba(255, 255, 255, .55); border-radius: var(--ui-radius-input);
  padding: 1px 7px; font: var(--ui-label);
}
.barra-vista form { flex: none; margin: 0; }
.barra-vista .btn {
  background: #fff; color: var(--ui-warning); border-color: #fff;
}
.barra-vista .btn:hover { background: var(--brand-neutral-050); }
/* El cromo baja los 40 px del letrero, y solo cuando el letrero existe. */
body.en-vista .topbar { top: 40px; }
body.en-vista .sidebar { top: 116px; }
body.en-vista .zona-contenido { padding-top: 116px; }

/* ---- Fluidez (25-ago-2026, guía Apple «Designing Fluid Interfaces») ------------
   1) La respuesta vive en el PRESS, no en el release: el control acusa recibo en el
      instante en que se toca. Solo transform (compositor), nunca layout.
   2) Movimiento reducido = equivalente sin vestíbulo, no cero feedback: quedan los
      cambios de color/opacidad, se van los desplazamientos. */
.btn, .boton { transition: background .15s, color .15s, transform .1s ease-out; }
.btn:active, .boton:active { transform: scale(.96); }
.tab:active { transform: translateY(1px); }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* ---- Cabezales ordenables (25-ago-2026, orden-tablas.js) ------------------------
   El indicador vive en el cabezal y solo aparece en la columna activa; el cursor
   dice que se puede antes del primer clic. */
th.ordenable { cursor: pointer; user-select: none; }
th.ordenable:hover { color: var(--brand-primary); }
th.orden-asc::after { content: " ▲"; font-size: 9px; }
th.orden-desc::after { content: " ▼"; font-size: 9px; }

/* ---------- salto al contenido ----------
   Primer foco de la pagina: permite pasar de largo la barra superior y el menu
   sin tabular por todos sus enlaces. Se esconde FUERA DE PANTALLA, no con
   display:none: un elemento oculto asi no puede recibir foco y el enlace no
   serviria para nada. */
.saltar-al-contenido {
  position: fixed; top: -100px; left: var(--ui-sp-2); z-index: 1000;
  background: var(--ui-surface); color: var(--ui-link);
  border: 1px solid var(--ui-focus-ring); border-radius: var(--ui-radius-input);
  padding: var(--ui-sp-2) var(--ui-sp-4); font: var(--ui-button);
  text-decoration: none;
}
.saltar-al-contenido:focus {
  top: var(--ui-sp-2);
  outline: var(--ui-focus-w) solid var(--ui-focus-ring);
  outline-offset: var(--ui-focus-offset);
}
