/* ============================================================================
   Agenia — componentes del sistema
   Hoja unica para TODA pantalla: encabezados, tarjetas, formularios, botones,
   avisos, pastillas de estado, cifras y tablas.

   Regla: una pantalla nueva NO define color, radio ni sombra propios. Si algo
   falta, se agrega aqui como componente y se usa desde todas partes. Lo unico
   que puede vivir en la hoja de una pantalla es su disposicion (que va donde).

   Reemplaza a formulario.css, que solo cubria campos, botones y avisos.
   ========================================================================== */

/* --- Encabezado de pantalla ---------------------------------------------- */
.titulo-pagina {
  font-size: var(--texto-2xl);
  margin: 0 0 var(--esp-1);
}

.bajada-pagina {
  color: var(--color-texto-suave);
  margin: 0 0 var(--esp-5);
  max-width: 70ch;
}

/* --- Rejilla de bloques --------------------------------------------------
   auto-fit + minmax deja que las tarjetas se acomoden solas; el min() evita que
   una columna pida mas ancho que la pantalla en un telefono. */
.rejilla {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: var(--esp-4);
}

/* Un formulario a 260px queda incomodo de llenar: sus columnas son mas anchas. */
.rejilla--formulario { grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr)); }
.rejilla--perfil     { grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr)); }

/* Hijo que ocupa la fila entera: la barra de acciones de un formulario que se
   reparte en varias tarjetas, o una tarjeta que necesita todo el ancho. */
.rejilla__completo { grid-column: 1 / -1; }

/* Dos rejillas seguidas en una misma pantalla: la segunda se separa con el mismo
   aire que hay entre tarjetas, no pegada. */
.rejilla + .rejilla { margin-top: var(--esp-4); }

/* --- Tarjeta -------------------------------------------------------------
   El contenedor de todo. En esta direccion visual el borde es casi invisible y
   la separacion la hace la elevacion: por eso sombra suave y radio grande. */
.tarjeta {
  padding: var(--esp-5);
  background: var(--color-superficie);
  border: 1px solid var(--color-borde);
  border-radius: var(--radio-lg);
  box-shadow: var(--sombra-sm);
  min-width: 0;   /* sin esto, una tabla ancha adentro estira la rejilla */
}

/* Los margenes por defecto de p/h del navegador separarian el contenido del
   borde de la tarjeta de forma despareja. */
.tarjeta > :first-child { margin-top: 0; }
.tarjeta > :last-child  { margin-bottom: 0; }

.tarjeta__titulo {
  font-size: var(--texto-lg);
  margin: 0 0 var(--esp-4);
  padding-bottom: var(--esp-3);
  border-bottom: 1px solid var(--color-borde-suave);
}

.tarjeta__nota {
  margin: calc(var(--esp-4) * -1) 0 var(--esp-4);
  font-size: var(--texto-sm);
  color: var(--color-texto-suave);
}

/* Cabecera de tarjeta con acciones a la derecha. Envuelve en movil en vez de
   apretar el titulo. */
.tarjeta__cabecera {
  display: flex; align-items: center; gap: var(--esp-3); flex-wrap: wrap;
  margin: 0 0 var(--esp-4);
  padding-bottom: var(--esp-3);
  border-bottom: 1px solid var(--color-borde-suave);
}
/* Dentro de la cabecera el titulo pierde su propio separador: lo aporta la
   cabecera, y dos lineas seguidas se ven como un error. */
.tarjeta__cabecera .tarjeta__titulo { margin: 0; padding: 0; border: 0; flex: 1 1 auto; }

/* --- Rotulo de bloque ----------------------------------------------------- */
.rotulo {
  font-size: var(--texto-sm);
  font-weight: 500;
  color: var(--color-texto-suave);
  margin: 0 0 var(--esp-3);
}

/* --- Tile de resumen ------------------------------------------------------
   Para cifras del dia (citas, recaudado, stock critico). La cifra manda: va en
   el tamano mayor y con tabular, para que una columna de tiles quede pareja. */
.tile {
  display: flex; flex-direction: column; gap: var(--esp-1);
  padding: var(--esp-4) var(--esp-5);
  background: var(--color-superficie);
  border: 1px solid var(--color-borde);
  border-radius: var(--radio-lg);
  box-shadow: var(--sombra-sm);
  min-width: 0;
}
.tile__rotulo { font-size: var(--texto-sm); color: var(--color-texto-suave); }
.tile__cifra  { font-size: var(--texto-2xl); font-weight: 600; letter-spacing: -.03em; line-height: 1.15; }
.tile__pie    { font-size: var(--texto-xs); color: var(--color-texto-suave); }

/* El tile destacado se tine de marca en vez de agregar una sombra mas fuerte:
   asi la jerarquia se lee sin que todo el tablero parezca flotar. */
.tile--destacado { background: var(--color-marca-suave); border-color: transparent; }
/* Totales con color semantico (reporte de comisiones): verde lo que ingresa, ambar lo que sale. El rotulo lo dice. */
.tile--ingreso .tile__cifra { color: var(--color-exito); }
.tile--egreso .tile__cifra  { color: var(--color-aviso); }
.tile--destacado .tile__cifra  { color: var(--color-marca-fuerte); }
.tile--destacado .tile__rotulo,
.tile--destacado .tile__pie    { color: var(--color-marca-fuerte); opacity: .85; }

/* --- Campos --------------------------------------------------------------- */
.campo { display: flex; flex-direction: column; gap: var(--esp-2); margin-bottom: var(--esp-4); }

.campo__etiqueta {
  font-size: var(--texto-sm);
  font-weight: 500;
  color: var(--color-texto-suave);
}

.campo__ayuda {
  font-size: var(--texto-xs);
  color: var(--color-texto-suave);
}

.campo__control {
  width: 100%;
  min-height: 46px;
  padding: var(--esp-3) var(--esp-4);
  /* El campo es el unico elemento con borde declaradamente visible: si no, en
     una superficie sin bordes no se distingue donde se puede escribir. */
  border: 1px solid var(--color-borde-fuerte);
  border-radius: var(--radio-campo);
  background: var(--color-superficie);
  color: var(--color-texto);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.campo__control::placeholder { color: var(--color-texto-tenue); }
.campo__control:hover { border-color: var(--color-texto-tenue); }
.campo__control:focus {
  outline: none;
  border-color: var(--color-marca);
  box-shadow: 0 0 0 3px var(--color-marca-suave);
}
.campo__control:disabled {
  background: var(--color-superficie-alt);
  color: var(--color-texto-suave);
  cursor: not-allowed;
}
/* aria-invalid lo pone el JS al fallar la validacion: el borde rojo acompana al
   mensaje, nunca lo reemplaza. */
.campo__control[aria-invalid="true"] { border-color: var(--color-error); }

/* select: se le quita la flecha del sistema y se dibuja una propia para que no
   desentone con el resto de los controles. */
select.campo__control {
  appearance: none;
  padding-right: var(--esp-8);
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 20px) 50%, calc(100% - 14px) 50%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}

textarea.campo__control { min-height: 110px; resize: vertical; }

.campo__grupo { position: relative; display: flex; }
.campo__grupo .campo__control { padding-right: 3.25rem; }

.campo__accion {
  position: absolute;
  right: var(--esp-2);
  top: 50%;
  transform: translateY(-50%);
  /* 44x44: area tactil minima para no fallar el toque en un telefono. */
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 0; background: transparent;
  color: var(--color-texto-suave);
  border-radius: var(--radio-full);
  cursor: pointer;
}
.campo__accion:hover { color: var(--color-texto); background: var(--color-superficie-alt); }

/* Mensaje de error pegado al campo, no en la caja de aviso general. */
.campo__error {
  display: flex; align-items: center; gap: var(--esp-2);
  font-size: var(--texto-xs);
  font-weight: 500;
  color: var(--color-error);
}

/* --- Botones --------------------------------------------------------------
   Pildora. El primario lleva sombra de marca, que es lo que lo separa del
   secundario incluso en una captura en blanco y negro. */
.boton {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--esp-2);
  min-height: 46px;
  padding: 0 var(--esp-5);
  border: 1px solid var(--color-marca);
  border-radius: var(--radio-boton);
  background: var(--color-marca);
  color: var(--color-marca-contraste);
  font-size: var(--texto-base);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--sombra-marca);
  transition: background-color .15s ease, border-color .15s ease, color .15s ease,
              box-shadow .15s ease, transform .15s ease;
}
.boton:hover:not(:disabled) { background: var(--color-marca-fuerte); border-color: var(--color-marca-fuerte); }
.boton:active:not(:disabled) { transform: translateY(1px); }
.boton:disabled { opacity: .6; cursor: not-allowed; box-shadow: none; }

/* Mientras el JS espera la respuesta el boton queda deshabilitado con el cursor
   de progreso: deshabilitado por si solo se lee como "no puede", no como
   "espere". */
.boton[data-cargando="true"] { cursor: progress; }

.boton--bloque { width: 100%; }
.boton--chico  { min-height: 38px; padding: 0 var(--esp-4); font-size: var(--texto-sm); }

.boton--secundario {
  background: var(--color-superficie);
  color: var(--color-texto);
  border-color: var(--color-borde-fuerte);
  box-shadow: var(--sombra-sm);
}
.boton--secundario:hover:not(:disabled) {
  background: var(--color-superficie-alt);
  border-color: var(--color-texto-tenue);
}

.boton--sutil {
  background: transparent;
  color: var(--color-marca-fuerte);
  border-color: transparent;
  box-shadow: none;
}
.boton--sutil:hover:not(:disabled) { background: var(--color-marca-suave); border-color: transparent; }

.boton--peligro {
  background: var(--color-error);
  border-color: var(--color-error);
  color: #fff;
  box-shadow: none;
}
.boton--peligro:hover:not(:disabled) { background: var(--color-error-fuerte); border-color: var(--color-error-fuerte); }

/* Fila de acciones al pie de un formulario. */
.acciones { display: flex; flex-wrap: wrap; gap: var(--esp-3); align-items: center; }
.acciones--fin { justify-content: flex-end; }

/* --- Avisos inline -------------------------------------------------------
   Para lo que el usuario tiene que leer y corregir; lo que ya se hizo va por
   toast (ver src/notificacion.ts). Todos llevan un simbolo ademas del color:
   quien no distingue rojo de verde debe poder saber igual como resulto.

   El simbolo se dibuja con ::before para que el JS pueda escribir el mensaje
   con textContent sin borrarlo. */
.aviso {
  display: flex;
  gap: var(--esp-3);
  align-items: flex-start;
  padding: var(--esp-3) var(--esp-4);
  margin-bottom: var(--esp-4);
  border: 1px solid transparent;
  border-radius: var(--radio-md);
  font-size: var(--texto-sm);
}
.aviso::before {
  flex-shrink: 0;
  width: 20px; height: 20px;
  margin-top: 1px;
  display: grid; place-items: center;
  border-radius: var(--radio-full);
  background: currentColor;
  color: var(--color-superficie);
  font-size: var(--texto-xs);
  font-weight: 700;
  line-height: 1;
}

.aviso--error { background: var(--color-error-fondo); color: var(--color-error); }
.aviso--error::before { content: "!"; }

.aviso--exito { background: var(--color-exito-fondo); color: var(--color-exito); }
.aviso--exito::before { content: "\2713"; }

.aviso--info { background: var(--color-aviso-fondo); color: var(--color-aviso); }
.aviso--info::before { content: "i"; }

/* --- Pastillas de estado -------------------------------------------------
   El cuadrito de color va SIEMPRE con su texto al lado. */
.estado {
  display: inline-flex; align-items: center; gap: var(--esp-2);
  padding: var(--esp-1) var(--esp-3);
  border-radius: var(--radio-full);
  font-size: var(--texto-xs);
  font-weight: 600;
  white-space: nowrap;
}
.estado::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: var(--radio-full);
  background: currentColor;
  flex-shrink: 0;
}

.estado--exito   { background: var(--color-exito-fondo); color: var(--color-exito); }
.estado--espera  { background: var(--color-aviso-fondo); color: var(--color-aviso); }
.estado--activo  { background: var(--color-marca-suave); color: var(--color-marca-fuerte); }
.estado--anulado { background: var(--color-error-fondo); color: var(--color-error); }
.estado--neutro  { background: var(--color-superficie-alt); color: var(--color-texto-suave); }

/* --- Tablas --------------------------------------------------------------
   La caja se encarga del scroll horizontal: la pagina NUNCA se desplaza de
   lado, la tabla si dentro de su contenedor. */
.tabla-caja {
  background: var(--color-superficie);
  border: 1px solid var(--color-borde);
  border-radius: var(--radio-lg);
  box-shadow: var(--sombra-sm);
  overflow-x: auto;
}

.tabla { width: 100%; border-collapse: collapse; font-size: var(--texto-sm); min-width: 560px; }

.tabla thead th {
  text-align: left;
  padding: var(--esp-3) var(--esp-4);
  font-size: var(--texto-sm);
  font-weight: 500;
  color: var(--color-texto-suave);
  border-bottom: 1px solid var(--color-borde);
  white-space: nowrap;
}

.tabla tbody td {
  padding: var(--esp-3) var(--esp-4);
  border-bottom: 1px solid var(--color-borde-suave);
  vertical-align: middle;
}
.tabla tbody tr:last-child td { border-bottom: 0; }
.tabla tbody tr:hover td { background: var(--color-superficie-alt); }

/* Columna de dinero o cantidades: a la derecha y con cifras de ancho fijo. */
.tabla .numero, .numero { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Portada de una sucursal (0136): proporcion fija 41:18 (820 x 360), recortada al centro por el servidor. */
.portada-vista { display: block; width: 100%; height: auto; aspect-ratio: 41 / 18; object-fit: cover; border-radius: var(--radio-campo); background: var(--color-superficie-alt); }

/* Estado vacio GUIADO: los pasos numerados del flujo y el boton para empezar (giftcards-catalogo.md §1). */
.vacio-guiado { display: grid; justify-items: center; gap: var(--esp-3); padding: var(--esp-6) var(--esp-4); text-align: center; }
.vacio-guiado__titulo { margin: 0; font-weight: 600; }
.vacio-guiado__pasos { display: grid; gap: var(--esp-2); margin: 0; padding: 0; list-style: none; counter-reset: paso; text-align: left; }
.vacio-guiado__pasos li { display: flex; align-items: baseline; gap: var(--esp-2); counter-increment: paso; font-size: var(--texto-sm); color: var(--color-texto-suave); }
.vacio-guiado__pasos li::before {
  content: counter(paso); flex: 0 0 auto; display: inline-grid; place-items: center; width: 1.75rem; height: 1.75rem;
  border-radius: var(--radio-full); background: var(--color-marca-suave); color: var(--color-texto); font-weight: 600;
}

/* Mensaje de tabla vacia. Una tabla sin filas y sin explicacion parece rota. */
.tabla-vacia {
  padding: var(--esp-6) var(--esp-4);
  text-align: center;
  color: var(--color-texto-suave);
  font-size: var(--texto-sm);
}

/* --- Ficha de solo lectura ----------------------------------------------
   Etiqueta arriba y valor abajo en movil; dos columnas desde tablet. */
.ficha { margin: 0; font-size: var(--texto-sm); }
.ficha dt { font-weight: 500; color: var(--color-texto-suave); }
.ficha dd { margin: 0 0 var(--esp-3); overflow-wrap: anywhere; }

@media (min-width: 480px) {
  .ficha {
    display: grid;
    grid-template-columns: minmax(130px, auto) 1fr;
    gap: var(--esp-2) var(--esp-4);
    align-items: baseline;
  }
  .ficha dd { margin: 0; }
}

/* --- Avatar de iniciales -------------------------------------------------- */
.avatar {
  width: 34px; height: 34px; flex-shrink: 0;
  display: grid; place-items: center;
  border-radius: var(--radio-full);
  background: var(--color-marca-suave);
  color: var(--color-marca-fuerte);
  font-size: var(--texto-sm);
  font-weight: 600;
}

/* --- Utilidades de texto -------------------------------------------------- */
.texto-suave { color: var(--color-texto-suave); }
.texto-sm    { font-size: var(--texto-sm); }

/* --- Barra de herramientas de un listado ---------------------------------
   Buscador + filtros + accion principal. En movil se apila; desde tablet el
   buscador se estira y los filtros se acomodan a su lado.

   La barra NO es una tarjeta: va suelta sobre el fondo, encima de la tabla,
   para que se lea como "controles de esta tabla" y no como otro bloque mas. */
.barra-herramientas {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--esp-3);
  margin-bottom: var(--esp-4);
}

/* Cada control lleva su etiqueta ENCIMA, siempre. Es una sola convencion a
   proposito: mezclar etiqueta dentro, encima y como pastilla en la misma app
   obliga al usuario a redescubrir el patron en cada pantalla. */
.barra-herramientas .campo { margin-bottom: 0; flex: 0 1 190px; min-width: 0; }
.barra-herramientas .campo--buscador { flex: 1 1 260px; }
.barra-herramientas .acciones { margin-left: auto; }

/* Buscador: la lupa vive dentro del campo, a la izquierda. */
.campo--buscador .campo__grupo .campo__control { padding-right: var(--esp-4); padding-left: 2.75rem; }
.campo--buscador .campo__icono {
  position: absolute;
  left: var(--esp-3);
  top: 50%;
  transform: translateY(-50%);
  color: var(--color-texto-suave);
  pointer-events: none;   /* el clic debe caer en el input, no en el icono */
}

/* --- Chips de filtro aplicado -------------------------------------------
   De los cuatro patrones de filtro que se vieron en el producto de referencia
   este es el mejor: el usuario ve de un vistazo TODO lo que esta acotando el
   listado y puede soltar un criterio sin abrir nada.

   La fila entera se oculta con [hidden] cuando no hay ningun filtro puesto. */
.chips {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-2);
  margin-bottom: var(--esp-4);
}
.chips__rotulo { font-size: var(--texto-xs); color: var(--color-texto-suave); }

.chip {
  display: inline-flex; align-items: center; gap: var(--esp-2);
  padding: var(--esp-1) var(--esp-2) var(--esp-1) var(--esp-3);
  border: 1px solid var(--color-borde);
  border-radius: var(--radio-full);
  background: var(--color-superficie);
  font-size: var(--texto-xs);
  white-space: nowrap;
  max-width: 100%;
}
.chip__texto { overflow: hidden; text-overflow: ellipsis; }

.chip__quitar {
  flex-shrink: 0;
  /* 24px visibles, pero el area tactil real llega a 44 con el ::after, que es
     lo que exige la regla de accesibilidad sin inflar el chip. */
  width: 24px; height: 24px;
  display: grid; place-items: center;
  position: relative;
  border: 0; border-radius: var(--radio-full);
  background: var(--color-superficie-alt);
  color: var(--color-texto-suave);
  cursor: pointer;
}
.chip__quitar::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 44px; height: 44px;
}
.chip__quitar:hover { background: var(--color-error-fondo); color: var(--color-error); }

/* --- Varios correos como chips (src/correosChips.ts) --------------------
   Se ve como un .campo__control: el borde marca donde se escribe; los chips van dentro. */
.correos-chips {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-2);
  min-height: 46px; padding: var(--esp-2) var(--esp-3);
  border: 1px solid var(--color-borde-fuerte); border-radius: var(--radio-campo);
  background: var(--color-superficie); cursor: text;
}
.correos-chips:focus-within { border-color: var(--color-marca); box-shadow: 0 0 0 3px var(--color-marca-suave); }
.correos-chips__lista { display: flex; flex-wrap: wrap; gap: var(--esp-2); margin: 0; padding: 0; list-style: none; min-width: 0; }
.correos-chips__entrada {
  flex: 1 1 12rem; min-width: 0; min-height: 32px; border: 0; padding: 0 var(--esp-1);
  background: transparent; color: var(--color-texto); font: inherit;
}
.correos-chips__entrada:focus { outline: none; }
.correos-chips__entrada::placeholder { color: var(--color-texto-tenue); }

/* --- Acciones dentro de una fila de tabla --------------------------------
   Botones chicos, siempre con texto: un listado lleno de iconos mudos obliga a
   probar para saber que hace cada uno. */
.tabla__acciones { display: flex; flex-wrap: wrap; gap: var(--esp-2); justify-content: flex-end; }
.tabla__acciones .boton { min-height: 34px; padding: 0 var(--esp-3); font-size: var(--texto-xs); }

/* Celda con avatar + nombre + dato secundario debajo. */
.celda-persona { display: flex; align-items: center; gap: var(--esp-3); min-width: 0; }
.celda-persona__texto { min-width: 0; }
.celda-persona__nombre { font-weight: 500; overflow-wrap: anywhere; }
.celda-persona__dato { font-size: var(--texto-xs); color: var(--color-texto-suave); overflow-wrap: anywhere; }

/* --- Paginacion ----------------------------------------------------------
   Un solo tamano de pagina en todo el sistema (25). El producto de referencia
   tenia cuatro distintos y el usuario no puede predecir cuantas filas vera. */
.paginacion {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-3);
  padding: var(--esp-3) var(--esp-4);
  border-top: 1px solid var(--color-borde-suave);
  font-size: var(--texto-sm);
  color: var(--color-texto-suave);
}
.paginacion__conteo { margin-right: auto; }

/* --- Modal ---------------------------------------------------------------
   Sobre <dialog> nativo: el navegador ya aporta el foco atrapado, el cierre con
   Escape y el orden de capas. Reimplementar eso a mano siempre sale peor.

   Se abre con showModal(). El ::backdrop es del navegador, asi que su color no
   puede salir de un token heredado: se declara aqui y en ningun otro sitio. */
.modal {
  width: min(560px, calc(100vw - var(--esp-6)));
  max-height: calc(100dvh - var(--esp-6));
  padding: 0;
  border: 1px solid var(--color-borde);
  border-radius: var(--radio-lg);
  background: var(--color-superficie);
  color: var(--color-texto);
  box-shadow: var(--sombra-lg);
  overflow: hidden;
}
.modal--ancho { width: min(760px, calc(100vw - var(--esp-6))); }
.modal::backdrop { background: rgba(12, 32, 30, .55); }

.modal__caja { display: flex; flex-direction: column; max-height: calc(100dvh - var(--esp-6)); }

.modal__cabecera {
  display: flex; align-items: flex-start; gap: var(--esp-3);
  padding: var(--esp-5) var(--esp-5) var(--esp-4);
  border-bottom: 1px solid var(--color-borde-suave);
}
.modal__titulo { font-size: var(--texto-lg); margin: 0; flex: 1 1 auto; }
.modal__nota   { font-size: var(--texto-sm); color: var(--color-texto-suave); margin: var(--esp-2) 0 0; }

.modal__cerrar {
  flex-shrink: 0;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  margin: calc(var(--esp-2) * -1) calc(var(--esp-2) * -1) 0 0;
  border: 0; border-radius: var(--radio-full);
  background: transparent;
  color: var(--color-texto-suave);
  cursor: pointer;
}
.modal__cerrar:hover { background: var(--color-superficie-alt); color: var(--color-texto); }

/* El cuerpo es lo unico que hace scroll: la cabecera y el pie quedan fijos y el
   boton de guardar no se pierde al final de un formulario largo. */
.modal__cuerpo { padding: var(--esp-5); overflow-y: auto; }

.modal__pie {
  display: flex; flex-wrap: wrap; gap: var(--esp-3); justify-content: flex-end;
  padding: var(--esp-4) var(--esp-5);
  border-top: 1px solid var(--color-borde-suave);
  background: var(--color-superficie-alt);
}

/* Dos columnas de formulario desde tablet; una sola en telefono. */
.modal__rejilla { display: grid; gap: 0 var(--esp-4); grid-template-columns: 1fr; }
.modal__rejilla .campo--completo { grid-column: 1 / -1; }

@media (min-width: 560px) {
  .modal__rejilla { grid-template-columns: 1fr 1fr; }
}

@media (prefers-reduced-motion: no-preference) {
  .modal[open] { animation: modal-entrar .18s ease-out; }
  @keyframes modal-entrar {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
  }
}

/* --- Texto solo para lectores de pantalla --------------------------------
   Para el <caption> de una tabla y para encabezados de columna que no llevan
   rotulo visible (la de acciones). Se saca de la vista sin usar display:none ni
   visibility:hidden, que ademas lo esconderian del lector de pantalla. */
.visualmente-oculto {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- Tile en modo boton (tarjeta-filtro) ---------------------------------
   El mismo tile, pero pulsable: la cifra y el filtro son el mismo control. El
   estado seleccionado se marca con aria-pressed, y el CSS se cuelga de ese
   atributo en vez de una clase, para que no puedan quedar desincronizados. */
button.tile {
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
button.tile:hover { border-color: var(--color-borde-fuerte); }
button.tile:active { transform: translateY(1px); }

button.tile[aria-pressed="true"] {
  background: var(--color-marca-suave);
  border-color: var(--color-marca);
}
button.tile[aria-pressed="true"] .tile__cifra { color: var(--color-marca-fuerte); }
button.tile[aria-pressed="true"] .tile__rotulo,
button.tile[aria-pressed="true"] .tile__pie   { color: var(--color-marca-fuerte); opacity: .85; }

/* --- Interruptor ---------------------------------------------------------
   Un <input type="checkbox"> de verdad por debajo: conserva el teclado, el
   foco y el anuncio del lector de pantalla sin reimplementar nada. La casilla
   original no se esconde con display:none —eso la sacaria del orden de
   tabulacion— sino que se hace transparente encima del dibujo.

   Marcado:
     <label class="interruptor">
       <input type="checkbox" class="interruptor__campo" role="switch">
       <span class="interruptor__pista" aria-hidden="true"></span>
       <span class="interruptor__texto">Abre este dia</span>
     </label>
   El texto va SIEMPRE: un interruptor sin rotulo obliga a adivinar que apaga. */
.interruptor {
  display: inline-flex; align-items: center; gap: var(--esp-3);
  position: relative;
  /* 44px de alto: area tactil minima, aunque el dibujo mida menos. */
  min-height: 44px;
  cursor: pointer;
}

.interruptor__campo {
  position: absolute;
  width: 44px; height: 44px;
  margin: 0; left: 0;
  opacity: 0;
  cursor: pointer;
}

.interruptor__pista {
  flex-shrink: 0;
  width: 42px; height: 24px;
  border-radius: var(--radio-full);
  background: var(--color-borde-fuerte);
  position: relative;
  transition: background-color .15s ease;
}
.interruptor__pista::after {
  content: "";
  position: absolute;
  top: 3px; left: 3px;
  width: 18px; height: 18px;
  border-radius: var(--radio-full);
  background: var(--color-superficie);
  box-shadow: var(--sombra-sm);
  transition: transform .15s ease;
}

.interruptor__campo:checked + .interruptor__pista { background: var(--color-marca); }
.interruptor__campo:checked + .interruptor__pista::after { transform: translateX(18px); }
.interruptor__campo:disabled + .interruptor__pista { opacity: .5; }
.interruptor__campo:disabled ~ .interruptor__texto { color: var(--color-texto-suave); }
.interruptor__campo:focus-visible + .interruptor__pista {
  outline: 2px solid var(--color-marca);
  outline-offset: 2px;
}

.interruptor__texto { font-size: var(--texto-sm); }

@media (prefers-reduced-motion: reduce) {
  .interruptor__pista, .interruptor__pista::after { transition: none; }
}

/* --- Cuadricula de horario -----------------------------------------------
   Los siete dias de la semana con su interruptor y sus horas. Se usa en el
   horario de la sucursal y servira igual para el del profesional, que ademas
   lleva descansos.

   En telefono cada dia es una tarjeta apilada; desde 620px pasa a cuadricula
   con el dia, el interruptor y las dos horas en una linea. */
.horario { display: flex; flex-direction: column; gap: var(--esp-3); }

.horario__dia {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--esp-2);
  padding: var(--esp-3);
  border: 1px solid var(--color-borde);
  border-radius: var(--radio-md);
  background: var(--color-superficie-alt);
}

/* El dia cerrado se apaga entero, no solo sus campos: de un vistazo se ve
   cuantos dias abre la sucursal sin leer cada fila. */
.horario__dia[data-abierto="false"] .horario__horas { opacity: .45; }

.horario__nombre { font-size: var(--texto-sm); font-weight: 500; }

.horario__horas { display: flex; align-items: center; gap: var(--esp-2); flex-wrap: wrap; }
.horario__horas .campo { margin-bottom: 0; }
.horario__horas .campo__control { min-height: 40px; padding: var(--esp-2) var(--esp-3); width: auto; }
.horario__separador { color: var(--color-texto-suave); font-size: var(--texto-sm); }

/* "Copiar en todos": evita configurar siete dias a mano. Va en la fila del
   primer dia, que es de donde se copia. */
.horario__copiar { margin-left: auto; }

@media (min-width: 620px) {
  .horario__dia {
    grid-template-columns: 7.5rem auto 1fr;
    align-items: center;
    gap: var(--esp-4);
  }
}

/* Nota explicativa bajo un rotulo de seccion, dentro de un formulario. Sube
   sobre el margen del rotulo para que se lean como un solo bloque. */
.rotulo__nota {
  font-size: var(--texto-xs);
  color: var(--color-texto-suave);
  margin: calc(var(--esp-3) * -1) 0 var(--esp-3);
}

/* --- Fila de agrupacion dentro de una tabla ------------------------------
   Encabezado de grupo que abarca todas las columnas: "Casa Matriz — 3 bodegas".
   Agrupar el listado por su padre es mas legible que repetir el nombre del padre
   en cada fila, y permite colgar del grupo un dato que es del padre y no de la
   fila (cuantas hay, si le falta alguna).

   Va como <tr> con un solo <th scope="colgroup"> para que el lector de pantalla
   lo anuncie como lo que es y no como una fila de datos mas. */
.tabla__grupo th {
  padding: var(--esp-3) var(--esp-4);
  background: var(--color-superficie-alt);
  border-bottom: 1px solid var(--color-borde);
  border-top: 1px solid var(--color-borde);
  font-size: var(--texto-sm);
  font-weight: 600;
  text-align: left;
}
.tabla tbody tr.tabla__grupo:hover th { background: var(--color-superficie-alt); }

.tabla__grupo-caja { display: flex; align-items: center; gap: var(--esp-3); flex-wrap: wrap; }
.tabla__grupo-dato { font-weight: 400; color: var(--color-texto-suave); font-size: var(--texto-xs); }

/* --- Regla con explicacion -----------------------------------------------
   Interruptor de configuracion que necesita decir QUE CAMBIA al activarlo.
   El rotulo nombra la regla; la ayuda cuenta la consecuencia. Las reglas de la
   agenda lo necesitan: "Reservas sobrepuestas" a secas no dice que solo vale
   para la recepcion y nunca para la reserva por internet.

     <div class="reglas">
       <div class="regla">
         <label class="interruptor">…<span class="interruptor__texto">Rotulo</span></label>
         <p class="regla__ayuda" id="x-ayuda">Que pasa si se activa.</p>
       </div>
     </div>
   El input lleva aria-describedby a la ayuda, para que el lector la lea junto
   con el rotulo y no como un parrafo suelto. */
.reglas { display: flex; flex-direction: column; }

.regla {
  padding: var(--esp-3) 0;
  border-bottom: 1px solid var(--color-borde-suave);
}
.regla:last-child { border-bottom: 0; }

.regla__ayuda {
  margin: 0 0 0 calc(42px + var(--esp-3));   /* alineada con el rotulo, no con la pista */
  font-size: var(--texto-xs);
  color: var(--color-texto-suave);
  max-width: 62ch;
}

/* --- Vista previa de logo ------------------------------------------------
   El logo se monta sobre una pastilla clara en ambos temas: casi todo logo
   viene dibujado sobre blanco, y sobre la superficie indigo del tema oscuro
   quedaria un rectangulo blanco sin forma. Con la pastilla se ve intencional. */
.vista-logo {
  display: grid;
  place-items: center;
  width: 100%;
  max-width: 280px;
  aspect-ratio: 16 / 9;
  padding: var(--esp-4);
  border-radius: var(--radio-md);
  background: var(--color-pastilla-logo);
  border: 1px solid var(--color-borde);
}
.vista-logo img { max-width: 100%; max-height: 100%; object-fit: contain; }

/* Sin logo: el hueco se explica en vez de quedar como una caja vacia. */
.vista-logo__vacio {
  font-size: var(--texto-sm);
  color: var(--color-texto-suave);
  text-align: center;
}
.vista-logo:has(.vista-logo__vacio) { background: var(--color-superficie-alt); border-style: dashed; }

.logo-acciones { display: flex; flex-wrap: wrap; gap: var(--esp-3); align-items: center; margin-top: var(--esp-4); }

/* --- Arbol de permisos ---------------------------------------------------
   Modulo > pantalla > control, con una casilla por nodo. La sangria la marca
   una linea vertical tenue: con tres niveles, sin ella no se sabe a quien
   pertenece un control al final de una lista larga.

     <ul class="arbol">
       <li class="arbol__nodo" data-tipo="modulo">
         <div class="arbol__fila">
           <label class="arbol__marca">
             <input class="arbol__casilla" type="checkbox">
             <span class="arbol__nombre">Configuracion</span>
           </label>
           <details class="arbol__detalle"><summary>Que permite</summary><p>…</p></details>
           <span class="arbol__nota">Usted no lo tiene: no puede concederlo.</span>
         </div>
         <ul class="arbol__hijos">…</ul>
       </li>
     </ul>

   La descripcion va plegada en <details>: son largas a proposito (las lee
   quien decide si concede) y desplegadas todas juntas el arbol no se recorre. */
.arbol, .arbol__hijos { list-style: none; margin: 0; padding: 0; }

.arbol__hijos {
  margin-left: calc(var(--esp-3) + 2px);
  padding-left: var(--esp-4);
  border-left: 1px solid var(--color-borde);
}

.arbol__nodo[data-tipo="modulo"] + .arbol__nodo[data-tipo="modulo"] {
  margin-top: var(--esp-2);
  padding-top: var(--esp-2);
  border-top: 1px solid var(--color-borde-suave);
}

.arbol__fila {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0 var(--esp-3);
}

.arbol__marca {
  display: inline-flex; align-items: center; gap: var(--esp-3);
  min-height: 44px;              /* area tactil, aunque la casilla mida menos */
  cursor: pointer;
}
.arbol__casilla {
  width: 20px; height: 20px; margin: 0;
  accent-color: var(--color-marca);
  cursor: pointer;
}
.arbol__casilla:disabled, .arbol__casilla:disabled + .arbol__nombre { cursor: not-allowed; }
.arbol__casilla:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 2px; }

.arbol__nombre { font-size: var(--texto-sm); }
.arbol__nodo[data-tipo="modulo"] > .arbol__fila .arbol__nombre { font-weight: 600; font-size: var(--texto-base); }
.arbol__nodo[data-tipo="control"] > .arbol__fila .arbol__nombre { color: var(--color-texto-suave); }

.arbol__detalle { font-size: var(--texto-xs); color: var(--color-texto-suave); }
.arbol__detalle summary {
  cursor: pointer;
  min-height: 32px; display: inline-flex; align-items: center;
  padding: 0 var(--esp-2);
  border-radius: var(--radio-full);
}
.arbol__detalle summary:hover { background: var(--color-superficie-alt); color: var(--color-texto); }
.arbol__detalle summary:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 1px; }
.arbol__detalle[open] { flex-basis: 100%; }
.arbol__detalle p {
  margin: 0 0 var(--esp-3) calc(20px + var(--esp-3));
  max-width: 70ch;
  line-height: 1.5;
}

/* Por que una casilla esta bloqueada: se dice al lado, no con un title que en
   un telefono no se ve. */
.arbol__nota { font-size: var(--texto-xs); color: var(--color-aviso); }
.arbol__nota--neutra { color: var(--color-texto-suave); }

/* Resumen fijo sobre el arbol: cuanto queda concedido mientras se marca. */
.arbol-resumen {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-2) var(--esp-4);
  margin-bottom: var(--esp-4);
  font-size: var(--texto-sm);
  color: var(--color-texto-suave);
}
.arbol-resumen .acciones { margin-left: auto; }

/* --- Selector con busqueda (combobox) ------------------------------------
   Para elegir UN registro de una tabla grande (el tutor de una mascota), donde
   un <select> con miles de opciones no sirve. Patron ARIA combobox: el input
   lleva role="combobox", aria-expanded y aria-activedescendant; la lista,
   role="listbox". Con el valor elegido, el input se reemplaza por una ficha
   con "Cambiar", para que no se confunda "lo que escribi" con "lo que elegi".

     <div class="selector">
       <input class="campo__control" role="combobox" aria-controls="x-lista" aria-expanded="false">
       <ul class="selector__lista" id="x-lista" role="listbox" hidden>
         <li class="selector__opcion" role="option" id="x-op-1" aria-selected="false">
           <span class="selector__principal">Ana Rojas</span>
           <span class="selector__dato">12.345.678-5 · +56 9…</span>
         </li>
       </ul>
       <div class="selector__elegido" hidden>…nombre… <button>Cambiar</button></div>
     </div> */
.selector { position: relative; }

.selector__lista {
  position: absolute; z-index: 20;
  top: calc(100% + var(--esp-1)); left: 0; right: 0;
  max-height: 16rem; overflow-y: auto;
  margin: 0; padding: var(--esp-1);
  list-style: none;
  background: var(--color-superficie);
  border: 1px solid var(--color-borde);
  border-radius: var(--radio-campo);
  box-shadow: var(--sombra-md);
}

.selector__opcion {
  display: flex; flex-direction: column;
  min-height: 44px; justify-content: center;
  padding: var(--esp-2) var(--esp-3);
  border-radius: var(--radio-sm);
  cursor: pointer;
}
.selector__opcion:hover,
.selector__opcion[aria-selected="true"] { background: var(--color-marca-suave); }
.selector__opcion--vacia { cursor: default; color: var(--color-texto-suave); font-size: var(--texto-sm); }
.selector__opcion--vacia:hover { background: transparent; }

.selector__principal { font-size: var(--texto-sm); font-weight: 500; }
.selector__dato { font-size: var(--texto-xs); color: var(--color-texto-suave); }

.selector__elegido {
  display: flex; align-items: center; gap: var(--esp-3); flex-wrap: wrap;
  min-height: 48px;
  padding: var(--esp-2) var(--esp-3);
  border-radius: var(--radio-campo);
  background: var(--color-marca-suave);
}
.selector__elegido .selector__principal { color: var(--color-marca-fuerte); }
.selector__elegido .boton { margin-left: auto; }

/* --- Alerta clinica ------------------------------------------------------
   Alergias y advertencias de manejo ("muerde"). Son datos de SEGURIDAD: van a
   la vista en el listado y en toda cabecera de paciente. Llevan icono y texto,
   nunca solo color. */
.alerta-clinica {
  display: inline-flex; align-items: flex-start; gap: var(--esp-1);
  margin-top: var(--esp-1);
  padding: 2px var(--esp-2);
  border-radius: var(--radio-sm);
  font-size: var(--texto-xs);
  background: var(--color-aviso-fondo);
  color: var(--color-aviso);
  max-width: 100%;
  overflow-wrap: anywhere;
}
.alerta-clinica--alergia { background: var(--color-error-fondo); color: var(--color-error); }
.alerta-clinica .icono { flex-shrink: 0; margin-top: 1px; }

/* Grupo de campos con <fieldset> + <legend> (la semantica correcta para "estos
   controles responden una misma pregunta"), sin el marco que el navegador le
   pone por defecto. min-width: 0 evita que un fieldset ensanche la rejilla. */
fieldset.campo--sin-borde { border: 0; padding: 0; margin: 0 0 var(--esp-4); min-width: 0; }
fieldset.campo--sin-borde > legend { padding: 0; margin-bottom: var(--esp-2); }

/* --- Cabecera de paciente ------------------------------------------------
   Identidad del paciente arriba de todo lo clinico, con sus alertas a la vista.
   Va en toda pantalla que trabaje sobre un paciente (ficha, agenda, caja). */
.cabecera-paciente { display: grid; gap: var(--esp-4); grid-template-columns: 1fr; }
.cabecera-paciente__nombre { font-size: var(--texto-xl); font-weight: 600; margin: 0; letter-spacing: -.02em; }
.cabecera-paciente__datos { font-size: var(--texto-sm); color: var(--color-texto-suave); margin: var(--esp-1) 0 0; }
.cabecera-paciente__alertas { display: flex; flex-wrap: wrap; gap: var(--esp-2); }
.cabecera-paciente__identidad { display: flex; align-items: flex-start; gap: var(--esp-3); }
/* Firma del profesional estampada en una atencion cerrada (0070): en la ficha y en la impresion. */
.firma-impresa { display: inline-flex; flex-direction: column; gap: var(--esp-1); margin-top: var(--esp-3); font-size: var(--texto-sm); color: var(--color-texto-suave); }
.firma-impresa img, img.firma-impresa { width: auto; max-width: 15rem; height: auto; max-height: 7.5rem; border-bottom: 1px solid var(--color-borde-fuerte); background: #fff; }
/* Foto del paciente: cuadrada (la genera el sistema en 400 px), recortada en circulo. */
.foto-paciente { width: 4.5rem; height: 4.5rem; flex-shrink: 0; border-radius: 50%; object-fit: cover; background: var(--color-superficie-alt); }
.foto-paciente--grande { width: 7rem; height: 7rem; }
@media (min-width: 760px) {
  .cabecera-paciente { grid-template-columns: 1fr auto; align-items: start; }
}

/* --- Linea de tiempo clinica ---------------------------------------------
   Una tarjeta por atencion, la mas reciente arriba. El estado (borrador,
   cerrada, anulada) va con texto; la anulada se atenua entera pero sigue
   legible: anulada no es borrada. */
.linea-tiempo { display: flex; flex-direction: column; gap: var(--esp-4); margin-top: var(--esp-4); }

.atencion {
  background: var(--color-superficie);
  border: 1px solid var(--color-borde-suave);
  border-radius: var(--radio-lg);
  box-shadow: var(--sombra-sm);
  padding: var(--esp-4) var(--esp-5);
  min-width: 0;
}
.atencion[data-estado="borrador"] { border-style: dashed; border-color: var(--color-borde-fuerte); }
.atencion[data-estado="anulada"] > :not(.atencion__cabecera):not(.atencion__anulacion) { opacity: .6; }

.atencion__cabecera { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--esp-2) var(--esp-3); }
.atencion__fecha { font-weight: 600; }
.atencion__quien { font-size: var(--texto-sm); color: var(--color-texto-suave); }
.atencion__motivo { margin: var(--esp-2) 0 0; font-size: var(--texto-base); }

.atencion__seccion { margin-top: var(--esp-3); }
.atencion__seccion h4 {
  margin: 0 0 var(--esp-1);
  font-size: var(--texto-xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--color-texto-suave);
}
.atencion__seccion p { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; font-size: var(--texto-sm); }

.atencion__anulacion {
  margin-top: var(--esp-3); padding: var(--esp-2) var(--esp-3);
  border-radius: var(--radio-sm);
  background: var(--color-error-fondo); color: var(--color-error);
  font-size: var(--texto-sm);
}

.atencion__adendas { margin-top: var(--esp-3); padding-left: var(--esp-3); border-left: 2px solid var(--color-marca-suave); }
.adenda { margin: 0 0 var(--esp-2); font-size: var(--texto-sm); }
.adenda__meta { display: block; font-size: var(--texto-xs); color: var(--color-texto-suave); }

.atencion__acciones { margin-top: var(--esp-3); display: flex; flex-wrap: wrap; gap: var(--esp-2); justify-content: flex-end; }

/* Signos vitales en fila: cifra grande con su unidad, y el rotulo abajo. */
.signos {
  display: grid; gap: var(--esp-2);
  grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));
  margin-top: var(--esp-3);
}
.signo { padding: var(--esp-2) var(--esp-3); border-radius: var(--radio-sm); background: var(--color-superficie-alt); }
.signo__valor { display: block; font-weight: 600; font-variant-numeric: tabular-nums; }
.signo__rotulo { display: block; font-size: var(--texto-xs); color: var(--color-texto-suave); }

/* --- Curva de peso -------------------------------------------------------
   Una sola serie: linea de 2px y marcadores de 8px en el color de marca, grilla
   y ejes recesivos. El tooltip es HTML (no <title>) para que se vea igual con
   mouse, teclado y en el tema oscuro. */
.curva { position: relative; width: 100%; }
.curva svg { display: block; width: 100%; height: auto; overflow: visible; color: var(--color-marca); }
.curva__grilla { stroke: var(--color-borde-suave); stroke-width: 1; }
.curva__eje { fill: var(--color-texto-suave); font-size: 11px; font-variant-numeric: tabular-nums; }
.curva__linea { fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.curva__punto { fill: currentColor; stroke: var(--color-superficie); stroke-width: 2; }
.curva__blanco { fill: transparent; cursor: pointer; }
.curva__blanco:focus-visible { outline: none; }
.curva__blanco:focus-visible + .curva__punto,
.curva__blanco:hover + .curva__punto { r: 6; }
.curva__tooltip {
  position: absolute; pointer-events: none; transform: translate(-50%, calc(-100% - 10px));
  padding: var(--esp-1) var(--esp-2);
  border-radius: var(--radio-sm);
  background: var(--color-texto); color: var(--color-superficie);
  font-size: var(--texto-xs); white-space: nowrap;
}

/* --- Formula visible ------------------------------------------------------
   Un calculo mostrado con sus operadores entre los terminos:
     Apertura + Ventas + Otros ingresos − Egresos = Resultado
   Hace auditable el total de un vistazo: nadie tiene que deducir de donde sale.
   En telefono los terminos se apilan y el operador queda a la izquierda de
   cada uno; desde 760px van en una fila. */
.formula {
  display: flex; flex-direction: column; gap: var(--esp-2);
  margin: 0; padding: 0; list-style: none;
}
.formula__termino {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--esp-3);
  padding: var(--esp-3) var(--esp-4);
  border-radius: var(--radio-md);
  background: var(--color-superficie-alt);
}
.formula__operador {
  flex-shrink: 0; width: 1.25rem;
  font-weight: 600; font-size: var(--texto-lg);
  color: var(--color-texto-suave);
  text-align: center;
}
.formula__rotulo { flex: 1 1 auto; font-size: var(--texto-sm); color: var(--color-texto-suave); }
.formula__valor { font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.formula__termino--total { background: var(--color-marca-suave); }
.formula__termino--total .formula__valor,
.formula__termino--total .formula__rotulo { color: var(--color-marca-fuerte); }

@media (min-width: 760px) {
  .formula { flex-direction: row; align-items: stretch; }
  .formula__termino {
    flex: 1 1 0; flex-direction: column; align-items: flex-start; justify-content: flex-start;
    position: relative; padding-left: var(--esp-5);
  }
  .formula__operador { position: absolute; left: calc(var(--esp-2) * -1 - .6rem); top: 50%; transform: translateY(-50%); }
  .formula__termino + .formula__termino { margin-left: var(--esp-3); }
  .formula__termino:first-child .formula__operador { display: none; }
}

/* Descanso dentro de un dia del horario (profesionales). Va en la misma caja
   de horas, en su propia linea, con rotulo: "Descanso 13:00 a 14:00". Un dia
   que la sucursal no abre muestra el motivo en vez de los controles. */
.horario__descanso {
  display: flex; align-items: center; gap: var(--esp-2); flex-wrap: wrap;
  flex-basis: 100%;
  font-size: var(--texto-sm); color: var(--color-texto-suave);
}
.horario__descanso .campo { margin-bottom: 0; }
.horario__descanso .campo__control { min-height: 40px; padding: var(--esp-2) var(--esp-3); width: auto; }
.horario__cerrado { font-size: var(--texto-sm); color: var(--color-texto-suave); }

/* --- Agenda del dia -------------------------------------------------------
   Una columna por profesional y una de horas. La altura sale de los minutos
   del dia (--agenda-px-min por minuto): la cita se posiciona con top/height
   calculados en el TS a partir de sus minutos, que es un dato, no un estilo.
   Lo ancho vive en .agenda-caja con scroll horizontal propio: la pagina nunca
   se desplaza de lado. */
.agenda-caja {
  overflow-x: auto;
  background: var(--color-superficie);
  border: 1px solid var(--color-borde-suave);
  border-radius: var(--radio-lg);
  box-shadow: var(--sombra-sm);
}
.agenda {
  --agenda-px-min: 1.6px;
  display: grid;
  grid-template-columns: 3.5rem repeat(var(--agenda-columnas, 1), minmax(11rem, 1fr));
  min-width: min-content;
}
.agenda__cabecera {
  position: sticky; top: 0; z-index: 3;
  padding: var(--esp-3) var(--esp-2);
  background: var(--color-superficie);
  border-bottom: 1px solid var(--color-borde);
  font-size: var(--texto-sm); font-weight: 600;
  text-align: center;
  overflow-wrap: anywhere;
}
.agenda__cabecera small { display: block; font-weight: 400; color: var(--color-texto-suave); font-size: var(--texto-xs); }
.agenda__cuerpo { position: relative; border-left: 1px solid var(--color-borde-suave); }
.agenda__horas { position: relative; }
.agenda__hora {
  position: absolute; right: var(--esp-2); transform: translateY(-50%);
  font-size: var(--texto-xs); color: var(--color-texto-suave); font-variant-numeric: tabular-nums;
}
.agenda__linea { position: absolute; left: 0; right: 0; border-top: 1px solid var(--color-borde-suave); }

/* Tiempo en que no se ofrece: fuera de jornada, descanso, bloqueo. Rayado
   tenue y con texto cuando cabe: nunca solo el color. */
.agenda__franja {
  position: absolute; left: 0; right: 0;
  background: repeating-linear-gradient(135deg, var(--color-superficie-alt) 0 6px, transparent 6px 12px);
  font-size: var(--texto-xs); color: var(--color-texto-suave);
  padding: var(--esp-1) var(--esp-2);
  overflow: hidden;
}
.agenda__franja--bloqueo { background: var(--color-aviso-fondo); color: var(--color-aviso); cursor: pointer; border: 0; text-align: left; font: inherit; font-size: var(--texto-xs); }
.agenda__franja--bloqueo:focus-visible { outline: 2px solid var(--color-marca); outline-offset: -2px; }

.agenda__cita {
  position: absolute; left: var(--esp-1); right: var(--esp-1);
  display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  padding: var(--esp-1) var(--esp-2);
  border: 0; border-left: 4px solid var(--color-marca);
  border-radius: var(--radio-sm);
  background: var(--color-marca-suave); color: var(--color-texto);
  font: inherit; font-size: var(--texto-xs); text-align: left;
  overflow: hidden; cursor: pointer;
  box-shadow: var(--sombra-sm);
}
.agenda__cita:hover { filter: brightness(.97); }
.agenda__cita:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 1px; z-index: 2; }
.agenda__cita strong { font-size: var(--texto-sm); font-weight: 600; }
.agenda__cita[data-estado="confirmada"] { border-left-color: var(--color-exito); background: var(--color-exito-fondo); }
.agenda__cita[data-estado="asistio"]    { border-left-color: var(--color-texto-suave); background: var(--color-superficie-alt); }
.agenda__cita[data-estado="no_asistio"] { border-left-color: var(--color-error); background: var(--color-error-fondo); }
.agenda__cita[data-estado="pendiente"]  { border-left-color: var(--color-aviso); background: var(--color-aviso-fondo); }
.agenda__cita[data-estado="cancelada"]  { border-left-style: dashed; border-left-color: var(--color-borde-fuerte); background: var(--color-superficie); opacity: .7; text-decoration: line-through; }
/* Dos citas que se pisan (excepcion "sobrepuesta"): la segunda se corre para
   que ambas se vean. */
.agenda__cita[data-carril="1"] { left: 50%; }
.agenda__cita[data-carril="0"][data-compartida="true"] { right: 50%; }

.agenda__ahora { position: absolute; left: 0; right: 0; border-top: 2px solid var(--color-error); z-index: 2; pointer-events: none; }
.agenda__ahora::before {
  content: attr(data-hora);
  position: absolute; left: var(--esp-1); top: -.9rem;
  font-size: var(--texto-xs); font-weight: 600; color: var(--color-error);
  background: var(--color-superficie); padding: 0 var(--esp-1); border-radius: var(--radio-sm);
}

/* Navegacion de fecha de la agenda. */
.agenda-nav { display: flex; align-items: center; gap: var(--esp-2); flex-wrap: wrap; }
.agenda-nav__fecha { font-weight: 600; font-size: var(--texto-lg); margin: 0 var(--esp-2); }

/* Horas libres ofrecidas al agendar: botones-pastilla. */
.horas-libres { display: flex; flex-wrap: wrap; gap: var(--esp-2); }
.horas-libres .boton[aria-pressed="true"] { background: var(--color-marca); color: var(--color-marca-contraste); border-color: var(--color-marca); }

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

/* Vista semana: la misma rejilla, una columna por dia. La cabecera es un boton
   que abre ese dia en la vista dia. */
.agenda--semana .agenda__cabecera { padding: 0; }
.agenda__dia {
  display: block; width: 100%; min-height: 44px;
  padding: var(--esp-2) var(--esp-3);
  background: none; border: 0; font: inherit; font-weight: 600; color: inherit; text-align: left; cursor: pointer;
}
.agenda__dia:hover { color: var(--color-marca-fuerte); }
.agenda__dia:focus-visible { outline: 2px solid var(--color-marca); outline-offset: -2px; }
.agenda__dia[aria-current="date"] { color: var(--color-marca-fuerte); }
.agenda--semana .agenda__cita strong { font-size: var(--texto-xs); }
.agenda__cita[draggable="true"] { cursor: grab; }
.agenda__cita[draggable="true"]:active { cursor: grabbing; }

/* Selector de vista (Dia / Semana / Lista) y profesional de la semana. */
.agenda-vistas { display: flex; align-items: center; gap: var(--esp-2); flex-wrap: wrap; }
.agenda-vistas .boton[aria-pressed="true"] { background: var(--color-marca); color: var(--color-marca-contraste); border-color: var(--color-marca); }
.agenda-vistas .campo__control { width: auto; min-width: 12rem; }
.agenda-lista__fila { cursor: pointer; }
.agenda-lista__fila:hover td { background: var(--color-superficie-alt); }

/* Vista mes: rejilla de 7 columnas; cada dia es un boton con sus cifras.
   "Cerrado" y "Con bloqueo" van escritos, no solo en color. */
.calendario-mes {
  display: grid; gap: var(--esp-1);
  background: var(--color-superficie);
  border: 1px solid var(--color-borde-suave);
  border-radius: var(--radio-lg);
  box-shadow: var(--sombra-sm);
  padding: var(--esp-2);
  overflow-x: auto;
}
.calendario-mes__fila { display: grid; grid-template-columns: repeat(7, minmax(2.75rem, 1fr)); gap: var(--esp-1); }
.calendario-mes__nombre { font-size: var(--texto-xs); font-weight: 600; color: var(--color-texto-suave); text-align: center; padding: var(--esp-1) 0; }
.calendario-mes__dia {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  min-height: 4.5rem; padding: var(--esp-2);
  background: var(--color-superficie-alt); border: 1px solid transparent; border-radius: var(--radio-sm);
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.calendario-mes__dia:hover { border-color: var(--color-marca); }
.calendario-mes__dia:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 1px; }
.calendario-mes__dia[data-abre="false"] { background: var(--color-superficie); color: var(--color-texto-suave); }
.calendario-mes__dia[aria-current="date"] { border-color: var(--color-marca); box-shadow: inset 0 0 0 1px var(--color-marca); }
.calendario-mes__numero { font-weight: 600; }
.calendario-mes__citas { font-size: var(--texto-sm); color: var(--color-marca-fuerte); font-weight: 600; }
.calendario-mes__nota { font-size: var(--texto-xs); color: var(--color-texto-suave); }

/* Apoyo de la agenda: dos meses para saltar a una fecha y el enlace de reservas con Copiar. */
.agenda-apoyo { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--esp-3) var(--esp-4); margin-bottom: var(--esp-3); }
.agenda-enlace { flex: 1 1 18rem; margin: 0; }
.agenda-meses > summary { list-style: none; }
.agenda-meses > summary::-webkit-details-marker { display: none; }
/* "Configurar horario" dentro de la columna de un profesional que no atiende ese dia. */
.agenda__configurar { position: absolute; left: var(--esp-2); right: var(--esp-2); z-index: 1; justify-content: center; }
.mini-meses { display: flex; flex-wrap: wrap; gap: var(--esp-4); margin-top: var(--esp-2); padding: var(--esp-3);
  background: var(--color-superficie); border-radius: var(--radio-lg); box-shadow: var(--sombra-sm); }
.mini-mes { border-collapse: separate; border-spacing: 2px; }
.mini-mes caption { font-weight: 600; text-transform: capitalize; padding-bottom: var(--esp-1); }
.mini-mes th { font-size: var(--texto-xs); font-weight: 600; color: var(--color-texto-suave); text-align: center; }
.mini-mes__dia {
  width: 2.75rem; height: 2.75rem; border: 0; border-radius: var(--radio-full);
  background: transparent; color: inherit; font: inherit; font-variant-numeric: tabular-nums; cursor: pointer;
}
.mini-mes__dia:hover { background: var(--color-superficie-alt); }
.mini-mes__dia:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 1px; }
.mini-mes__dia[aria-current="date"] { box-shadow: inset 0 0 0 2px var(--color-marca); font-weight: 600; }
.mini-mes__dia[aria-pressed="true"] { background: var(--color-marca); color: var(--color-marca-contraste); }

/* Pantalla completa: la agenda en el monitor de recepcion. */
.agenda-pantalla:fullscreen { background: var(--color-fondo); padding: var(--esp-4); overflow: auto; }

@media print {
  .agenda-caja { overflow: visible; box-shadow: none; border: 0; }
  .agenda__ahora { display: none; }
}

/* =========================================================================
   Reserva por internet (sitio publico) — componentes reutilizables
   ========================================================================= */

/* Pasos de un flujo: el actual con aria-current="step". El numero lo pone el
   contador, asi el paso se entiende sin color. */
.pasos {
  display: flex; flex-wrap: wrap; gap: var(--esp-2);
  margin: 0; padding: 0; list-style: none;
  counter-reset: paso;
}
.pasos__paso {
  counter-increment: paso;
  display: inline-flex; align-items: center; gap: var(--esp-2);
  padding: var(--esp-1) var(--esp-3) var(--esp-1) var(--esp-1);
  border-radius: var(--radio-full);
  background: var(--color-superficie);
  color: var(--color-texto-suave);
  font-size: var(--texto-sm);
}
.pasos__paso::before {
  content: counter(paso);
  display: inline-grid; place-items: center;
  width: 1.75rem; height: 1.75rem;
  border-radius: var(--radio-full);
  background: var(--color-superficie-alt);
  font-weight: 600;
}
.pasos__paso[aria-current="step"] { color: var(--color-texto); font-weight: 600; box-shadow: var(--sombra-sm); }
.pasos__paso[aria-current="step"]::before { background: var(--color-marca); color: var(--color-marca-contraste); }
.pasos__paso[data-hecho="true"]::before { content: "✓"; background: var(--color-marca-suave); color: var(--color-marca-fuerte); }

/* Tira de dias: scroll horizontal propio, nunca el de la pagina. Un dia sin
   horas se ve, pero apagado Y con el texto "Sin horas". */
.tira-dias { display: flex; align-items: center; gap: var(--esp-2); margin-bottom: var(--esp-4); }
.tira-dias__lista {
  display: flex; gap: var(--esp-2);
  flex: 1; min-width: 0;
  overflow-x: auto;
  padding: var(--esp-1);
  scroll-snap-type: x proximity;
}
.dia {
  flex: 0 0 auto;
  display: grid; justify-items: center; gap: 2px;
  min-width: 4.25rem; min-height: 44px;
  padding: var(--esp-2) var(--esp-2);
  border: 1px solid var(--color-borde-fuerte);
  border-radius: var(--radio-md);
  background: var(--color-superficie);
  color: var(--color-texto);
  font: inherit; font-size: var(--texto-sm);
  cursor: pointer;
  scroll-snap-align: start;
}
.dia__semana { color: var(--color-texto-suave); font-size: var(--texto-xs); text-transform: capitalize; }
.dia__numero { font-size: var(--texto-lg); font-weight: 600; }
.dia__nota { font-size: var(--texto-xs); color: var(--color-texto-suave); }
.dia[aria-pressed="true"] { background: var(--color-marca); border-color: var(--color-marca); color: var(--color-marca-contraste); }
.dia[aria-pressed="true"] .dia__semana,
.dia[aria-pressed="true"] .dia__nota { color: var(--color-marca-contraste); }
.dia:disabled { background: var(--color-superficie-alt); border-color: var(--color-borde); color: var(--color-texto-suave); cursor: not-allowed; }
.dia:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 2px; }

/* Opciones grandes de eleccion unica (profesional, etc.): boton con aria-pressed. */
.opciones { display: grid; gap: var(--esp-2); }
.opcion {
  display: grid; gap: 2px; text-align: left;
  min-height: 44px;
  padding: var(--esp-3) var(--esp-4);
  border: 1px solid var(--color-borde-fuerte);
  border-radius: var(--radio-md);
  background: var(--color-superficie);
  color: var(--color-texto);
  font: inherit;
  cursor: pointer;
}
.opcion__titulo { font-weight: 600; }
.opcion__dato { font-size: var(--texto-sm); color: var(--color-texto-suave); }
.opcion--destacada { border-color: var(--color-marca); background: var(--color-marca-suave); }
.opcion[aria-pressed="true"] { border-color: var(--color-marca); box-shadow: inset 0 0 0 2px var(--color-marca); }
.opcion:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 2px; }

/* Tarjeta de servicio del catalogo publico. */
.servicios-publicos { display: grid; gap: var(--esp-3); margin-bottom: var(--esp-4); }
.servicio-publico {
  display: grid; gap: var(--esp-2);
  padding: var(--esp-4);
  border-radius: var(--radio-md);
  background: var(--color-superficie-alt);
}
.servicio-publico__nombre { margin: 0; font-size: var(--texto-lg); font-weight: 600; }
.servicio-publico__dato { color: var(--color-texto-suave); font-size: var(--texto-sm); }
.servicio-publico__descripcion { margin: 0; font-size: var(--texto-sm); }
.servicio-publico .boton { justify-self: start; }
@media (min-width: 640px) { .servicios-publicos { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Carrito del sitio de reservas: la tarjeta elegida se marca, el boton pasa a cantidad,
   y una barra flotante lleva el total y la accion sin perder el catalogo. */
.servicio-publico[data-en-carrito="true"] { box-shadow: inset 0 0 0 2px var(--color-marca); }
.cantidad { display: inline-flex; align-items: center; gap: var(--esp-2); justify-self: start; }
.cantidad__valor { min-width: 2ch; text-align: center; font-weight: 600; font-variant-numeric: tabular-nums; }
.barra-carrito {
  position: sticky; bottom: var(--esp-3); z-index: 5;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--esp-3);
  padding: var(--esp-3) var(--esp-4);
  border-radius: var(--radio-lg);
  background: var(--color-superficie);
  box-shadow: var(--sombra-lg);
}
.barra-carrito__texto { display: grid; gap: var(--esp-1); min-width: 0; }
.barra-carrito__detalle { overflow-wrap: anywhere; font-size: var(--texto-sm); }
.barra-carrito__total { font-weight: 600; font-variant-numeric: tabular-nums; }

/* Casilla de verificacion con area tactil de 44px (consentimientos, aceptar). */
.casilla { display: flex; align-items: flex-start; gap: var(--esp-3); min-height: 44px; font-size: var(--texto-sm); cursor: pointer; }
.casilla input { flex-shrink: 0; width: 1.25rem; height: 1.25rem; margin: 2px 0 0; accent-color: var(--color-marca); }
.casilla input:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 2px; }
/* Varias casillas cortas en fila (se envuelven en pantallas chicas). */
.casillas-en-linea { display: flex; flex-wrap: wrap; gap: 0 var(--esp-4); }

/* Ficha siempre en una columna (paneles angostos). */
.ficha--una { display: block; }
.ficha--una dd { margin: 0 0 var(--esp-3); }

/* =========================================================================
   Reportes — KPI con comparacion y graficos livianos (HTML/CSS, sin libreria)
   ========================================================================= */

/* Variacion frente al periodo anterior: flecha + signo + texto, nunca solo color.
   --buena / --mala las decide el TS segun si subir es bueno (reservas) o malo
   (inasistencias). --neutra cuando no hay contra que comparar. */
.variacion { display: inline-flex; align-items: center; gap: var(--esp-1); font-size: var(--texto-xs); font-weight: 600; }
.variacion--buena  { color: var(--color-exito); }
.variacion--mala   { color: var(--color-error); }
.variacion--neutra { color: var(--color-texto-suave); font-weight: 500; }

/* Filtros del reporte + la frase que verbaliza el rango. */
.filtros-reporte { display: grid; gap: var(--esp-3); grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); align-items: end; }
.rango-reporte { margin: var(--esp-2) 0 var(--esp-4); font-size: var(--texto-sm); color: var(--color-texto-suave); }

/* Leyenda: la muestra repite la FORMA de la serie (relleno / contorno). */
.leyenda { display: flex; flex-wrap: wrap; gap: var(--esp-4); margin: 0 0 var(--esp-3); padding: 0; list-style: none; font-size: var(--texto-xs); color: var(--color-texto-suave); }
.leyenda li { display: inline-flex; align-items: center; gap: var(--esp-2); }
.leyenda__muestra { width: .875rem; height: .875rem; border-radius: 3px; background: var(--color-grafico-actual); }
.leyenda__muestra--anterior { background: transparent; border: 2px solid var(--color-grafico-anterior); }

/* Barras horizontales: una fila por categoria, el valor escrito al lado. */
.barras { display: grid; gap: var(--esp-3); margin: 0; padding: 0; list-style: none; }
.barras__fila { display: grid; gap: var(--esp-1); }
.barras__cabeza { display: flex; justify-content: space-between; gap: var(--esp-3); font-size: var(--texto-sm); }
.barras__nombre { min-width: 0; overflow-wrap: anywhere; }
.barras__valor { flex-shrink: 0; font-weight: 600; }
.barras__pista { height: .5rem; border-radius: var(--radio-full); background: var(--color-superficie-alt); overflow: hidden; }
.barras__relleno { height: 100%; border-radius: var(--radio-full); background: var(--color-grafico-actual); }
.barras__pie { display: flex; gap: var(--esp-3); font-size: var(--texto-xs); color: var(--color-texto-suave); }

/* Columnas en el tiempo: scroll horizontal propio si no caben. */
.columnas-caja { overflow-x: auto; }
.columnas {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(1.25rem, 1fr);
  align-items: end; gap: var(--esp-1);
  height: 12rem; min-width: 100%;
  padding-top: var(--esp-2);
  border-bottom: 1px solid var(--color-borde);
}
.columnas__cubo { display: flex; align-items: flex-end; justify-content: center; gap: 2px; height: 100%; }
.columnas__barra { flex: 1; max-width: 1.25rem; min-height: 1px; border-radius: 4px 4px 0 0; background: var(--color-grafico-actual); }
.columnas__barra--anterior { background: transparent; border: 2px solid var(--color-grafico-anterior); border-bottom: 0; }
.columnas__ejes { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(1.25rem, 1fr); gap: var(--esp-1); min-width: 100%;
                  font-size: var(--texto-xs); color: var(--color-texto-suave); text-align: center; }
.columnas__ejes span { overflow: hidden; white-space: nowrap; }

/* Mapa de calor dia x hora. La intensidad la calcula el TS como --intensidad
   (0..1): es dato, no estilo. El numero va escrito en cada celda con valor. */
.mapa-calor-caja { overflow-x: auto; }
.mapa-calor { display: grid; grid-template-columns: 2.5rem repeat(var(--horas, 12), minmax(1.9rem, 1fr)); gap: 2px; min-width: max-content; font-size: var(--texto-xs); }
.mapa-calor__eje { display: grid; place-items: center; color: var(--color-texto-suave); padding: var(--esp-1); }
.mapa-calor__celda {
  display: grid; place-items: center; min-height: 1.9rem; border-radius: 4px;
  background: color-mix(in srgb, var(--color-grafico-actual) calc(var(--intensidad, 0) * 100%), var(--color-superficie-alt));
  color: var(--color-texto);
}
.mapa-calor__celda[data-fuerte="true"] { color: var(--color-marca-contraste); font-weight: 600; }

/* Variante por franjas (Precios inteligentes): filas = franjas de 2 h, columnas = dias.
   Las celdas son botones seleccionables; la seleccion se marca con borde punteado
   (no solo color) y el descuento va escrito. */
.mapa-calor--franjas { grid-template-columns: 5.75rem repeat(7, minmax(3.25rem, 1fr)); }
button.mapa-calor__celda {
  min-height: 44px; border: 0; padding: var(--esp-1); font: inherit; font-size: var(--texto-xs);
  cursor: pointer; display: grid; gap: 0; line-height: 1.2;
}
button.mapa-calor__celda:disabled { cursor: default; color: var(--color-texto-suave); }
button.mapa-calor__celda[aria-pressed="true"] { outline: 2px dashed var(--color-marca); outline-offset: -3px; }
.mapa-calor__descuento { font-weight: 700; }
.mapa-calor__eje--franja { justify-content: end; white-space: nowrap; }

/* =========================================================================
   Inicio — panel de widgets reordenables
   ========================================================================= */
.panel-widgets { display: grid; gap: var(--esp-4); grid-template-columns: minmax(0, 1fr); align-items: start; margin-top: var(--esp-4); }
@media (min-width: 900px) { .panel-widgets { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.widget { display: grid; gap: var(--esp-3); min-width: 0; }
.widget--ancho { grid-column: 1 / -1; }
.widget__cabecera { display: flex; align-items: center; justify-content: space-between; gap: var(--esp-2); }
.widget__acciones { display: flex; gap: var(--esp-1); }
.widget[data-oculto="true"] { opacity: .55; }
.widget[data-arrastrando="true"] { outline: 2px dashed var(--color-marca); outline-offset: 4px; }
.panel-widgets[data-personalizando="true"] .widget { cursor: grab; }
.widget__vacio { margin: 0; font-size: var(--texto-sm); color: var(--color-texto-suave); }

/* Horario de hoy: una fila por cita, hora grande a la izquierda. */
.lista-hoy { display: grid; gap: var(--esp-2); margin: 0; padding: 0; list-style: none; }
.lista-hoy__cita { display: grid; grid-template-columns: 4.5rem minmax(0, 1fr) auto; gap: var(--esp-3); align-items: center;
                   padding: var(--esp-2) var(--esp-3); border-radius: var(--radio-sm); background: var(--color-superficie-alt); }
.lista-hoy__hora { font-weight: 600; }
.lista-hoy__dato { font-size: var(--texto-xs); color: var(--color-texto-suave); }
.lista-hoy__cita[data-pasada="true"] { opacity: .7; }

/* "Para revisar": filas accionables con enlace. */
.lista-accion { display: grid; gap: var(--esp-2); margin: 0; padding: 0; list-style: none; }
.lista-accion a { display: grid; gap: 2px; min-height: 44px; padding: var(--esp-2) var(--esp-3); border-radius: var(--radio-sm);
                  background: var(--color-aviso-fondo); color: var(--color-texto); text-decoration: none; }
.lista-accion a:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 2px; }
.lista-accion__detalle { font-size: var(--texto-xs); color: var(--color-texto-suave); }

/* =========================================================================
   Arbol de permisos (catalogo) — lista anidada de nodos con acciones
   ========================================================================= */
.catalogo, .catalogo ul { margin: 0; padding: 0; list-style: none; }
.catalogo ul { margin-left: var(--esp-5); padding-left: var(--esp-3); border-left: 2px solid var(--color-borde); }
.nodo { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--esp-2);
        padding: var(--esp-2) var(--esp-3); margin: var(--esp-1) 0; border-radius: var(--radio-sm); background: var(--color-superficie-alt); }
.nodo--modulo { background: var(--color-marca-suave); }
.nodo[data-inactivo="true"] { opacity: .6; }
.nodo__texto { display: grid; gap: 2px; min-width: 0; }
.nodo__nombre { font-weight: 600; overflow-wrap: anywhere; }
.nodo__token { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: var(--texto-xs); color: var(--color-texto-suave); overflow-wrap: anywhere; }
.nodo__insignias { display: flex; flex-wrap: wrap; gap: var(--esp-1); }
.nodo__acciones { display: flex; flex-wrap: wrap; gap: var(--esp-1); }
.nodo__acciones .boton { min-height: 34px; padding: 0 var(--esp-3); font-size: var(--texto-xs); }

/* Encabezado de columna ordenable: boton con aspecto de encabezado. El th
   lleva aria-sort; la flecha va escrita (no solo como estilo). */
.tabla__orden { display: inline-flex; align-items: center; gap: var(--esp-1); min-height: 44px; padding: 0; border: 0;
                background: none; color: inherit; font: inherit; font-weight: inherit; cursor: pointer; }
.tabla__orden:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 2px; border-radius: var(--radio-sm); }
.tabla__flecha { color: var(--color-texto-suave); font-size: var(--texto-xs); }

/* Navegacion entre registros dentro de un modal (‹ ›). */
.modal__navegacion { display: inline-flex; gap: var(--esp-1); }

/* =========================================================================
   Pestanas (tablist accesible). La activa: aria-selected="true", ademas de
   la linea inferior (no solo color). Paneles con role="tabpanel" + hidden.
   ========================================================================= */
.pestanas { display: flex; gap: var(--esp-1); overflow-x: auto; margin: var(--esp-4) 0 var(--esp-3);
            border-bottom: 1px solid var(--color-borde); }
.pestanas__pestana { flex: 0 0 auto; min-height: 44px; padding: 0 var(--esp-4); border: 0; border-bottom: 3px solid transparent;
                     background: none; color: var(--color-texto-suave); font: inherit; font-weight: 500; cursor: pointer; }
.pestanas__pestana[aria-selected="true"] { color: var(--color-texto); font-weight: 600; border-bottom-color: var(--color-marca); }
.pestanas__pestana:focus-visible { outline: 2px solid var(--color-marca); outline-offset: -2px; border-radius: var(--radio-sm); }
.pestanas__cifra { margin-left: var(--esp-1); color: var(--color-texto-suave); font-size: var(--texto-xs); }

/* Cabecera de ficha de persona: avatar + nombre + datos en linea. */
.cabecera-ficha { display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-4); }
.cabecera-ficha__datos { display: flex; flex-wrap: wrap; gap: var(--esp-1) var(--esp-4); font-size: var(--texto-sm); color: var(--color-texto-suave); }

/* Lienzo de firma: el trazo se dibuja con el dedo, el lapiz o el mouse.
   touch-action: none para que dibujar no desplace la pagina en el telefono. */
.firma { display: grid; gap: var(--esp-2); }
.firma__lienzo { width: 100%; height: 11rem; border: 1px dashed var(--color-borde-fuerte); border-radius: var(--radio-md);
                 background: var(--color-papel); touch-action: none; cursor: crosshair; }
.firma__lienzo:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 2px; }
.firma__pie { display: flex; justify-content: space-between; align-items: center; gap: var(--esp-2); font-size: var(--texto-xs); color: var(--color-texto-suave); }

/* Vista previa de un PDF dentro de un modal (en telefono puede mostrar solo la
   primera pagina: por eso va siempre el enlace para abrirlo completo). */
.vista-pdf { width: 100%; height: 22rem; border: 1px solid var(--color-borde); border-radius: var(--radio-sm); background: var(--color-superficie-alt); }

/* -----------------------------------------------------------------------------
   Plantillas de ficha medica
   .constructor  editor plantilla > categoria > campo (Configuracion)
   .seccion-ficha  una seccion de plantilla dentro del formulario de atencion
   .respuestas   lo registrado en una seccion, en la linea de tiempo
   -------------------------------------------------------------------------- */
.constructor { display: grid; gap: var(--esp-4); }
.constructor__categoria {
  display: grid; gap: var(--esp-3);
  padding: var(--esp-4); border-radius: var(--radio-lg);
  background: var(--color-superficie-alt);
}
.constructor__cabeza { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--esp-2); }
.constructor__cabeza .campo { flex: 1 1 14rem; margin: 0; }
.constructor__campos { display: grid; gap: var(--esp-2); }
.constructor__campo {
  display: grid; gap: var(--esp-2);
  padding: var(--esp-3); border-radius: var(--radio-md);
  background: var(--color-superficie); box-shadow: var(--sombra-sm);
}
.constructor__campo .campo { margin: 0; }
.constructor__fila { display: grid; gap: var(--esp-2); grid-template-columns: 1fr; }
.constructor__botones { display: flex; flex-wrap: wrap; gap: var(--esp-1); align-items: center; }
@media (min-width: 48em) {
  .constructor__fila { grid-template-columns: 2fr 1.4fr 1fr; align-items: end; }
}

.seccion-ficha {
  padding: var(--esp-4); border-radius: var(--radio-lg);
  background: var(--color-superficie-alt);
  margin-bottom: var(--esp-4);
}
.seccion-ficha__cabeza { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--esp-2); margin-bottom: var(--esp-3); }
.seccion-ficha__titulo { margin: 0; font-size: var(--texto-base); font-weight: 600; }
.seccion-ficha__categoria { margin: var(--esp-3) 0 var(--esp-2); }

.respuestas { display: grid; gap: var(--esp-1) var(--esp-4); margin: 0; font-size: var(--texto-sm); }
.respuestas dt { color: var(--color-texto-suave); }
.respuestas dd { margin: 0 0 var(--esp-2); white-space: pre-wrap; overflow-wrap: anywhere; }
@media (min-width: 40em) {
  .respuestas { grid-template-columns: minmax(8rem, 14rem) 1fr; }
  .respuestas dd { margin: 0; }
}

/* -----------------------------------------------------------------------------
   Encuestas
   .editor-encuesta  configuracion a la izquierda, vista previa en vivo a la
                     derecha (una columna en telefono: la vista va debajo)
   .puntaje          respuesta en pildoras (escala 1-5, 0-10, si/no): radios
                     reales, asi funcionan con teclado y lector de pantalla
   -------------------------------------------------------------------------- */
.editor-encuesta { display: grid; gap: var(--esp-5); }
.editor-encuesta__vista {
  padding: var(--esp-4); border-radius: var(--radio-lg);
  background: var(--color-superficie-alt);
  align-self: start;
}
@media (min-width: 64em) {
  .editor-encuesta { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); }
  .editor-encuesta__vista { position: sticky; top: 0; }
}
.banco { display: grid; gap: var(--esp-2); }
.banco__dimension { border-radius: var(--radio-md); background: var(--color-superficie-alt); padding: var(--esp-2) var(--esp-3); }
.banco__dimension > summary { min-height: 44px; display: flex; align-items: center; cursor: pointer; font-weight: 600; font-size: var(--texto-sm); }
.banco__dimension > summary:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 2px; border-radius: var(--radio-sm); }

.pregunta-encuesta { border: 0; padding: 0; margin: 0 0 var(--esp-5); min-width: 0; }
.pregunta-encuesta > legend { padding: 0; margin-bottom: var(--esp-2); font-weight: 600; font-size: var(--texto-sm); }
.pregunta-encuesta__tema { display: block; font-weight: 400; font-size: var(--texto-xs); color: var(--color-texto-suave); }

.puntaje { display: flex; flex-wrap: wrap; gap: var(--esp-2); }
.puntaje__opcion { position: relative; }
.puntaje__opcion input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.puntaje__opcion span {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; padding: 0 var(--esp-3);
  border-radius: var(--radio-full);
  background: var(--color-superficie); box-shadow: var(--sombra-sm);
  font-weight: 600;
}
.puntaje__opcion input:checked + span { background: var(--color-marca); color: var(--color-marca-contraste); }
.puntaje__opcion input:focus-visible + span { outline: 2px solid var(--color-marca); outline-offset: 2px; }
.puntaje__opcion input:disabled { cursor: default; }
.puntaje__extremos { display: flex; justify-content: space-between; gap: var(--esp-2); margin-top: var(--esp-1); font-size: var(--texto-xs); color: var(--color-texto-suave); }

/* -----------------------------------------------------------------------------
   Comisiones
   .regla-comision  una fila del editor: nombre del item, valor y unidad (% / $)
   -------------------------------------------------------------------------- */
.regla-comision {
  display: grid; gap: var(--esp-2); align-items: end;
  grid-template-columns: 1fr;
  padding: var(--esp-2) 0; border-bottom: 1px solid var(--color-borde-suave);
}
.regla-comision .campo { margin: 0; }
.regla-comision__nombre { font-size: var(--texto-sm); font-weight: 500; align-self: center; }
.regla-comision--defecto { background: var(--color-superficie-alt); border-radius: var(--radio-md); padding: var(--esp-3); border-bottom: 0; margin-bottom: var(--esp-2); }
@media (min-width: 40em) {
  .regla-comision { grid-template-columns: minmax(0, 2fr) minmax(6rem, 1fr) minmax(6rem, 1fr) auto; }
}

/* -----------------------------------------------------------------------------
   Adjuntos de la ficha clinica
   .adjunto--anulado  tachado Y con la insignia "Anulado": nunca solo por color
   -------------------------------------------------------------------------- */
.adjuntos { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--esp-2); }
.adjunto { display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-1) var(--esp-3); font-size: var(--texto-sm); }
.adjunto__enlace { display: inline-flex; align-items: center; gap: var(--esp-1); min-height: 44px; font-weight: 500; overflow-wrap: anywhere; }
.adjunto__meta { color: var(--color-texto-suave); font-size: var(--texto-xs); }
.adjunto--anulado .adjunto__enlace { text-decoration: line-through; color: var(--color-texto-suave); }

/* Vista previa de un correo (campanas): iframe sandbox sin scripts, fondo del
   propio correo. Alto fijo con scroll interno: el correo puede ser largo. */
.vista-correo { width: 100%; height: 34rem; border: 0; border-radius: var(--radio-md); background: var(--color-papel); }

/* Vista previa de un mensaje de WhatsApp: una burbuja sobre un fondo de chat.
   Colores de tokens (exito-fondo como la burbuja propia); respeta saltos de linea. */
.vista-whatsapp { padding: var(--esp-4); border-radius: var(--radio-lg); background: var(--color-superficie-alt); }
.vista-whatsapp__burbuja {
  max-width: 22rem; margin-left: auto; padding: var(--esp-2) var(--esp-3); border-radius: var(--radio-md);
  background: var(--color-exito-fondo); color: var(--color-texto); white-space: pre-line; overflow-wrap: anywhere;
  font-size: var(--texto-sm); line-height: 1.45;
}
.vista-whatsapp__vacia { color: var(--color-texto-suave); font-style: italic; }
.variables-whatsapp { display: flex; flex-wrap: wrap; gap: var(--esp-1); }

/* Tarjeta plegable (<details class="tarjeta">): el resumen es el control. */
details.tarjeta > summary {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-2);
  min-height: 44px; cursor: pointer; border-radius: var(--radio-sm);
}
details.tarjeta > summary:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 2px; }
details.tarjeta[open] > summary { margin-bottom: var(--esp-3); }

/* Lista ordenable con botones (composicion de un paquete): numerada, cada fila con
   su texto, un dato secundario y acciones subir / bajar / quitar. */
.lista-orden { margin: var(--esp-2) 0 0; padding-left: var(--esp-6); display: grid; gap: var(--esp-2); }
.lista-orden:empty { display: none; }
.lista-orden__fila { display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-1) var(--esp-3); font-size: var(--texto-sm); }
.lista-orden__texto { font-weight: 500; overflow-wrap: anywhere; }
.lista-orden__dato { color: var(--color-texto-suave); font-size: var(--texto-xs); }
.lista-orden__acciones { display: flex; gap: var(--esp-1); margin-left: auto; }
.foto-paciente--chica { width: 34px; height: 34px; }

/* Bloque de codigo (documentacion de la API): monoespaciada, con su propio scroll
   horizontal para no ensanchar la pagina. */
.codigo {
  margin: var(--esp-2) 0;
  padding: var(--esp-3);
  overflow-x: auto;
  border-radius: var(--radio-md);
  background: var(--color-superficie-alt);
  color: var(--color-texto);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--texto-xs);
  line-height: 1.5;
  white-space: pre;
}

/* Comentarios internos de la ficha del cliente (0093): lista con autor y fecha; el anulado queda tachado. */
.comentarios { display: grid; gap: var(--esp-3); margin: var(--esp-4) 0 0; padding: 0; list-style: none; }
.comentarios__item { display: grid; gap: var(--esp-1); padding: var(--esp-3) var(--esp-4); border-radius: var(--radio-md); background: var(--color-superficie-alt); }
.comentarios__item p { margin: 0; white-space: pre-line; overflow-wrap: anywhere; }
.comentarios__item .boton { justify-self: start; }
.comentarios__item--anulado p { text-decoration: line-through; color: var(--color-texto-suave); }

/* Modo edicion del sitio de reservas: barra del equipo, visible solo para quien puede editar. */
.barra-editor {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--esp-2) var(--esp-4);
  padding: var(--esp-3) var(--esp-4); border-radius: var(--radio-lg);
  background: var(--color-aviso-fondo); color: var(--color-texto);
}
.editor-formulario { display: grid; gap: var(--esp-3); margin-top: var(--esp-2); }

/* Contador de caracteres y palabras (data-contador, src/armazon.ts). Cerca del tope lo dice en texto. */
.contador { display: block; margin-top: var(--esp-1); font-size: var(--texto-xs); color: var(--color-texto-suave); text-align: right; }
.contador--cerca { color: var(--color-aviso); font-weight: 600; }

/* Selector de pais delante de un telefono (data-pais, src/telefonoPais.ts). */
.campo__pais { flex: 0 0 auto; width: auto; max-width: 11rem; }


/* Imagen propia del diseño de una gift card (0108): certificado y catálogo público. */
.certificado__imagen, .catalogo-publico__imagen {
  display: block; width: 100%; height: auto; margin-bottom: var(--esp-3); border-radius: var(--radio-md);
}

/* Familia de un perfil (0109): pastilla con el NOMBRE del perfil (texto, nunca solo color). */
.familia { display: inline-flex; align-items: center; padding: var(--esp-1) var(--esp-2); border-radius: var(--radio-full);
  font-size: var(--texto-xs); font-weight: 600; }
.familia--administracion { background: var(--color-familia-admin-fondo); color: var(--color-familia-admin); }
.familia--recepcion      { background: var(--color-familia-recepcion-fondo); color: var(--color-familia-recepcion); }
.familia--staff          { background: var(--color-familia-staff-fondo); color: var(--color-familia-staff); }

/* Soporte integrado (0113): en la conversacion de un ticket, los mensajes de soporte van hacia la derecha y
   con la superficie de marca. El nombre del autor ("Soporte") ya lo dice: el color no es la unica pista. */
.comentarios__item--soporte { background: var(--color-marca-suave); margin-left: var(--esp-6); }
.comentarios__item--propio { margin-right: var(--esp-6); }

/* Recetas (0117): cada medicamento del formulario es un bloque con su propia rejilla y su boton Quitar. */
.receta-item { display: grid; gap: var(--esp-2); padding: var(--esp-3) var(--esp-4); margin-bottom: var(--esp-3); border-radius: var(--radio-md); background: var(--color-superficie-alt); }
.receta-item__cabecera { display: flex; align-items: center; justify-content: space-between; gap: var(--esp-2); }
.receta-item__rejilla { display: grid; gap: var(--esp-2) var(--esp-3); grid-template-columns: 1fr; }
@media (min-width: 40rem) { .receta-item__rejilla { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 60rem) { .receta-item__rejilla { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.receta-item__rejilla .campo--ancho { grid-column: 1 / -1; }

/* «¿No encuentra lo que busca?»: acordeon de enlaces a pantallas vecinas, bajo la bajada (funciones/ayudaCruzada.php). */
.ayuda-cruzada { margin: calc(-1 * var(--esp-2)) 0 var(--esp-4); font-size: var(--texto-sm); color: var(--color-texto-suave); }
.ayuda-cruzada summary {
  cursor: pointer; display: inline-flex; align-items: center; min-height: 44px;
  padding: 0 var(--esp-2); border-radius: var(--radio-full);
}
.ayuda-cruzada summary:hover { background: var(--color-superficie-alt); color: var(--color-texto); }
.ayuda-cruzada summary:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 1px; }
.ayuda-cruzada ul { list-style: none; margin: var(--esp-2) 0 0; padding: 0 var(--esp-2); display: grid; gap: var(--esp-1); }
.ayuda-cruzada a { display: inline-flex; align-items: center; gap: var(--esp-1); min-height: 44px; color: var(--color-marca-fuerte); }

/* Receta impresa: QR de verificacion junto al texto (el SVG trae su propio fondo blanco y su zona de silencio). */
.receta-verificar { display: flex; align-items: center; gap: var(--esp-3); }
.receta-verificar svg { flex: none; }

/* Consentimiento de texto (0119): el texto a firmar, completado con los datos del caso. Hermano de .vista-pdf. */
.vista-texto {
  max-height: 22rem; overflow-y: auto; padding: var(--esp-3) var(--esp-4);
  border: 1px solid var(--color-borde); border-radius: var(--radio-sm); background: var(--color-superficie-alt);
  white-space: pre-wrap; overflow-wrap: anywhere; font-size: var(--texto-sm);
}
.vista-texto:focus-visible { outline: 2px solid var(--color-marca); outline-offset: 2px; }
