/* Urvano Barbershop — variables de diseño (.claude/rules/DISENO.md) + reset */

:root {
  /* Superficies (de más oscura a más clara) */
  --color-canvas:        #0f1011;
  --color-surface-deep:  #090a0b;
  --color-surface:       #2e2e2e;
  --color-surface-hover: #3f4041;

  /* Texto */
  --color-text:          #f5f5f7;
  --color-text-body:     #9f9fa0;
  --color-text-muted:    #6a6b6b;
  --color-text-invert:   #0f1011;

  /* Acento */
  --color-accent:        #D4AF37;
  --color-accent-dim:    #8f7526;

  /* Acción primaria */
  --color-action-bg:     #ffffff;
  --color-action-text:   #000000;

  /* Estado de turno */
  --color-turno-pendiente: #6a6b6b;
  --color-turno-pagado:    #4ade80;
  --color-turno-cancelado: #f87171;
  --color-turno-gratis:    #D4AF37;

  /* Selector de estado en el listado de reservas (solo admin) — paleta propia a pedido:
     no pagado en blanco puro (única excepción a "sin blanco puro" — es un selector de
     estado interno del admin, no texto de cuerpo del sitio público). Pagado/cancelado
     reusan los tokens de turno ya existentes (mismo verde/rojo). También usado para marcar
     "ya enviado" en los botones de WhatsApp (13.7). */
  --color-badge-amarillo: #eab308;

  /* Categoría de cliente (solo admin, listado de Clientes) — mismo criterio que arriba:
     paleta propia, "candy" y vívida a propósito, para un control interno de trabajo, no
     para el sitio público. Rosa nuevo, exclusivo de "Nuevo" — el resto reusa tokens ya
     existentes (dorado, verde, blanco). Celeste nuevo, exclusivo de "Reactivado". */
  --color-categoria-nuevo: #f472b6;
  --color-categoria-reactivado: #38bdf8;

  /* Estado (formularios y sistema) */
  --color-success:       #4ade80;
  --color-error:         #f87171;
  --color-border:        rgba(255, 255, 255, 0.12);

  /* Tipografía */
  --font-display: "DM Serif Display", Georgia, serif;
  --font-body:    "Inter", system-ui, -apple-system, sans-serif;

  --text-caption: 0.75rem;
  --text-body:    1rem;
  --text-sub:     1.125rem;
  --text-heading: clamp(1.75rem, 5vw, 2.375rem);
  --text-display: clamp(2.5rem, 9vw, 5rem);

  --leading-display: 0.95;
  --leading-heading: 1.1;
  --leading-body:    1.5;

  --weight-light:   300;
  --weight-regular: 400;
  --weight-medium:  500;

  /* Espaciado y layout */
  --space-unit: 4px;
  --space-xs:  8px;
  --space-sm:  12px;
  --space-md:  16px;
  --space-lg:  32px;
  --space-xl:  48px;
  --space-2xl: 80px;

  --container-max: 1200px;
  --card-padding:  32px;

  /* Forma, borde */
  --radius-sm:   8px;
  --radius-md:   16px;
  --radius-full: 9999px;

  --border-width: 1px;

  /* Capas */
  --z-base:    0;
  --z-sticky:  100;
  --z-overlay: 200;
  --z-modal:   300;
  --z-toast:   400;
  --z-splash:  500;

  /* Movimiento */
  --duration-instant: 80ms;
  --duration-fast:   160ms;
  --duration-base:   240ms;
  --ease-out: cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* Reset mínimo */
*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  /* En mobile real (Safari iOS sobre todo), 100vh se calcula más alto que el espacio
     visible mientras la barra de direcciones sigue expandida, dejando un scroll fantasma
     hasta que se asienta — 100dvh (dynamic viewport height) lo evita; los navegadores que
     no la soportan simplemente ignoran esta línea y se quedan con el 100vh de arriba. */
  min-height: 100dvh;
  background-color: var(--color-canvas);
  color: var(--color-text-body);
  font-family: var(--font-body);
  font-weight: var(--weight-regular);
  font-size: var(--text-body);
  line-height: var(--leading-body);
}

/* #main reparte el alto sobrante entre header y footer (ambos de alto natural, fuera de
   #main) — la landing (10.2) lo aprovecha con flex:1 para ocupar exactamente ese resto sin
   necesidad de scroll; el resto de las secciones simplemente conservan su alto de contenido,
   igual que antes de este cambio. */
#main {
  display: flex;
  flex-direction: column;
  flex: 1;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: var(--weight-light);
  line-height: var(--leading-heading);
  color: var(--color-text);
}

img {
  max-width: 100%;
  display: block;
}

button {
  font-family: inherit;
}

a {
  color: inherit;
}

/* [hidden] siempre gana, sin importar qué componente fije su propio "display"
   (landing, header__volver, etc.) — la alternativa es repetir esta excepción
   en cada clase que use display, así que se centraliza acá una sola vez. */
[hidden] {
  display: none !important;
}

/* prefers-reduced-motion: DISEÑO.md 15 lo exige "sin excepciones, incluido el splash".
   Se centraliza acá para no repetir la media query en cada transición (splash, landing, etc). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* Splash y landing: pantalla fija, sin scroll ni rebote (10.1/10.2). main.js agrega esta
   clase al body mientras el splash o la landing están activos y la saca al entrar a una
   sección real. Sin esto, en mobile el "rubber-band" del navegador desplaza la foto de
   fondo unos píxeles mientras el logo del splash queda clavado — se ven despegados. */
body.pantalla-fija {
  overflow: hidden;
  overscroll-behavior: none;
}

/* Splash (10.1) — sin foto propia, se apoya en el fondo de la landing (10.2) detrás */
.splash {
  position: fixed;
  inset: 0;
  z-index: var(--z-splash);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: opacity var(--duration-base) var(--ease-out),
              transform var(--duration-base) var(--ease-out);
}

.splash--oculto {
  opacity: 0;
  transform: scale(0.96);
  pointer-events: none;
}

.splash__logo {
  width: min(75vw, 320px);
}

/* Pista de "tocá para entrar" (10.1, pedido explícito) — sin rebote/translate: la sección 15
   prohíbe "rebotes" salvo las dos excepciones ya nombradas (slide del splash, bottom sheet),
   así que la señal es un pulso lento de opacity, la única propiedad de esa lista que tiene
   sentido acá sin caer en un movimiento tipo rebote. Rotada 90° (mismo trazo que
   ICONO_FLECHA_DER de calendario.js/el "volver atrás" del header) para apuntar hacia abajo. */
.splash__flecha {
  position: absolute;
  left: 50%;
  bottom: 8%;
  transform: translateX(-50%) rotate(90deg);
  color: var(--color-text);
  animation: splash-flecha-pulso 2s var(--ease-out) infinite;
}

@keyframes splash-flecha-pulso {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 1; }
}

/* El splash entero ya se saltea sin animar cuando prefers-reduced-motion está activo
   (js/main.js, iniciarSplash) — este fallback es solo para el instante en que el CSS ya
   cargó pero el JS todavía no decidió saltearlo. */
@media (prefers-reduced-motion: reduce) {
  .splash__flecha {
    animation: none;
  }
}

/* Header persistente (10.5) + flecha volver (10.6) */
.header {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background-color: var(--color-canvas);
  border-bottom: var(--border-width) solid var(--color-border);
}

.header__volver {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  background: none;
  border: none;
  color: var(--color-text-body);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-out);
}

.header__volver:hover {
  color: var(--color-accent);
}

.header__logo {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  text-decoration: none;
  color: var(--color-text);
  font-weight: var(--weight-medium);
}

.header__logo img {
  height: 40px;
  width: auto;
}

/* Accesos rápidos (10.5): las mismas 4 opciones de la landing, siempre disponibles desde
   el header — así el cliente no tiene que volver a la landing para saltar de una sección
   a otra. Empujados a la derecha con margin-left: auto, misma línea que el logo. */
.header__accesos {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-xs);
  margin-left: auto;
}

.header__acceso {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--space-xs);
  background: none;
  border: none;
  color: var(--color-text);
  text-decoration: none;
  font-size: var(--text-caption);
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-out);
}

.header__acceso:hover {
  color: var(--color-accent);
}

/* Mobile (solo público, index.html): el header pasa a dos filas apiladas — logo centrado
   arriba (con la flecha "volver" flotando a la izquierda para no descentrarlo, mismo
   criterio que el header admin con grid, 10.4) y los 4 accesos rápidos repartidos en UNA
   sola fila a todo el ancho abajo (pedido explícito). Antes: logo a la izquierda y los
   accesos envueltos en 2 líneas contra el margen derecho (10.5.1). Desktop no cambia. */
@media (max-width: 767px) {
  body:not(.admin) .header {
    flex-direction: column;
    flex-wrap: nowrap;
    gap: var(--space-xs);
  }

  body:not(.admin) .header__volver {
    position: absolute;
    left: var(--space-xs);
    top: var(--space-xs);
  }

  body:not(.admin) .header__logo {
    align-self: center;
  }

  body:not(.admin) .header__accesos {
    width: 100%;
    margin-left: 0;
    flex-wrap: nowrap;
    justify-content: space-between;
    gap: var(--space-unit);
  }

  body:not(.admin) .header__acceso {
    flex: 1;
    min-width: 0;
    justify-content: center;
    padding: 0 var(--space-unit);
    text-align: center;
    white-space: normal;
    line-height: 1.2;
  }
}

.header__etiqueta-admin {
  font-size: var(--text-heading);
  font-weight: var(--weight-medium);
  color: var(--color-accent);
  text-transform: uppercase;
}

.franja-admin {
  height: 4px;
  background-color: var(--color-accent);
}

/* Logo a la izquierda (como en index.html) + "Panel administrador" centrado en la barra
   de verdad, sin importar el ancho del logo — grid de 3 columnas en vez de flex: la
   columna 1 y la 3 son iguales (1fr cada una), la 3 queda vacía a propósito, así el
   ancho que "roba" el logo a la izquierda se compensa del lado derecho y el título cae
   en el centro real del header, no en el centro del espacio sobrante después del logo. */
body.admin .header {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
}

body.admin .header__logo {
  grid-column: 1;
  justify-self: start;
}

body.admin .header__etiqueta-admin {
  grid-column: 2;
  justify-self: center;
}

/* Menú admin (13.13): tab bar fija abajo en mobile, barra lateral en desktop */
.admin-layout {
  display: flex;
  flex-direction: column;
}

.admin-layout #main {
  flex: 1;
  min-width: 0;
  padding-bottom: 72px;
}

.admin-menu {
  display: flex;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: var(--z-sticky);
  justify-content: space-around;
  background-color: var(--color-canvas);
  border-top: var(--border-width) solid var(--color-border);
}

.admin-menu__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  flex: 1;
  min-height: 56px;
  background: none;
  border: none;
  color: var(--color-text);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-out);
}

.admin-menu__etiqueta {
  font-size: var(--text-sub);
}

.admin-menu__item--activo {
  color: var(--color-accent);
}

/* Mobile: primero de la fila (izquierda) — en desktop se reordena a último (abajo, ver
   media query) para que "parte inferior izquierda de la página" tenga sentido en las dos
   orientaciones: izquierda en la barra horizontal, abajo en la barra lateral vertical. */
.admin-menu__item--salir {
  order: -1;
  margin-top: auto;
}

@media (min-width: 1024px) {
  .admin-layout {
    flex-direction: row;
  }

  .admin-layout #main {
    padding-bottom: 0;
  }

  .admin-menu {
    position: sticky;
    top: 81px;
    /* Alto real hasta el fondo del viewport — sin esto la columna se achica a su propio
       contenido y el margin-top:auto de "Cerrar sesión" no tiene dónde empujar: quedaba
       pegado debajo de Clientes en vez de al fondo de la página. */
    height: calc(100vh - 81px);
    bottom: auto;
    left: auto;
    right: auto;
    flex-direction: column;
    justify-content: flex-start;
    align-self: flex-start;
    width: 220px;
    flex-shrink: 0;
    border-top: none;
    border-right: var(--border-width) solid var(--color-border);
    padding: var(--space-md) 0;
    /* Pedido explícito: separación pareja entre las 5 opciones principales, para
       diferenciarlas mejor una de otra (además refuerza el empuje de margin-top:auto de
       "Cerrar sesión" de abajo, sin tocar esa regla). */
    gap: var(--space-xs);
  }

  .admin-menu__item {
    flex-direction: row;
    justify-content: flex-start;
    gap: var(--space-sm);
    min-height: 44px;
    padding: var(--space-sm) var(--space-md);
    border-left: 3px solid transparent;
  }

  .admin-menu__item--activo {
    border-left-color: var(--color-accent);
  }

  .admin-menu__item--salir {
    order: 0;
    /* Separador visual claro respecto del bloque de opciones principales — sumado al
       margin-top:auto (base, fuera de este media query) que ya lo empuja al fondo. */
    border-top: var(--border-width) solid var(--color-border);
    padding-top: var(--space-md);
  }
}

/* Login admin (13.14) */
.admin-login {
  max-width: 360px;
  margin: var(--space-2xl) auto;
  padding: var(--space-md);
  text-align: center;
}

.admin-login__logo {
  width: 120px;
  margin: 0 auto var(--space-xl);
}

.admin-login__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  text-align: left;
}

.campo__password {
  display: flex;
  gap: var(--space-xs);
}

.campo__password input {
  flex: 1;
  min-height: 44px;
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font-size: var(--text-body);
  padding: 0 var(--space-sm);
}

.campo__mostrar {
  min-height: 44px;
  padding: 0 var(--space-sm);
  background: none;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-body);
  cursor: pointer;
  white-space: nowrap;
}

.admin-login__form button[type='submit'] {
  min-height: 44px;
  background-color: var(--color-action-bg);
  color: var(--color-action-text);
  border: none;
  border-radius: var(--radius-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
}

.admin-login__form button[type='submit']:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.admin-login__estado {
  font-size: var(--text-caption);
}

.admin-login__estado--cargando {
  color: var(--color-text-muted);
}

.admin-login__estado--error {
  color: var(--color-error);
}

/* Contenido de las secciones admin (calendario, reservas, tablero, clientes) */
.admin-seccion {
  padding: var(--space-lg) var(--space-md);
  max-width: var(--container-max);
  /* Bug real encontrado: sin esto, en una ventana más ancha que --container-max + la barra
     lateral, el bloque quedaba pegado a la izquierda (comportamiento por defecto de un
     bloque con max-width sin margin) — todo el margen sobrante caía del lado derecho en vez
     de repartirse parejo. */
  margin: 0 auto;
}

/* Reservas y Clientes (pedido explícito): la tabla ocupa TODO el ancho de #main (que ya va
   del borde de la barra lateral al borde derecho del viewport), sin el tope de
   --container-max ni los márgenes de centrado — así cada columna tiene ancho suficiente y
   Cliente/Teléfono/Tipo de corte dejan de truncarse. Se mantiene un gutter chico a los
   lados para que el texto no quede pegado al borde. */
.admin-seccion--ancho-completo {
  max-width: none;
  padding-left: var(--space-sm);
  padding-right: var(--space-sm);
}

.admin-seccion__titulo {
  margin-bottom: var(--space-lg);
  text-align: center;
}

/* Cabecera de Clientes con el botón "+" a la derecha sin descentrar el título (13.13
   exige título centrado) — mismo patrón de grid 1fr/auto/1fr que el header admin (10.4):
   la columna 3 vacía compensa el ancho de la columna 1, así el título cae en el centro
   real de la barra, no en el centro del espacio que queda libre. */
.admin-seccion__cabecera {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  margin-bottom: var(--space-lg);
}

.admin-seccion__cabecera .admin-seccion__titulo {
  grid-column: 2;
  margin-bottom: 0;
}

.admin-clientes__agregar {
  grid-column: 3;
  justify-self: end;
  width: 44px;
  height: 44px;
  background-color: var(--color-action-bg);
  color: var(--color-action-text);
  border: none;
  border-radius: var(--radius-full);
  font-size: var(--text-sub);
  line-height: 1;
  cursor: pointer;
}

.admin-error {
  background-color: var(--color-surface);
  border-left: 3px solid var(--color-error);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  padding: var(--space-sm) var(--space-md);
  margin-bottom: var(--space-md);
  font-size: var(--text-caption);
}

/* Walk-in / "Corte amigo" (solo admin) */
/* Controles del margen superior del Calendario (13.3, admin): "Activar/Desactivar Barbero 2"
   y "Horas extra", uno al lado del otro pero separados — flex-wrap para que no se corten en
   mobile, cada botón se apila solo si no entran los dos en una línea. */
.admin-calendario-controles {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}

/* Botón distintivo compartido: fondo gris (--color-surface, el mismo tono de superficie que
   tarjetas/paneles), texto y contorno en --color-text (el "blanco" real del sistema, no
   blanco puro — mismo criterio que la tarjeta de servicio, 13.9, y el ticket, 13.17). El
   estado de "Activar Barbero 2" se comunica con el propio texto del botón (Activar ↔
   Desactivar), no con un color distinto — los dos botones se ven siempre iguales entre sí. */
.admin-calendario-boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 var(--space-md);
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-text);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font-size: var(--text-body);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out);
}

.admin-calendario-boton:hover {
  background-color: var(--color-surface-hover);
}

/* "Activar Barbero 2" con Barbero 2 activo: contorno y texto en verde (--color-success)
   en vez del blanco de siempre — mismo fondo gris que su estado inactivo y que "Horas
   extra" al lado, el color es la única diferencia. */
.admin-calendario-boton--activo {
  border-color: var(--color-success);
  color: var(--color-success);
}

/* Formulario de "Horas extra" (13.3) — mismo tratamiento visual que .admin-walkin de abajo
   (mismo componente conceptual: nombre/apellido/teléfono/pago), pero fecha/hora/barbero/tipo
   de corte se completan a mano acá, sin depender de tocar el calendario. */
.admin-hora-extra-form {
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-accent);
  border-radius: var(--radius-sm);
  padding: var(--space-md);
  margin: 0 auto var(--space-md);
  max-width: 480px;
}

.admin-hora-extra-form__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.admin-hora-extra-form__acciones {
  display: flex;
  gap: var(--space-sm);
}

.admin-hora-extra-form__acciones button {
  flex: 1;
  min-height: 44px;
  border-radius: var(--radius-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
}

.admin-hora-extra-form__acciones button[type='submit'] {
  background-color: var(--color-action-bg);
  color: var(--color-action-text);
  border: none;
}

.admin-hora-extra-form__acciones button[type='submit']:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.admin-hora-extra-form__cancelar {
  background: none;
  color: var(--color-text-body);
  border: var(--border-width) solid var(--color-border);
}

.admin-hora-extra-form__estado {
  font-size: var(--text-caption);
}

.admin-hora-extra-form__estado--cargando {
  color: var(--color-text-muted);
}

.admin-hora-extra-form__estado--exito {
  color: var(--color-success);
}

.admin-hora-extra-form__estado--error {
  color: var(--color-error);
}

.admin-walkin {
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-accent);
  border-radius: var(--radius-sm);
  padding: var(--space-md);
  margin: 0 auto var(--space-md);
  max-width: 480px;
}

.admin-walkin__resumen {
  color: var(--color-text);
  margin-bottom: var(--space-md);
}

.admin-walkin__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.admin-walkin__acciones {
  display: flex;
  gap: var(--space-sm);
}

.admin-walkin__acciones button {
  flex: 1;
  min-height: 44px;
  border-radius: var(--radius-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
}

.admin-walkin__acciones button[type='submit'] {
  background-color: var(--color-action-bg);
  color: var(--color-action-text);
  border: none;
}

.admin-walkin__acciones button[type='submit']:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.admin-walkin__cancelar {
  background: none;
  color: var(--color-text-body);
  border: var(--border-width) solid var(--color-border);
}

.admin-walkin__estado {
  font-size: var(--text-caption);
}

.admin-walkin__estado--cargando {
  color: var(--color-text-muted);
}

.admin-walkin__estado--exito {
  color: var(--color-success);
}

.admin-walkin__estado--error {
  color: var(--color-error);
}

/* Listado de reservas (13.6) */
.admin-reservas__barra {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  margin-bottom: var(--space-md);
}

.filtro-periodo {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

/* Más distancia hasta la tabla de abajo (pedido explícito, "mayor prolijidad") — antes sin
   margen propio, quedaba pegado a la cabecera de columnas (ID/Cliente/Teléfono...). */
.admin-clientes__filtro {
  margin-bottom: var(--space-lg);
}

.admin-reservas__nav-mes {
  margin-bottom: 0;
}

.admin-reservas__nivel {
  margin-bottom: var(--space-md);
}

.filtro-periodo__item {
  min-height: 44px;
  padding: 0 var(--space-md);
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-body);
  cursor: pointer;
  transition: border-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}

.filtro-periodo__item--activo {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

.admin-reservas__exportar {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  min-height: 44px;
  padding: 0 var(--space-md);
  background: none;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-body);
  cursor: pointer;
}

.admin-reservas__exportar:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.admin-tabla {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.admin-tabla th,
.admin-tabla td {
  padding: var(--space-xs) var(--space-sm);
  /* Pedido explícito: cada celda de dato centrada, alineada con el título de su columna
     (antes izquierda) — Reservas y Clientes, las dos comparten .admin-tabla. */
  text-align: center;
  /* Antes: white-space: nowrap + overflow: hidden + text-overflow: ellipsis, que recortaba
     nombre / teléfono / tipo de corte con "…". Decisión revisada (pedido explícito, ahora que
     la tabla ocupa todo el ancho): el dato se muestra completo — si no entra en una línea
     envuelve (overflow-wrap: anywhere para strings sin espacios, ej. el teléfono), la fila
     crece de alto. Sigue sin haber scroll horizontal (DISEÑO 11). */
  white-space: normal;
  overflow-wrap: anywhere;
  /* Sin min-height acá — lo que hacía a la fila más alta de lo que su propio contenido
   * necesita (el texto de las celdas de dato es más chico que 44px). Los controles que sí
   * necesitan área táctil real (los botones de WhatsApp, .admin-accion-wtp) ya tienen su
   * propio min-height, así que su fila sigue siendo tan alta como haga falta — esto solo
   * achica las filas de puro texto (Cliente, Teléfono, Fecha, Hora, Tipo de corte...). */
}

.admin-tabla th {
  vertical-align: middle;
}

/* Middle (decisión revisada, pedido explícito: la fila de datos tiene que quedar centrada
   en el alto de su rectángulo, no pegada abajo). El ícono Eliminar no se mueve — es
   position: absolute anclado a la esquina de la celda de Acciones (.admin-tabla__eliminar),
   independiente de este vertical-align. Los botones de WhatsApp de esa misma celda siguen
   anclados arriba (padding-top de .admin-tabla__col-acciones + align-items: flex-start),
   debajo del ícono. Antes era `bottom` para que el texto quedara a la misma altura que esos
   botones; ahora prima centrar el dato. */
.admin-tabla td {
  vertical-align: middle;
}

/* Columnas parejas (decisión revisada, pedido explícito — antes cada columna tenía un
   ancho distinto a mano, ej. 15%/16%/11%/7%..., pensado según cuánto contenido esperaba
   cada una): sin un ancho explícito por columna, table-layout: fixed (arriba) reparte el
   ancho de la tabla en partes iguales entre todas las columnas — vale tal cual para las 6
   columnas de Clientes, sin reglas nth-child propias. El truncado con "…" (arriba) sigue de
   resguardo para la columna que le quede más justa (ej. Teléfono) en el caso extremo. */

/* Reservas (8 columnas) y con Barbero activo (9): Acciones NO entra en el reparto parejo de
   arriba — bug real encontrado al emparejar todas por igual, Recordar y Reseña (13.7) dejaban
   de entrar lado a lado y se apilaban, rompiendo la simetría de línea pedida más arriba. Se
   mantiene ensanchada (ya lo estaba, antes de este cambio) y el resto de las columnas se
   reparte parejo entre sí en el espacio que queda — "parejas entre ellas", no con Acciones. */
.admin-tabla:not(.admin-tabla--clientes) th:nth-last-child(1),
.admin-tabla:not(.admin-tabla--clientes) td:nth-last-child(1) {
  width: 16%;
}

.admin-tabla:not(.admin-tabla--clientes):not(.admin-tabla--con-barbero) th:nth-child(-n+7),
.admin-tabla:not(.admin-tabla--clientes):not(.admin-tabla--con-barbero) td:nth-child(-n+7) {
  width: 12%;
}

.admin-tabla.admin-tabla--con-barbero th:nth-child(-n+8),
.admin-tabla.admin-tabla--con-barbero td:nth-child(-n+8) {
  width: 10.5%;
}

.admin-tabla thead th {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background-color: var(--color-canvas);
  border-bottom: var(--border-width) solid var(--color-border);
  /* Pedido explícito: encabezados más grandes (antes --text-caption, 12px, se leían chicos) */
  font-size: var(--text-body);
  color: var(--color-text-muted);
  text-transform: uppercase;
  /* A este tamaño, títulos como "Tipo de corte"/"Barbero"/"Forma de pago" no entran en una
     sola línea dentro de columnas angostas — bug real encontrado al probar: quedaban
     truncados ("BARBE...", "H..."), ilegibles. A diferencia de las celdas de dato (que sí
     deben quedar en una sola línea, 13.6), el encabezado puede pasar a una segunda línea sin
     problema — la fila de títulos ya es más alta que una fila de datos normal. */
  white-space: normal;
  line-height: 1.15;
}

.admin-tabla tbody tr:nth-child(odd) {
  background-color: var(--color-surface);
}

.admin-tabla tbody tr:nth-child(even) {
  background-color: var(--color-surface-deep);
}

/* Fila separadora de grupo (13.6) — "Martes 11" dentro de una semana, "Semana del 11 al
   15" dentro del mes completo. Va después de las reglas nth-child en el archivo para
   ganar el empate de especificidad (misma cantidad de clases y de elementos) por orden
   de aparición, sin necesidad de subir la especificidad a mano ni usar !important. */
.admin-tabla tbody tr.admin-tabla__grupo {
  background-color: var(--color-surface-deep);
}

/* El <td> se queda con su display de tabla por defecto (table-cell) — un <td> con
   display:flex deja de participar del cálculo de ancho de table-layout:fixed y el
   colspan=8 termina angosto (bug real que se notaba como texto partido en 2-3 renglones,
   ver AUDITORIA_PENDIENTE.md). El flex va en el <div> interno de abajo. */
.admin-tabla__grupo td {
  color: var(--color-text);
  font-size: var(--text-caption);
  font-weight: var(--weight-medium);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: normal;
}

.admin-tabla__grupo-contenido {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

/* Línea que completa la fila al lado del texto ("Semana del 9 al 15 ————") — separa mejor
   un grupo del siguiente que el texto solo, hasta el margen derecho real de la tabla
   (ahora que el <div> sí ocupa el ancho completo del colspan). --color-text (blanco del
   sistema) en vez de --color-border (12% de opacidad, casi invisible) — tiene que notarse
   como corte entre un grupo y el siguiente. */
.admin-tabla__grupo-contenido::after {
  content: '';
  flex: 1;
  height: var(--border-width);
  background-color: var(--color-text);
}

/* Selector de estado del turno — editable desde la misma celda del listado de reservas */
.selector-estado {
  width: 100%;
  min-height: 32px;
  padding: 2px var(--space-xs);
  border: none;
  border-radius: var(--radius-full);
  font-size: var(--text-caption);
  font-weight: var(--weight-medium);
  color: var(--color-text-invert);
  cursor: pointer;
}

.selector-estado--no-pagado {
  background-color: var(--color-action-bg);
}

.selector-estado--pagado {
  background-color: var(--color-turno-pagado);
}

.selector-estado--cancelado {
  background-color: var(--color-turno-cancelado);
}

/* Gratis: asignación manual del admin (regalar un corte puntual) — sin relación con el
   5to corte de fidelidad, que es un 50% de descuento sobre un Pagado normal (13.17). */
.selector-estado--gratis {
  background-color: var(--color-badge-amarillo);
}

/* Forma de pago — solo editable una vez que el turno está Pagado */
.selector-metodo-pago {
  width: 100%;
  min-height: 32px;
  padding: 2px var(--space-xs);
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font-size: var(--text-caption);
  cursor: pointer;
}

.selector-metodo-pago:disabled {
  color: var(--color-text-muted);
  cursor: not-allowed;
  opacity: 0.6;
}

/* Recordar/Reseña lado a lado, no apilados (decisión revisada — apilar los dos hacía la
 * fila más alta, exactamente lo contrario de "ver más reservas de un vistazo" que buscaba
 * la versión anterior; ninguno de los dos botones se achica por debajo de 44px, la fila
 * baja de altura porque no hay dos de 44px uno arriba del otro). flex-wrap por si el
 * ancho de columna queda muy angosto (13.6, con Barbero activo hay una columna más) —
 * ahí sí se apilan solos, pero es el caso excepcional, no el de siempre. */
.admin-acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: center;
  gap: var(--space-xs);
}

/* Celda de Acciones del listado de reservas — position: relative para anclar el botón
   Eliminar en la esquina, mismo mecanismo que el candado de bloqueo del calendario (13.3).
   padding-top extra para que el ícono no tape el primer botón de WhatsApp de abajo. */
.admin-tabla td.admin-tabla__col-acciones {
  position: relative;
  padding-top: 36px;
}

/* Ícono Eliminar en la esquina de una celda de Acciones — genérico (renombrado desde
   admin-reserva__eliminar): lo usa tanto el listado de Reservas como el de Clientes, mismo
   patrón visual en los dos (13.6/13.18). */
.admin-tabla__eliminar {
  position: absolute;
  top: 2px;
  right: 2px;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  background-color: var(--color-surface-deep);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
}

.admin-tabla__eliminar:hover,
.admin-tabla__eliminar:focus-visible {
  color: var(--color-error);
  border-color: var(--color-error);
}

.admin-tabla__eliminar:disabled {
  opacity: 0.5;
  cursor: default;
}

.admin-accion-texto {
  min-height: 44px;
  padding: 0 var(--space-sm);
  background: none;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-body);
  cursor: pointer;
  font-size: var(--text-caption);
  transition: color var(--duration-fast) var(--ease-out);
}

body.admin .admin-accion-texto:hover {
  color: var(--color-accent);
}

.admin-accion-wtp {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  min-height: 44px;
  padding: var(--space-xs) 0;
  color: var(--color-text-body);
  text-decoration: none;
  font-size: var(--text-caption);
  overflow-wrap: break-word;
  transition: color var(--duration-fast) var(--ease-out);
}

.admin-accion-wtp span {
  min-width: 0;
  overflow-wrap: break-word;
}

body.admin .admin-accion-wtp:hover {
  color: var(--color-accent);
}

.admin-tabla__vacio {
  text-align: center;
  color: var(--color-text-muted);
  padding: var(--space-2xl) var(--space-md);
}

/* Tablero de comando (13.11) */
/* Navegador de mes y nivel (HOY/Semana/Mes) del Tablero (13.11) — mismo .calendario-nav que
   Reservas (13.6), y mismo .filtro-periodo de siempre para los 3 botones. */
.admin-tablero__nav-mes {
  margin-bottom: 0;
}

.admin-tablero__nivel {
  margin-bottom: var(--space-md);
}

/* Pedido explícito: HOY/Semana/Mes en blanco cuando no están activos (--color-text), no el
   gris --color-text-body que usa .filtro-periodo__item en el resto del sitio — acotado a
   esta pantalla, Reservas/Clientes siguen con el gris de siempre. El estado activo sigue
   dorado (--color-accent), sin cambios — "activo = dorado" es el criterio de todo el sitio.
   :not() en vez de confiar en el orden en la hoja: .filtro-periodo__item--activo (una
   clase) tiene menos especificidad que este selector (dos clases) y perdería el dorado si
   no se lo excluye a propósito acá. */
.admin-tablero__nivel .filtro-periodo__item:not(.filtro-periodo__item--activo) {
  color: var(--color-text);
}

.tablero__metricas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  margin: var(--space-lg) 0;
}

/* Contorno blanco + un poco más chicas (pedido explícito) — mismo criterio de "blanco real
   del sistema" que la tarjeta de servicio, 13.9, en vez de un borde de --color-border. */
.tablero__tarjeta {
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-text);
  border-radius: var(--radius-md);
  padding: var(--space-md);
  flex: 1;
  min-width: 260px;
  max-width: 480px;
}

/* Pedido explícito: la tarjeta de Objetivo se distingue de Cortes/Facturación sin el
   contorno blanco — border-color transparent en vez de border:none para no mover el box
   model (mismo padding/tamaño exacto que las otras dos). */
.tablero__tarjeta--objetivo {
  border-color: transparent;
}

/* h1-h4 heredan --font-display por defecto (sección 3 del sistema de diseño) — acá se pisa
   a propósito: pedido explícito de que TODA la tipografía de esta sección sea la misma
   simple de los botones HOY/Semana/Mes (.filtro-periodo__item), sin la fuente display. */
.tablero__tarjeta-titulo {
  font-family: var(--font-body);
  font-weight: var(--weight-regular);
  font-size: var(--text-body);
  color: var(--color-text);
  margin-bottom: var(--space-sm);
}

.tablero__sin-objetivo {
  font-size: var(--text-caption);
  color: var(--color-text-muted);
}

/* Fila de los dos gráficos (pedido explícito): barras 70%, líneas 30%, bien separados —
   flex-wrap para que una ventana angosta los apile en vez de desbordar (el admin está
   pensado para escritorio, 13.6, pero esto evita romper el layout si se achica igual). */
.tablero__graficos-fila {
  display: flex;
  gap: var(--space-lg);
  flex-wrap: wrap;
  margin-bottom: var(--space-lg);
}

.tablero__grafico {
  flex: 7 1 320px;
}

/* Mismo tratamiento que .tablero__grafico (título+leyenda, .tablero__grafico-lienzo con
   contorno blanco reusado tal cual) — oculto entero cuando el otro barbero nunca estuvo
   activo en el rango graficado (dibujarGraficoLineas, admin.js) o en la pestaña HOY. */
.tablero__grafico-lineas {
  flex: 3 1 200px;
}

.tablero__grafico-cabecera {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}

.tablero__grafico-cabecera .tablero__tarjeta-titulo {
  margin-bottom: 0;
}

.tablero__grafico-leyenda {
  display: flex;
  gap: var(--space-md);
  font-size: var(--text-caption);
  color: var(--color-text-muted);
}

.tablero__grafico-leyenda-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
}

.tablero__grafico-swatch {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-full);
  display: inline-block;
}

.tablero__grafico-swatch--real {
  background-color: var(--color-text);
}

.tablero__grafico-swatch--objetivo {
  background-color: var(--color-accent);
}

.tablero__grafico-lienzo {
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-text);
  border-radius: var(--radius-md);
  padding: var(--space-sm);
}

.tablero__grafico-svg {
  width: 100%;
  height: auto;
  display: block;
}

.tablero__grafico-eje {
  stroke: var(--color-border);
  stroke-width: 1;
}

/* Barra de objetivo: contorno dorado hueco, sin relleno — la barra de "actual" (abajo) se
   dibuja encima, superpuesta a la misma base, mostrando cuánto de ese contorno ya se llenó. */
.tablero__grafico-barra-objetivo {
  fill: none;
  stroke: var(--color-accent);
  stroke-width: 2;
}

.tablero__grafico-barra-actual {
  fill: var(--color-text);
}

.tablero__grafico-etiqueta {
  fill: var(--color-text);
  font-size: 10px;
}

.tablero__grafico-porcentaje {
  fill: var(--color-accent);
  font-size: 13px;
  font-weight: var(--weight-medium);
}

/* Números de objetivo/actual arriba de cada barra (pedido explícito) — mismo criterio de
   color que el resto del gráfico: dorado = objetivo, blanco = actual. */
.tablero__grafico-num-objetivo {
  fill: var(--color-accent);
  font-size: 10px;
  font-weight: var(--weight-medium);
}

.tablero__grafico-num-actual {
  fill: var(--color-text);
  font-size: 10px;
  font-weight: var(--weight-medium);
}

/* Gráfico de líneas (evolución por barbero, al lado del de barras) — Lautaro en blanco
   (mismo tono que "Actual" del otro gráfico), el otro barbero en dorado. La <polyline>
   (--linea, hueca) y sus <circle> de cada punto (--punto, rellenos) van en clases separadas
   a propósito: una CSS class de fill le gana en especificidad al atributo fill="none" de la
   polyline, así que compartir una sola clase para las dos formas pintaría la línea rellena
   en vez de hueca. */
.tablero__grafico-linea--principal {
  stroke: var(--color-text);
  stroke-width: 2;
}

.tablero__grafico-linea--secundaria {
  stroke: var(--color-accent);
  stroke-width: 2;
}

.tablero__grafico-punto--principal {
  fill: var(--color-text);
}

.tablero__grafico-punto--secundaria {
  fill: var(--color-accent);
}

/* Cantidad de cortes en cada punto (pedido explícito) — mismo color que su línea/punto. */
.tablero__grafico-valor--principal {
  fill: var(--color-text);
  font-size: 10px;
  font-weight: var(--weight-medium);
}

.tablero__grafico-valor--secundaria {
  fill: var(--color-accent);
  font-size: 10px;
  font-weight: var(--weight-medium);
}

.tablero__grafico-sin-objetivo {
  font-size: var(--text-caption);
  color: var(--color-text-muted);
  margin-top: var(--space-xs);
}

.tablero__resumen {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  align-items: baseline;
  margin-bottom: var(--space-sm);
}

/* Pedido explícito: nada de la fuente display grande acá — misma tipografía simple que
   .filtro-periodo__item (Día/Semana/Mes), sin font-family ni font-weight propios. El color
   (blanco/dorado, abajo) sigue distinguiendo Actual de Objetivo — cambia la fuente, no eso. */
.tablero__realizado-num,
.tablero__objetivo-num {
  font-size: var(--text-body);
}

.tablero__realizado-num {
  color: var(--color-text);
}

.tablero__objetivo-num {
  color: var(--color-accent);
}

.tablero__modificar-objetivo {
  background: none;
  border: none;
  color: var(--color-text-body);
  font-size: var(--text-caption);
  text-decoration: underline;
  cursor: pointer;
  padding: var(--space-xs) 0;
  transition: color var(--duration-fast) var(--ease-out);
}

.tablero__modificar-objetivo:hover {
  color: var(--color-accent);
}

.tablero__barra {
  position: relative;
  height: 16px;
  background-color: var(--color-canvas);
  border-radius: var(--radius-sm);
  overflow: hidden;
  margin-bottom: var(--space-md);
}

.tablero__barra-relleno {
  height: 100%;
  width: 100%;
  background-color: var(--color-accent);
  transform-origin: left;
  transform: scaleX(0);
  transition: transform var(--duration-base) var(--ease-out);
}

.tablero__objetivo-marcador {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  background-color: var(--color-text-muted);
}

.tablero__objetivo-form {
  display: flex;
  align-items: flex-end;
  gap: var(--space-sm);
  flex-wrap: wrap;
  margin-bottom: var(--space-md);
}

.tablero__objetivo-form .campo {
  flex: 1;
  min-width: 180px;
}

.tablero__objetivo-form input {
  min-height: 44px;
  background-color: var(--color-canvas);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  padding: 0 var(--space-sm);
  width: 100%;
}

.tablero__objetivo-form button {
  min-height: 44px;
  padding: 0 var(--space-md);
  background: none;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-body);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-out);
}

.tablero__objetivo-form button:hover {
  color: var(--color-accent);
}

.tablero__objetivo-nota {
  font-size: var(--text-caption);
  color: var(--color-text-muted);
  margin-top: var(--space-xs);
}

.tablero__objetivo-pasado {
  font-size: var(--text-caption);
  color: var(--color-text-muted);
}

/* Fila de desgloses (13.11) — "Cortes realizados por tipo" y, con 2+ barberos activos,
   "Cortes por barbero" al lado, no debajo. Mismo patrón que .tablero__metricas: flex-wrap
   sin media query, se apilan solos en mobile cuando no entran los dos lado a lado. */
.tablero__desglose-fila {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-lg);
  margin-top: var(--space-lg);
}

.tablero__desglose {
  flex: 1;
  min-width: 260px;
  max-width: 480px;
}

/* Pedido explícito: recuadros separados, no dos columnas de texto suelto — mismo
   tratamiento que .tablero__tarjeta (fondo + radio), sin el contorno blanco de esa (acá el
   límite del recuadro ya lo da el propio fondo, no hace falta remarcarlo dos veces). */
.tablero__desglose--recuadro {
  background-color: var(--color-surface);
  border-radius: var(--radius-md);
  padding: var(--space-md);
}

.tablero__desglose-titulo {
  font-family: var(--font-body);
  font-weight: var(--weight-regular);
  font-size: var(--text-body);
  margin-bottom: var(--space-sm);
}

/* Subtítulo chico arriba de los dos recuadros de desglose, indicando a qué período
   corresponde lo que se está mostrando (evita confusiones al navegar mes/semana) — una
   sola vez para los dos recuadros, no repetido en cada uno. Deliberadamente poco
   llamativo: es información redundante con los botones HOY/Semana/Mes de arriba. */
.tablero__desglose-periodo {
  font-size: var(--text-caption);
  color: var(--color-text-muted);
  margin-bottom: var(--space-sm);
}

.tablero__desglose-lista {
  list-style: none;
}

.tablero__desglose-item {
  display: flex;
  justify-content: space-between;
  padding: var(--space-sm) 0;
  border-bottom: var(--border-width) solid var(--color-border);
  color: var(--color-text);
}

.tablero__desglose-vacio {
  color: var(--color-text-muted);
  padding: var(--space-lg) 0;
}

/* Sueldo de cada barbero que no es el dueño (13.11) — fila(s) aparte debajo de la lista de
   cortes por barbero, no ya adentro de cada <li> — mismo criterio visual que un renglón de
   total, separado por línea superior. */
/* Más espacio del que separaría "un ítem más de la lista" (--space-sm) — pedido explícito:
   que se note más la distancia respecto a "Cortes por barbero" arriba. */
.tablero__desglose-sueldo:not(:empty) {
  margin-top: var(--space-lg);
  padding-top: var(--space-sm);
  border-top: var(--border-width) solid var(--color-border);
}

.tablero__desglose-sueldo-item {
  color: var(--color-turno-gratis);
  font-weight: var(--weight-medium);
}

/* Lista de clientes */
.admin-clientes__proximo-descuento {
  color: var(--color-turno-gratis);
  font-size: var(--text-caption);
  font-weight: var(--weight-medium);
}

/* Cada múltiplo de 5 de la racha de fidelidad (5, 10, 15…) se destaca en dorado — el mismo
   tratamiento que cualquier corte marcado Gratis. Ese mismo número es el que dispara el
   50% de descuento del próximo corte (calcularEstadoFidelidad, datos.js). */
.admin-clientes__cortes-milestone {
  color: var(--color-turno-gratis);
  font-weight: var(--weight-medium);
}

/* Select editable de categoría de cliente (Fiel/Recurrente/Nuevo/Reactivado/Inactivo/Amigo)
   — el color refleja la categoría efectiva (13.18): Nuevo rosa, Reactivado celeste,
   Recurrente verde, Fiel dorado, Amigo blanco. */
.admin-clientes__selector-tipo {
  min-height: 32px;
  padding: 2px var(--space-sm);
  background: none;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-full);
  color: var(--color-text-body);
  font-size: var(--text-caption);
  cursor: pointer;
}

.admin-clientes__selector-tipo--fiel {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

.admin-clientes__selector-tipo--recurrente {
  border-color: var(--color-turno-pagado);
  color: var(--color-turno-pagado);
}

.admin-clientes__selector-tipo--nuevo {
  border-color: var(--color-categoria-nuevo);
  color: var(--color-categoria-nuevo);
}

.admin-clientes__selector-tipo--reactivado {
  border-color: var(--color-categoria-reactivado);
  color: var(--color-categoria-reactivado);
}

.admin-clientes__selector-tipo--inactivo {
  border-color: var(--color-text-muted);
  color: var(--color-text-muted);
}

.admin-clientes__selector-tipo--amigo {
  border-color: var(--color-action-bg);
  color: var(--color-action-bg);
}

/* El <select> hereda su color de la categoría efectiva (ej. blanco puro en Amigo) y ese
   color se cuela a las <option> del desplegable nativo, que en la mayoría de navegadores
   abre con fondo claro — texto blanco sobre fondo claro queda invisible. Se fuerza negro
   acá, sin importar el color de la categoría actual, para que las opciones siempre se lean. */
.admin-clientes__selector-tipo option {
  color: var(--color-text-invert);
}

/* Fila editable de alta manual (botón "+", 13.18) — un único <td colspan> con este <div>
   flex adentro, no 6 <td> individuales atados al reparto de columnas de la tabla (mismo
   patrón que .admin-tabla__grupo-contenido en Reservas, 13.6: un <td> con display:flex deja
   de comportarse como celda para table-layout:fixed). Bug real (reportado en producción):
   con 6 columnas reales, ese reparto dejaba el campo de Teléfono en ~41px de ancho real en
   un celular — imposible de tocar ("no puedo ni pararme en el campo"), aunque técnicamente
   nunca hubo scroll horizontal. Acá cada campo reflowea libre con flex-wrap, y en mobile
   pasa a columna única a ancho completo (mismo breakpoint que el resto del sitio, 768px,
   sección 4) — el único lugar de toda la tabla donde el layout no sigue las columnas de
   datos, porque es un formulario, no una fila de solo lectura.
   Mismo tratamiento visual que cualquier campo del sitio, pero sin <label> — los
   placeholders (Nombre/Apellido/teléfono) y la cabecera de columna que dejó de estar arriba
   ya dan suficiente contexto para un formulario de una sola fila. */
.admin-clientes__fila-nueva-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs) var(--space-sm);
  padding: var(--space-xs) 0;
}

.admin-clientes__fila-nueva-id {
  flex: 0 0 auto;
  min-width: 60px;
  color: var(--color-text-muted);
  font-size: var(--text-caption);
}

.admin-clientes__celda-doble {
  display: flex;
  flex: 1 1 220px;
  gap: var(--space-xs);
}

.admin-clientes__telefono-grupo {
  display: flex;
  align-items: center;
  flex: 1 1 160px;
  gap: 2px;
}

.admin-clientes__telefono-grupo .admin-clientes__input {
  flex: 1 1 auto;
}

.admin-clientes__fila-nueva-form select.admin-clientes__input {
  flex: 1 1 140px;
}

.admin-clientes__fila-nueva-form input[type='number'].admin-clientes__input {
  flex: 0 1 90px;
}

.admin-clientes__fila-nueva-acciones {
  display: flex;
  flex: 0 0 auto;
  gap: var(--space-xs);
}

.admin-clientes__input {
  width: 100%;
  min-width: 0;
  min-height: 44px;
  padding: 2px var(--space-xs);
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font-size: var(--text-caption);
}

.admin-clientes__input:disabled {
  opacity: 0.5;
}

@media (max-width: 767px) {
  .admin-clientes__fila-nueva-form {
    flex-direction: column;
    align-items: stretch;
  }

  .admin-clientes__celda-doble,
  .admin-clientes__telefono-grupo,
  .admin-clientes__fila-nueva-form select.admin-clientes__input,
  .admin-clientes__fila-nueva-form input[type='number'].admin-clientes__input {
    flex-basis: auto;
  }
}

.admin-clientes__prefijo {
  color: var(--color-text-muted);
  font-size: var(--text-caption);
  margin-right: 2px;
}

.admin-clientes__fila-nueva-estado {
  display: block;
  flex: 1 0 100%;
  color: var(--color-text-muted);
  font-size: var(--text-caption);
}

.admin-clientes__fila-nueva-estado--error {
  color: var(--color-error);
}

/* Mensaje compartido para un grupo filtrado de clientes */
.admin-clientes__grupal {
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-accent);
  border-radius: var(--radius-sm);
  padding: var(--space-md);
  margin-bottom: var(--space-md);
  max-width: 560px;
}

.admin-clientes__grupal textarea {
  width: 100%;
  min-height: 60px;
  background-color: var(--color-canvas);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font-family: inherit;
  font-size: var(--text-body);
  padding: var(--space-xs) var(--space-sm);
  resize: vertical;
}

.admin-clientes__grupal-nota {
  font-size: var(--text-caption);
  color: var(--color-text-muted);
  margin-top: var(--space-xs);
}

.admin-clientes__composer-fila td {
  background-color: var(--color-surface-deep);
  white-space: normal;
}

.admin-clientes__composer {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--space-sm);
  padding: var(--space-xs) 0;
}

.admin-clientes__mensaje {
  flex: 1;
  min-width: 220px;
  min-height: 44px;
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font-family: inherit;
  font-size: var(--text-body);
  padding: var(--space-xs) var(--space-sm);
  resize: vertical;
}

.admin-clientes__enviar {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  min-height: 44px;
  padding: 0 var(--space-md);
  background-color: var(--color-action-bg);
  color: var(--color-action-text);
  border-radius: var(--radius-sm);
  text-decoration: none;
  font-size: var(--text-caption);
  font-weight: var(--weight-medium);
  white-space: nowrap;
}

.admin-clientes__enviar--deshabilitado {
  opacity: 0.4;
  pointer-events: none;
}

/* Subtítulo de bloque dentro de una sección admin (13.20: "Precios de los cortes" /
   "Promociones", conviven en la misma pestaña) — misma tipografía que el título de
   tarjeta del Tablero (.tablero__tarjeta-titulo), sin token nuevo. */
.admin-seccion__subtitulo {
  font-size: var(--text-sub);
  color: var(--color-text);
  margin-bottom: var(--space-sm);
}

.admin-seccion__separador {
  border: none;
  border-top: var(--border-width) solid var(--color-border);
  margin: var(--space-xl) 0;
}

/* "Precios de los cortes" y "Promociones" (13.20) — decisión revisada: antes apilados con
   un <hr> separador, ahora lado a lado en recuadros propios (pedido explícito, "mejorar la
   visibilidad") — mismo patrón flex-wrap que .tablero__desglose-fila, se apilan solos en
   mobile cuando no entran los dos lado a lado. El <hr> ya no hace falta: el fondo propio de
   cada recuadro ya separa visualmente, incluso apilados. */
.admin-promos-fila {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-lg);
}

.admin-precios--recuadro,
.admin-promos-bloque--recuadro {
  background-color: var(--color-surface);
  border-radius: var(--radius-md);
  padding: var(--space-md);
  flex: 1;
  /* min(320px, 100%): el recuadro nunca es más ancho que su contenedor — con `min-width:
     320px` fijo, en un viewport de 360-375px el propio recuadro desbordaba unos px y metía
     scroll horizontal (viola DISEÑO 11/16). */
  min-width: min(320px, 100%);
}

/* Precios de los cortes (13.20) — edición por fila, guardado independiente, sin
   confirmación (no es una acción destructiva como Eliminar). */
.admin-precios__intro {
  color: var(--color-text-body);
  margin-bottom: var(--space-lg);
  max-width: 65ch;
}

.admin-precios__lista {
  list-style: none;
  max-width: 480px;
}

.admin-precios__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-sm) 0;
  border-bottom: var(--border-width) solid var(--color-border);
  /* En un recuadro angosto (mobile), nombre+duración y el campo $+Guardar no entran en una
     línea — que envuelvan en vez de desbordar. */
  flex-wrap: wrap;
}

.admin-precios__info {
  display: flex;
  flex-direction: column;
}

.admin-precios__nombre {
  color: var(--color-text);
  font-weight: var(--weight-medium);
}

.admin-precios__duracion {
  color: var(--color-text-muted);
  font-size: var(--text-caption);
  margin-top: var(--space-xs);
}

.admin-precios__form {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  flex-wrap: wrap;
}

.admin-precios__campo {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-xs) var(--space-sm);
}

.admin-precios__campo input {
  width: 80px;
  min-width: 0;
  background: none;
  border: none;
  color: var(--color-text);
  font-size: var(--text-body);
}

/* Precios y promos: sin las flechas de subir/bajar de a 1 (pedido explícito — no tiene
   sentido incrementar un precio de a $1). Se mantiene type="number" (teclado numérico en
   mobile, validación min) pero solo se escribe/borra el número. Aplica al precio de cada
   servicio y al % de descuento de las promos. */
.admin-promos-fila input[type='number'] {
  -moz-appearance: textfield;
  appearance: textfield;
}

.admin-promos-fila input[type='number']::-webkit-outer-spin-button,
.admin-promos-fila input[type='number']::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.admin-precios__form button[type='submit'] {
  min-height: 44px;
  padding: 0 var(--space-md);
  background-color: var(--color-action-bg);
  color: var(--color-action-text);
  border: none;
  border-radius: var(--radius-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
}

/* Estados obligatorios (14), mismo patrón que .admin-promos__estado */
.admin-precios__estado {
  font-size: var(--text-caption);
  width: 100%;
}

.admin-precios__estado--cargando {
  color: var(--color-text-muted);
}

.admin-precios__estado--exito {
  color: var(--color-success);
}

.admin-precios__estado--error {
  color: var(--color-error);
}

/* Promos (13.19) — gestión admin de lo que precios.js ya muestra en INDEX */
.admin-promos__intro {
  color: var(--color-text-body);
  margin-bottom: var(--space-lg);
  max-width: 65ch;
}

.admin-promos__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  max-width: 480px;
  margin-bottom: var(--space-xl);
}

.admin-promos__form-acciones {
  display: flex;
  gap: var(--space-sm);
}

.admin-promos__form button[type='submit'] {
  min-height: 44px;
  padding: 0 var(--space-md);
  background-color: var(--color-action-bg);
  color: var(--color-action-text);
  border: none;
  border-radius: var(--radius-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
}

.admin-promos__cancelar-edicion {
  min-height: 44px;
  padding: 0 var(--space-md);
  background: none;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-body);
  cursor: pointer;
}

.admin-promos__cancelar-edicion:hover {
  color: var(--color-accent);
}

/* Estados obligatorios (14) al guardar/eliminar — mismo patrón que .admin-walkin__estado */
.admin-promos__estado {
  font-size: var(--text-caption);
}

.admin-promos__estado--cargando {
  color: var(--color-text-muted);
}

.admin-promos__estado--exito {
  color: var(--color-success);
}

.admin-promos__estado--error {
  color: var(--color-error);
}

.admin-promos__lista {
  list-style: none;
  max-width: 640px;
}

.admin-promos__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-sm) 0;
  border-bottom: var(--border-width) solid var(--color-border);
}

.admin-promos__item-titulo {
  color: var(--color-text);
  font-weight: var(--weight-medium);
}

.admin-promos__item-detalle {
  color: var(--color-text-muted);
  font-size: var(--text-caption);
  margin-top: var(--space-xs);
}

.admin-promos__item-detalle--promo {
  color: var(--color-accent);
}

.admin-promos__vacio {
  color: var(--color-text-muted);
}

/* Más contraste tipográfico en el panel admin — es la pantalla de trabajo diaria de
   Lautaro, prioriza legibilidad por sobre la estética "midnight gallery" del lado
   cliente (esa sigue con --color-text-body como cuerpo, sin blanco puro, sección 2).
   Solo afecta admin.html — el calendario (calendario.js) se comparte con el cliente,
   así que estas reglas van con el prefijo body.admin para no tocar su versión pública. */
body.admin {
  color: var(--color-text);
}

body.admin .admin-tabla__vacio,
body.admin .tablero__desglose-vacio,
body.admin .calendario-vacio {
  color: var(--color-text-body);
}

body.admin .admin-tabla thead th {
  color: var(--color-text);
  font-weight: var(--weight-medium);
}

body.admin .campo__label,
body.admin .admin-accion-texto,
body.admin .admin-accion-wtp {
  color: var(--color-text);
}

/* Recordatorio/Reseña ya clickeados (13.7) — misma especificidad que la regla de arriba
   (body.admin .admin-accion-wtp), tiene que ir después en el archivo para ganar el empate
   por orden de aparición. El hover sigue mostrando dorado por encima (mayor especificidad,
   clase+pseudo-clase), así se nota que se puede volver a clickear si hace falta reenviar. */
body.admin .admin-accion-wtp--enviado {
  color: var(--color-badge-amarillo);
}

/* Footer (10.7) */
.footer {
  padding: var(--space-sm) var(--space-md) var(--space-md);
  text-align: center;
  font-size: var(--text-caption);
  color: var(--color-text-muted);
}

.footer__linea {
  margin-top: var(--space-xs);
}

.footer a {
  text-decoration: none;
}

.footer a:hover {
  color: var(--color-accent);
}

/* Landing (10.2): foto persistente de fondo, botones ocultos hasta que el splash se salta */
#landing.landing {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1;
  transition: opacity var(--duration-base) var(--ease-out);
}

.landing--saliendo {
  opacity: 0;
}

/* position: fixed (no absolute): así, aunque el documento llegue a rebotar en mobile, la
   foto y el scrim quedan clavados al viewport junto con el logo del splash (también fixed),
   sin despegarse. Mientras la landing está activa ocupan toda la pantalla; al pasar a
   [hidden] o a .landing--saliendo (opacity: 0 en #landing) desaparecen/funden con ella. */
.landing__foto {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  z-index: 0;
}

/* Mobile: el recorte vertical de `cover` sobre esta foto apaisada (1717×916) en una
   pantalla de celular deja ver solo ~1/4 del ancho. Centrado puro (50%) queda pesado a la
   derecha — el pilar blanco derecho ocupa medio encuadre y la pared izquierda no entra.
   42% corre el encuadre para centrarlo en el salón (las dos estaciones de corte quedan
   repartidas y el logo cae al medio). Valor para afinar en un celular real (DISEÑO.md 8). */
@media (max-width: 767px) {
  .landing__foto {
    object-position: 42% 50%;
  }
}

.landing__scrim {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  z-index: 1;
}

.landing__botones {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  width: 100%;
  max-width: 480px;
  padding: var(--space-md);
  pointer-events: none;
}

.landing__botones--visible {
  pointer-events: auto;
}

.cartel-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 56px;
  background-color: var(--color-action-bg);
  color: var(--color-action-text);
  border: var(--border-width) solid var(--color-accent);
  border-radius: var(--radius-sm);
  font-size: var(--text-sub);
  font-weight: var(--weight-medium);
  text-decoration: none;
  cursor: pointer;
  opacity: 0;
  transform: translateY(12px);
  transition: background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out),
              opacity var(--duration-base) var(--ease-out),
              transform var(--duration-base) var(--ease-out);
}

/* Entrada escalonada de los 4 botones (13.8) al salir del splash — stagger 60ms (DISEÑO.md 15) */
.landing__botones--visible .cartel-btn {
  opacity: 1;
  transform: translateY(0);
}

.landing__botones--visible .cartel-btn:nth-child(1) { transition-delay: 0ms; }
.landing__botones--visible .cartel-btn:nth-child(2) { transition-delay: 60ms; }
.landing__botones--visible .cartel-btn:nth-child(3) { transition-delay: 120ms; }
.landing__botones--visible .cartel-btn:nth-child(4) { transition-delay: 180ms; }

.cartel-btn:hover,
.cartel-btn:active {
  background-color: var(--color-accent-dim);
  color: var(--color-text);
}

.seccion {
  min-height: 50vh;
}

/* Flujo de reserva (13.15, 13.3, 13.4, 13.2) */
.reserva {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: var(--space-lg) var(--space-md);
}

.reserva__progreso {
  display: flex;
  gap: var(--space-xs);
  margin-bottom: var(--space-xs);
}

.progreso-segmento {
  flex: 1;
  height: 4px;
  background-color: var(--color-surface);
  border: var(--border-width) solid transparent;
  transition: background-color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
}

.progreso-segmento--completo {
  background-color: var(--color-accent);
}

.progreso-segmento--actual {
  background-color: var(--color-surface);
  border-color: var(--color-accent);
}

.reserva__paso-actual {
  font-size: var(--text-caption);
  color: var(--color-text);
  margin-bottom: var(--space-lg);
}

/* Aviso fijo arriba del calendario (paso 1) — nota tenue de una sola línea, sin recuadro
   (decisión revisada, pedido explícito: "que no quede con tanta relevancia"). Antes era una
   caja con fondo --color-surface y borde izquierdo, mismo patrón que .reserva__error; ahora
   es solo texto muted chico. Desaparece por JS (reserva.js) apenas se elige el tipo de
   corte — a esa altura el cartel de resumen ya dice servicio y día. Mismo tratamiento en
   mobile y desktop. */
.reserva__aviso-dias {
  color: var(--color-text-muted);
  margin-bottom: var(--space-sm);
  font-size: var(--text-caption);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.reserva__error {
  background-color: var(--color-surface);
  border-left: 3px solid var(--color-error);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  padding: var(--space-sm) var(--space-md);
  margin-bottom: var(--space-md);
  font-size: var(--text-caption);
}

/* Barra de confirmación visual del turno, entre "tipo de corte" y "tus datos" (13.4) */
.reserva__preview {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-accent);
  border-radius: var(--radius-sm);
  padding: var(--space-sm) var(--space-md);
  margin-bottom: var(--space-md);
}

.reserva__preview-resumen {
  color: var(--color-text);
  font-size: var(--text-sub);
}

.reserva__preview-acciones {
  display: flex;
  gap: var(--space-sm);
}

.reserva__preview-acciones button {
  min-height: 44px;
  padding: 0 var(--space-md);
  border-radius: var(--radius-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
}

.reserva__preview-confirmar {
  background-color: var(--color-action-bg);
  color: var(--color-action-text);
  border: none;
}

.reserva__preview-cambiar {
  background: none;
  color: var(--color-text-body);
  border: var(--border-width) solid var(--color-border);
}

.reserva__preview-cambiar:hover {
  color: var(--color-accent);
}

/* Aviso de reserva ya existente esa semana (cliente) — pide confirmar antes de reservar
   un segundo turno en la misma semana. Reusa .reserva__preview-acciones para los botones. */
.modal-confirmar__scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  background-color: rgba(0, 0, 0, 0.6);
}

.modal-confirmar__caja {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: var(--z-modal);
  background-color: var(--color-surface);
  border-radius: var(--radius-md);
  padding: var(--card-padding);
  max-width: 360px;
  width: calc(100% - var(--space-md) * 2);
}

.modal-confirmar__texto {
  color: var(--color-text);
  margin-bottom: var(--space-md);
}

/* Navegador de fecha/semana (13.3) */
.calendario-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}

.calendario-nav__flecha {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  background: none;
  border: none;
  color: var(--color-text-body);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-out);
}

.calendario-nav__flecha:hover:not(:disabled) {
  color: var(--color-accent);
}

.calendario-nav__flecha:disabled {
  color: var(--color-text-muted);
  opacity: 0.4;
  cursor: not-allowed;
}

.calendario-nav__fecha {
  min-width: 220px;
  text-align: center;
  font-size: var(--text-sub);
  color: var(--color-text);
}

.calendario-vacio {
  text-align: center;
  color: var(--color-text-muted);
  padding: var(--space-2xl) var(--space-md);
}

/* Grilla — mobile: un día, 3 columnas */
.calendario-grilla--dia {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-xs);
}

/* Grilla — desktop: semana laboral (martes a sábado, 5 columnas — DISEÑO.md 13.3) */
.calendario-grilla--semana {
  display: grid;
  grid-template-columns: 64px repeat(5, 1fr);
  grid-auto-rows: minmax(40px, auto);
  gap: var(--space-unit);
  align-items: stretch;
}

/* Separador visual mañana/tarde (13.3) — mismo alto que una unidad laboral, sin botón */
.calendario-spacer {
  grid-column: 1 / -1;
  min-height: 22px;
}

.calendario-grilla--dia .calendario-spacer {
  grid-column: 1 / -1;
  min-height: 44px;
}

/* Encabezados de día y hora (eje X/Y) — un escalón más grandes y más claros que los
   números de las U laborales dentro de la grilla (--text-caption, --color-text-muted),
   para que se lean como referencia del calendario, no como una celda más. */
.calendario-grilla__cab-dia {
  text-align: center;
  font-size: var(--text-body);
  color: var(--color-text);
  padding: var(--space-xs) 0;
  border-bottom: var(--border-width) solid var(--color-border);
}

.calendario-grilla__cab-dia--hoy {
  color: var(--color-accent);
  border-bottom-color: var(--color-accent);
}

.calendario-grilla__cab-hora {
  font-size: var(--text-body);
  color: var(--color-text);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding-right: var(--space-xs);
}

.calendario-slot {
  position: relative;
  min-height: 44px;
  background-color: var(--color-surface);
  color: var(--color-text);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--text-caption);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}

/* Hora extra (13.3, solo admin): círculo dorado chico, margen superior izquierdo — indica
   nada más que "hay 2 cortes en esta unidad". El cliente nunca la ve (agregado solo en la
   rama !modoCliente de crearBotonSlot). */
.calendario-slot__hora-extra {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background-color: var(--color-accent);
}

.calendario-slot:hover:not(:disabled) {
  background-color: var(--color-surface-hover);
}

/* U laboral elegida por el cliente en el flujo de reserva (13.3/13.4, "Seleccionado"):
   fondo gris + contorno dorado 2px, mismo peso visual que el contorno blanco de las
   disponibles (.calendario-slot--contorno). Se marca en su lugar dentro de la grilla, una
   celda por unidad del rango — no como bloque fundido (ver construirElementosDia). */
.calendario-slot--seleccionado {
  border-color: var(--color-accent);
  border-width: 2px;
  color: var(--color-accent);
  background-color: var(--color-surface-hover);
}

/* Disponible, calendario del cliente: contorno blanco además del fondo gris de .calendario-slot */
.calendario-slot--contorno {
  border-color: var(--color-action-bg);
  border-width: 2px;
}

/* Iniciales de disponibilidad por barbero (13.3, solo con 2+ barberos activos) — margen
   superior de la unidad laboral, informativas: verde si ese barbero está libre ahí, gris
   si no. El color es de disponibilidad, no de identidad — mismo criterio para los dos.
   Grid de 3 columnas (candado izquierdo / grupo de iniciales / candado derecho), no flex:
   cada columna lateral reserva su espacio aunque esté vacía (cliente, unidad pasada, o ese
   barbero con un turno real ahí — crearIniciales, calendario.js), así el grupo del centro
   siempre queda centrado en la unidad sin importar si hay 0, 1 o 2 candados presentes. */
.calendario-slot__iniciales {
  display: grid;
  grid-template-columns: 14px 1fr 14px;
  align-items: center;
  width: 100%;
  margin-bottom: 2px;
}

.calendario-slot__inicial-grupo {
  grid-column: 2;
  display: flex;
  justify-content: center;
  gap: 4px;
}

.calendario-slot__inicial {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: var(--radius-full);
  font-size: 10px;
  font-weight: var(--weight-medium);
  color: var(--color-text-invert);
}

.calendario-slot__inicial--libre {
  background-color: var(--color-success);
}

.calendario-slot__inicial--ocupado {
  background-color: var(--color-text-muted);
}

/* Candado por barbero (solo admin, 2+ barberos activos) — uno en cada punta lateral de la
   unidad, misma línea que las iniciales — reemplaza, para este caso, al candado único de
   .calendario-slot__bloqueo (más abajo, sigue siendo el de 1 solo barbero). Excepción
   documentada al área táctil mínima de 44px (sección 16), más chica todavía que la del
   candado único (20px, ya excepción) — a este tamaño de celda no hay lugar para dos
   candados de 44px sin taparse entre sí ni tapar el botón de reservar. */
.calendario-slot__inicial-candado {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  padding: 0;
  background: none;
  border: none;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-out);
}

.calendario-slot__inicial-candado--izq {
  grid-column: 1;
  justify-self: start;
}

.calendario-slot__inicial-candado--der {
  grid-column: 3;
  justify-self: end;
}

.calendario-slot__inicial-candado:hover,
.calendario-slot__inicial-candado:focus-visible {
  color: var(--color-accent);
}

/* Días ya pasados de la semana visible (cliente): rectángulo vacío, sin horario ni tachado */
.calendario-slot--vacio-pasado {
  background-color: transparent;
  border-color: var(--color-turno-pendiente);
  opacity: 0.35;
  cursor: default;
}

/* Nota de "reserva cancelada" sobre un horario que volvió a quedar libre (solo admin):
   sigue siendo un horario disponible normal — el acento rojo es solo una referencia,
   no un bloqueo. Clickeable salvo que además esté --pasado. */
.calendario-slot--nota-cancelada {
  border-color: var(--color-turno-cancelado);
}

.calendario-slot__detalle--cancelado {
  color: var(--color-turno-cancelado);
}

/* Más de un turno real en la misma unidad (2 barberos, o barbero + hora extra, 13.3) — el
   fondo/borde de la celda quedan neutros (no puede ser "de un solo estado" cuando hay uno
   Pagado y otro No pagado a la vez) y cada línea de turno lleva su propio color, ver abajo. */
.calendario-slot--multiple {
  background-color: transparent;
  border-color: var(--color-border);
  color: var(--color-text);
}

/* A diferencia de reserva/pagado/gratis/pasado (siempre no-clickeables), esta clase se usa
   tanto en unidades reservables (mixta: uno ocupado, otro libre) como no — el cursor sigue
   al estado real `disabled` del botón, no a la clase de color. */
.calendario-slot--multiple:disabled {
  cursor: not-allowed;
}

.calendario-slot__cliente--pagado,
.calendario-slot__detalle--pagado {
  color: var(--color-turno-pagado);
}

.calendario-slot__cliente--gratis,
.calendario-slot__detalle--gratis {
  color: var(--color-turno-gratis);
}

/* Contenido detallado (solo admin): nombre del cliente, tipo de corte y estado de pago
   dentro de la misma celda del turno — cliente/hora/estado ya se distingue por color. */
.calendario-slot--detallado,
.calendario-bloque--detallado {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 2px;
  text-align: left;
  padding: var(--space-xs);
  height: auto;
}

.calendario-slot__hora {
  font-size: var(--text-caption);
  font-weight: var(--weight-medium);
}

.calendario-slot__cliente {
  font-size: var(--text-caption);
  font-weight: var(--weight-medium);
  white-space: normal;
  overflow-wrap: anywhere;
}

.calendario-slot__detalle {
  font-size: var(--text-caption);
  opacity: 0.85;
  white-space: normal;
}

.calendario-slot--reserva,
.calendario-slot--pagado,
.calendario-slot--gratis,
.calendario-slot--pasado {
  cursor: not-allowed;
}

/* Reserva futura no concretada (No pagado) — para el cliente, cualquier horario tomado sea
   cual sea su estado real. Fondo sólido gris + texto blanco, sin tachado — a diferencia del
   resto de los estados (color solo en borde/texto), esta es la variante "por defecto". */
.calendario-slot--reserva {
  background-color: var(--color-turno-pendiente);
  border-color: var(--color-turno-pendiente);
  color: var(--color-action-bg);
}

.calendario-slot--pagado {
  background-color: transparent;
  border-color: var(--color-turno-pagado);
  color: var(--color-turno-pagado);
}

/* Gratis: asignación manual del admin, sin relación con el descuento de fidelidad (13.17) */
.calendario-slot--gratis {
  background-color: transparent;
  border-color: var(--color-turno-gratis);
  color: var(--color-turno-gratis);
}

/* Horario pasado que nunca tuvo reserva (o cuya reserva ahí se canceló, ver la nota de
   arriba): apagado, sin tachado — ya cerró, no hace falta remarcarlo más que con el color. */
.calendario-slot--pasado {
  background-color: transparent;
  border-color: var(--color-turno-pendiente);
  color: var(--color-turno-pendiente);
}

/* Horario bloqueado por el admin (sin turno real, ej. un turno médico) — mismo tratamiento
   apagado que --pasado, cursor not-allowed: no es un turno, pero tampoco se puede reservar. */
.calendario-slot--bloqueado {
  background-color: transparent;
  border-color: var(--color-turno-pendiente);
  color: var(--color-turno-pendiente);
  cursor: not-allowed;
}

/* "Ver calendario" del ticket (13.17): el turno propio del cliente, revelado en detalle, se
   distingue del resto de las unidades ocupadas (gris genérico) con contorno dorado. Va
   después de --reserva/--pagado/--gratis/--pasado a propósito (misma especificidad, gana por
   orden de aparición — sin esto el gris de --reserva lo tapaba). */
.calendario-slot--propio {
  border-color: var(--color-accent);
}

/* Celda que envuelve un botón de horario + el ícono candado (solo admin, 13.3) — position:
   relative para anclar el ícono en la esquina, sin anidar un <button> dentro de otro. */
.calendario-slot-celda {
  position: relative;
}

.calendario-slot-celda .calendario-slot {
  width: 100%;
  height: 100%;
}

/* Excepción documentada al área táctil mínima de 44px (sección 16): a este tamaño de
   celda de calendario no entra un ícono de 44px sin tapar el botón de reservar de abajo.
   Se compensa con separación del borde y un color de foco/hover bien visible. */
.calendario-slot__bloqueo {
  position: absolute;
  top: 2px;
  right: 2px;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  background-color: var(--color-surface-deep);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
}

.calendario-slot__bloqueo:hover,
.calendario-slot__bloqueo:focus-visible {
  color: var(--color-accent);
  border-color: var(--color-accent);
}

/* Bloque fundido: turnos de más de 1 unidad y la preview de selección en curso (13.3) —
   una sola celda que abarca visualmente todas las unidades del turno, no N celdas separadas. */
.calendario-bloque {
  min-height: 44px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-xs);
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--text-caption);
  text-align: center;
  cursor: not-allowed;
}

.calendario-grilla--dia .calendario-bloque {
  grid-column: 1 / -1;
}

/* Va después de la regla base .calendario-bloque (arriba) para ganar el empate de
   especificidad por orden de aparición — antes vivía junto a .calendario-slot--reserva,
   antes de la base, y la base le ganaba el empate (mismo mecanismo que ya se documenta
   para .admin-tabla__grupo, sin !important). */
.calendario-bloque--reserva {
  background-color: var(--color-turno-pendiente);
  border-color: var(--color-turno-pendiente);
  color: var(--color-action-bg);
}

.calendario-bloque--seleccionado {
  border-color: var(--color-accent);
  color: var(--color-accent);
  background-color: var(--color-surface-hover);
  cursor: default;
  text-decoration: none;
}

.calendario-bloque--pagado {
  background-color: transparent;
  border-color: var(--color-turno-pagado);
  color: var(--color-turno-pagado);
}

.calendario-bloque--gratis {
  background-color: transparent;
  border-color: var(--color-turno-gratis);
  color: var(--color-turno-gratis);
}

/* Desplegable de tipo de corte (13.4) */
.tipo-corte__popover {
  position: absolute;
  z-index: var(--z-overlay);
  width: 260px;
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-xs);
}

.tipo-corte__scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  background-color: rgba(0, 0, 0, 0.6);
}

.tipo-corte__hoja {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: var(--z-modal);
  background-color: var(--color-surface);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  padding: var(--space-md);
  max-height: 70vh;
  overflow-y: auto;
  /* Sube desde abajo (13.4) — arranca fuera de pantalla, calendario.js agrega el
     modificador --visible un tick después de montarla para que el navegador anime la
     transición en vez de aparecer ya en su posición final. */
  transform: translateY(100%);
  transition: transform var(--duration-fast) var(--ease-out);
}

.tipo-corte__hoja--visible {
  transform: translateY(0);
}

.tipo-corte__cerrar {
  display: block;
  margin-left: auto;
  width: 44px;
  height: 44px;
  background: none;
  border: none;
  color: var(--color-text-body);
  cursor: pointer;
  font-size: var(--text-sub);
}

.tipo-corte__lista {
  display: flex;
  flex-direction: column;
}

.tipo-corte__item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 44px;
  padding: var(--space-xs) var(--space-sm);
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out);
}

.tipo-corte__item:hover,
.tipo-corte__item:focus-visible {
  background-color: var(--color-surface-hover);
}

.tipo-corte__item-fila {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

.tipo-corte__item-detalle {
  font-size: var(--text-caption);
  color: var(--color-text-muted);
  white-space: nowrap;
}

/* "Corte amigo" en el desplegable, solo visible en el flujo walk-in del admin (13.4) */
.tipo-corte__item--admin {
  border: var(--border-width) solid var(--color-accent-dim);
}

.tipo-corte__item-badge {
  font-size: var(--text-caption);
  color: var(--color-text-muted);
  white-space: nowrap;
}

/* Promo reservable en el desplegable (13.4) — mismo patrón que "Corte amigo" arriba, pero
   en el dorado normal (no el apagado) para que se sienta un destaque, no un aviso neutro. */
.tipo-corte__item--promo {
  border: var(--border-width) solid var(--color-accent);
}

.tipo-corte__item-badge--promo {
  color: var(--color-accent);
  /* A diferencia de "Solo admin" arriba (texto fijo y corto), el título de la promo lo
   * escribe el admin y puede ser largo — sin esto heredaba white-space: nowrap de
   * .tipo-corte__item-badge y se cortaba a la mitad contra el ancho fijo del popover (13.4). */
  white-space: normal;
  overflow-wrap: anywhere;
}

/* Paso "Tus datos" */

/* Autocompletado de nombre (13.2.1) — mismo tratamiento visual que el desplegable de tipo
   de corte (.tipo-corte__item/__popover) para no introducir un lenguaje nuevo. Namespace
   .campo (genérico) en vez de .reserva porque este componente se reusa también en el
   walk-in del admin (autocompletado.js) — el mismo bloque "campo" ya usan otros campos
   de formulario en todo el sitio. */
.campo--con-sugerencias {
  position: relative;
}

.campo__sugerencias {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: var(--z-overlay);
  margin-top: var(--space-xs);
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-xs);
  list-style: none;
  max-height: 220px;
  overflow-y: auto;
}

.campo__sugerencia {
  display: block;
  width: 100%;
  min-height: 44px;
  padding: var(--space-xs) var(--space-sm);
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out);
}

.campo__sugerencia:hover,
.campo__sugerencia:focus-visible {
  background-color: var(--color-surface-hover);
}

.reserva__volver {
  display: inline-block;
  background: none;
  border: none;
  color: var(--color-text-body);
  cursor: pointer;
  padding: var(--space-xs) 0;
  margin-bottom: var(--space-sm);
  transition: color var(--duration-fast) var(--ease-out);
}

.reserva__volver:hover {
  color: var(--color-accent);
}

.reserva__resumen {
  color: var(--color-text);
  margin-bottom: var(--space-lg);
}

.reserva__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  max-width: 480px;
}

.campo {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.campo__label {
  font-size: var(--text-caption);
  color: var(--color-text-body);
}

.campo input,
.campo select {
  min-height: 44px;
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font-size: var(--text-body);
  padding: 0 var(--space-sm);
}

/* Checkbox "Ya pagó" (walk-in del admin) — la fila entera del <label> es el área táctil,
   no solo el cuadradito nativo del checkbox. */
.campo--checkbox {
  flex-direction: row;
  align-items: center;
  gap: var(--space-xs);
  min-height: 44px;
  cursor: pointer;
}

.campo--checkbox input[type='checkbox'] {
  width: 20px;
  height: 20px;
  accent-color: var(--color-accent);
  cursor: pointer;
}

.campo--checkbox span {
  color: var(--color-text);
}

.campo__telefono {
  display: flex;
  align-items: stretch;
  gap: var(--space-xs);
}

.campo__prefijo {
  display: flex;
  align-items: center;
  padding: 0 var(--space-sm);
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
}

.campo__telefono input {
  flex: 1;
}

.campo__error {
  font-size: var(--text-caption);
  color: var(--color-error);
}

.reserva__form button[type='submit'] {
  min-height: 44px;
  background-color: var(--color-action-bg);
  color: var(--color-action-text);
  border: none;
  border-radius: var(--radius-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
}

.reserva__form button[type='submit']:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.reserva__form-estado {
  font-size: var(--text-caption);
}

.reserva__form-estado--cargando {
  color: var(--color-text-muted);
}

.reserva__form-estado--exito {
  color: var(--color-success);
}

.reserva__form-estado--error {
  color: var(--color-error);
}

/* Confirmación (13.15, paso 4) — única excepción de foto de fondo dentro del flujo de
   reserva (DISEÑO.md 8): vuelve a la misma foto del splash/landing como cierre de marca,
   una vez que ya no hay datos por completar. El resto del flujo sigue en negro sólido. */
.reserva__paso--confirmacion {
  /* Rompe el max-width/padding centrado de .reserva para ocupar todo el ancho de la
     pantalla, igual que el splash/landing — sigue en el flujo normal del documento
     (no position:fixed) para que el indicador de progreso, justo arriba, no quede tapado. */
  position: relative;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
  width: 100vw;
  overflow: hidden;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-lg) var(--space-md);
}

.reserva__confirmacion-foto {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}

.reserva__confirmacion-scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  z-index: 1;
}

.reserva__confirmacion {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

.reserva__confirmacion .cartel-btn {
  max-width: 320px;
  margin-top: var(--space-md);
}

/* Ticket de reserva confirmada */
.ticket {
  background-color: var(--color-surface);
  border-radius: var(--radius-md);
  border: var(--border-width) solid var(--color-text);
  padding: var(--card-padding);
  max-width: 400px;
  width: 100%;
}

.ticket__encabezado {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
  text-align: center;
  color: var(--color-accent);
}

.ticket__encabezado h2 {
  color: var(--color-text);
}

.ticket__separador {
  border: none;
  border-top: var(--border-width) dashed var(--color-border);
  margin: var(--space-md) 0;
}

.ticket__detalle {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.ticket__detalle-fila {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
}

.ticket__detalle-fila dt {
  color: var(--color-text-muted);
  font-size: var(--text-caption);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.ticket__detalle-fila dd {
  color: var(--color-text);
  font-weight: var(--weight-medium);
  text-align: right;
}

.ticket__aviso {
  font-size: var(--text-caption);
  color: var(--color-text-muted);
  margin-bottom: var(--space-sm);
}

/* Aviso de forma de pago (transferencia/local) — se destaca en blanco del resto de los
   avisos grises porque es información accionable, mismo criterio que .ticket__direccion. */
.ticket__aviso--pago {
  color: var(--color-text);
}

.ticket__direccion {
  font-size: var(--text-caption);
  color: var(--color-text);
  font-weight: var(--weight-medium);
  margin-bottom: var(--space-sm);
}

.ticket__aviso-descuento {
  font-size: var(--text-caption);
  color: var(--color-turno-gratis);
  font-weight: var(--weight-medium);
  margin-bottom: var(--space-sm);
}

.ticket__whatsapp {
  display: block;
  font-size: var(--text-caption);
  color: var(--color-text-body);
  text-decoration: underline;
  transition: color var(--duration-fast) var(--ease-out);
}

.ticket__whatsapp:hover {
  color: var(--color-accent);
}

/* "Ver calendario" (13.17, pedido explícito): dorado siempre, no solo al hover como el link
   de WhatsApp de arriba — mismo tratamiento tipográfico (tamaño, subrayado), es un <button>
   (navegación interna sin URL real) pero se ve como cualquier otro link del ticket. */
.ticket__ver-calendario {
  display: block;
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  margin-top: var(--space-sm);
  font: inherit;
  font-size: var(--text-caption);
  color: var(--color-accent);
  text-decoration: underline;
  cursor: pointer;
  text-align: left;
}

/* Precios y cortes (13.9, 13.10) */
.precios {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: var(--space-lg) var(--space-md);
}

.precios__titulo {
  margin-bottom: var(--space-lg);
  text-align: center;
}

.precios__promos {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-bottom: var(--space-xl);
}

.cartel-promo {
  background-color: var(--color-surface);
  border-left: 3px solid var(--color-accent);
  border-radius: var(--radius-sm);
  padding: var(--space-sm) var(--space-md);
}

.cartel-promo__titulo {
  color: var(--color-text);
  font-weight: var(--weight-medium);
}

.cartel-promo__detalle {
  color: var(--color-text);
  font-size: var(--text-caption);
  margin-top: var(--space-xs);
}

.precios__grilla {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--space-md);
}

/* Desktop: 3 tarjetas por fila (antes hasta 5). Con la tipografía más grande (--text-heading
   en nombre y precio, 13.9) las tarjetas angostas de una grilla de 5 partían "Corte solo" en
   dos líneas; a 3 por fila el nombre entra en una sola. Mobile sigue en una columna. */
@media (min-width: 768px) {
  .precios__grilla {
    grid-template-columns: repeat(3, 1fr);
  }
}

.tarjeta-servicio {
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-text);
  border-radius: var(--radius-md);
  padding: var(--card-padding);
  text-align: center;
}

/* Tipografía más grande (pedido explícito, general): las tarjetas tenían mucho aire vacío
   alrededor de un título/precio chicos. Nombre y precio suben a --text-heading, duración a
   --text-body — así el texto llena el cuadro y se lee mejor. Tokens existentes de DISEÑO.md,
   nada inventado. */
.tarjeta-servicio__nombre {
  font-size: var(--text-heading);
  margin-bottom: var(--space-sm);
}

.tarjeta-servicio__precio {
  color: var(--color-accent);
  font-size: var(--text-heading);
  font-weight: var(--weight-medium);
  line-height: var(--leading-heading);
}

.tarjeta-servicio__duracion {
  color: var(--color-text-muted);
  font-size: var(--text-body);
  margin-top: var(--space-xs);
}

/* Mis cortes (13.12) — todo centrado: el bloque como unidad (flex column + align-items)
   y el texto dentro de cada hijo (text-align), heredado por .campo/.fidelidad__historial
   sin tocar esas reglas compartidas con el resto del sitio (solo aplica dentro de esta
   sección, por cascada de herencia, no por selector). */
.fidelidad {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: var(--space-lg) var(--space-md);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.fidelidad__titulo {
  margin-bottom: var(--space-sm);
}

.fidelidad__intro {
  color: var(--color-text-body);
  margin-bottom: var(--space-lg);
  max-width: 65ch;
}

.fidelidad__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  max-width: 480px;
}

.fidelidad__form button[type='submit'] {
  min-height: 44px;
  background-color: var(--color-action-bg);
  color: var(--color-action-text);
  border: none;
  border-radius: var(--radius-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
}

.fidelidad__resultado {
  margin-top: var(--space-lg);
  font-size: var(--text-sub);
}

.fidelidad__resultado--cargando {
  color: var(--color-text-muted);
}

.fidelidad__resultado--error {
  color: var(--color-error);
}

.fidelidad__resultado--vacio {
  color: var(--color-text-muted);
}

.fidelidad__resultado--exito {
  color: var(--color-text);
}

.fidelidad__historial {
  list-style: none;
  max-width: 480px;
  margin-top: var(--space-lg);
}

.fidelidad__historial-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-sm) 0;
  border-bottom: var(--border-width) solid var(--color-border);
  color: var(--color-text);
}

.fidelidad__historial-estado {
  font-size: var(--text-caption);
  font-weight: var(--weight-medium);
  white-space: nowrap;
  color: var(--color-turno-pendiente);
}

.fidelidad__historial-estado--pagado {
  color: var(--color-turno-pagado);
}

.fidelidad__historial-estado--cancelado {
  color: var(--color-turno-cancelado);
}

.fidelidad__historial-estado--gratis {
  color: var(--color-turno-gratis);
}

/* Línea de cortes acreditados a mano (alta manual con "Cant. cortes", 13.18) — no es un
   turno real, se distingue en itálica y con color neutro para no confundirla con las
   demás filas del historial. */
.fidelidad__historial-item--acreditado {
  font-style: italic;
  color: var(--color-text-muted);
}

.fidelidad__historial-estado--acreditado {
  color: var(--color-text-muted);
}

/* Turno real anterior a la fecha base de un acreditado manual (13.18) — ya está sumado en
   la línea "acreditados" de arriba, así que el badge se ve neutro en vez del verde de Pagado
   normal, para que la suma visible nunca dé más que el número de arriba. */
.fidelidad__historial-estado--no-cuenta {
  color: var(--color-text-muted);
}

