/* =========================================================================
   EL BÚNKER — hoja de estilos única
   Consolidada desde docs/identidad-visual-bunker.md.
   El repo viejo tenía el sistema copiado a mano en 6 páginas; acá vive
   una sola vez. Todo lo nuevo se agrega en su sección, no se duplica.
   ========================================================================= */

/* -------------------------------------------------------------------------
   0. FUENTE PROPIA — Bebas Neue, autohospedada
   Es la que más se nota si tarda: el número de puntos y el nombre de
   nivel de la tarjeta son Bebas a full tamaño. Si esperara a Google
   Fonts (dos saltos: la hoja de estilos y despues el archivo) el cambio
   de fuente se veía como un parpadeo grande en el elemento más
   importante de la pantalla. Autohospedada + precargada (layout.html)
   ese salto queda en uno solo.
   font-display: swap, no optional: con el preload el parpadeo ya es
   mínimo, y swap garantiza que la tarjeta siempre termine en Bebas
   real — con optional, un cliente entrando por primera vez con mala
   señal (3G) se podía quedar con el fallback (Arial Narrow) toda la
   sesión.
   Inter y JetBrains Mono se quedan en Google Fonts (ver layout.html):
   ya piden display=swap ahí, y separar sus archivos por peso a mano
   pedía replicar la negociación de Google Fonts por user-agent, que no
   es algo que se pueda hacer bien a ciegas. */
@font-face {
  font-family: 'Bebas Neue';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/bebas-neue-400.woff2') format('woff2');
}

/* -------------------------------------------------------------------------
   1. TOKENS
   ------------------------------------------------------------------------- */
:root {
  /* Fondos */
  --bg: #0a0a0a;
  --bg-1: #131313;
  --bg-2: #1a1a1a;
  --bg-3: #232323;
  --bg-deep: #050505;

  /* Bordes */
  --border: #2a2a2a;
  --border-strong: #3a3a3a;
  --border-bright: #4a4a4a;

  /* Texto */
  --text: #faf7ee;
  --text-soft: #d4cfc2;
  --text-mute: #807a6e;
  --text-dim: #4a4540;

  /* Acento — dorado único de la marca.
     Es el color de detalle Y el fondo del botón primario.
     La convención --warm del repo viejo queda eliminada. */
  --accent: #d9a55e;
  --accent-ink: #0a0a0a;
  --accent-rgb: 217, 165, 94;

  /* Semánticos */
  --success: #84bb6e;
  --danger: #c85b5b;
  --info: #6e9cbb;

  /* Radios */
  --radius: 4px;
  --radius-md: 6px;
  --radius-lg: 10px;
  --radius-xl: 16px;

  /* Sombras */
  --shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
  --shadow-sm: 0 4px 12px rgba(0, 0, 0, 0.4);
  --shadow-lg: 0 8px 40px rgba(0, 0, 0, 0.6);
  --shadow-accent: 0 8px 28px rgba(var(--accent-rgb), 0.18);
  --shadow-accent-hover: 0 12px 34px rgba(var(--accent-rgb), 0.26);

  /* Espaciado — escala de 4px. El repo viejo escribía los valores a mano;
     acá quedan tokenizados. */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-7: 28px;
  --sp-8: 32px;
  --sp-10: 40px;
  --sp-11: 44px;
  --sp-12: 48px;
  --sp-16: 64px;

  /* Tipografía */
  --font-display: 'Bebas Neue', 'Arial Narrow', sans-serif;
  --font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'Courier New', monospace;

  /* Duraciones — 150ms es el estándar del sistema */
  --t-fast: 120ms;
  --t: 150ms;
  --t-slow: 200ms;
  --ease-settle: cubic-bezier(0.2, 0, 0, 1);
  /* Curva del prototipo de la tarjeta: entra rapido y se posa. */
  --ease-carta: cubic-bezier(0.2, 0.7, 0.2, 1);

  /* Layout */
  --wrap: 720px;
}

/* -------------------------------------------------------------------------
   2. BASE
   ------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html,
body {
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--text-soft);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background-image:
    radial-gradient(1200px 600px at 50% -200px, rgba(var(--accent-rgb), 0.08), transparent 60%),
    linear-gradient(180deg, var(--bg) 0%, var(--bg-deep) 100%);
  background-attachment: fixed;
}

::selection {
  background: var(--accent);
  color: var(--bg);
}

a {
  color: inherit;
}

/* height:auto de base: cualquier <img> con width y height como atributos
   HTML (para reservar el espacio y evitar CLS) más un ancho en CSS —
   .logo img y .wmark son el caso que se rompió — necesita esto para que
   el alto lo calcule el navegador a partir del intrínseco, no del
   atributo suelto. */
img,
svg {
  max-width: 100%;
  height: auto;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--sp-5);
  flex: 1;
  display: flex;
  flex-direction: column;
}

/* -------------------------------------------------------------------------
   3. HERO
   ------------------------------------------------------------------------- */
.hero {
  text-align: center;
  padding: var(--sp-16) var(--sp-4) var(--sp-10);
}

.hero-logo {
  width: 132px;
  height: 132px;
  margin: 0 auto var(--sp-6);
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero-logo svg,
.hero-logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.hero-name {
  font-family: var(--font-display);
  font-size: 60px;
  font-weight: 400;
  letter-spacing: 0.16em;
  color: var(--text);
  line-height: 0.95;
  margin-bottom: 10px;
}

/* Triángulo dorado bajo el nombre */
.hero-accent {
  display: block;
  width: 0;
  height: 0;
  margin: var(--sp-1) auto var(--sp-4);
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
  border-bottom: 14px solid var(--accent);
}

.hero-tag {
  font-size: 13px;
  letter-spacing: 0.06em;
  color: var(--text-soft);
  margin-bottom: 6px;
}

.hero-sub {
  font-size: 11px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--text-mute);
}

/* -------------------------------------------------------------------------
   4. BOTONES
   ------------------------------------------------------------------------- */
.btn,
.btn-ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  /* Alto de 44px: la vertical de --sp-4 (16px) sumada al line-height del
     texto se pasaba de los 44px que pide la escala de botones. */
  min-height: 44px;
  padding: var(--sp-2) var(--sp-12);
  border-radius: var(--radius-md);
  cursor: pointer;
  border: 1px solid transparent;
  transition: transform var(--t) ease, box-shadow var(--t) ease,
    filter var(--t) ease, background var(--t) ease, color var(--t) ease,
    border-color var(--t) ease;
}

/* Primario: dorado sólido */
.btn {
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow: var(--shadow-accent);
}

.btn:hover {
  filter: brightness(1.06);
  transform: translateY(-1px);
  box-shadow: var(--shadow-accent-hover);
}

.btn:active {
  transform: translateY(0);
}

/* Secundario: borde dorado, fondo transparente */
.btn-ghost {
  background: transparent;
  color: var(--accent);
  border-color: rgba(var(--accent-rgb), 0.45);
  box-shadow: none;
}

.btn-ghost:hover {
  border-color: var(--accent);
  background: rgba(var(--accent-rgb), 0.07);
  transform: translateY(-1px);
}

.btn:disabled,
.btn-ghost:disabled,
.btn[aria-disabled='true'] {
  opacity: 0.35;
  cursor: not-allowed;
  transform: none;
  filter: none;
}

.btn-sm {
  font-size: 12px;
  padding: 10px var(--sp-5);
  letter-spacing: 0.16em;
  /* Aunque el botón sea "chico", el área tocable no baja de 44px. */
  min-height: 44px;
}

.btn-block {
  width: 100%;
}

/* -------------------------------------------------------------------------
   5. ACCIONES DEL LANDING + LINK SOCIAL
   ------------------------------------------------------------------------- */
.actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  margin: var(--sp-2) 0 var(--sp-11);
}

.actions .btn,
.actions .btn-ghost {
  min-width: 288px;
}

.social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  /* Target táctil de 44px, aunque el texto mida 12px. */
  min-height: 44px;
  padding: 0 var(--sp-3);
  color: var(--text-mute);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-decoration: none;
  transition: color var(--t) ease;
}

.social:hover {
  color: var(--accent);
}

.social svg {
  width: 22px;
  height: 22px;
  display: block;
}

/* -------------------------------------------------------------------------
   6. PANEL (superficie genérica) + INFO + MAPA
   ------------------------------------------------------------------------- */
.panel {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  /* Recorta el iframe del mapa contra las esquinas redondeadas. */
  overflow: hidden;
  margin-bottom: var(--sp-7);
}

.info {
  display: grid;
  grid-template-columns: 1fr;
}

.info-item {
  padding: 22px var(--sp-5);
  border-bottom: 1px solid var(--border);
  text-align: center;
}

.info-item:last-child {
  border-bottom: none;
}

.info-label {
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-mute);
  margin-bottom: var(--sp-2);
}

.info-value {
  font-size: 13px;
  color: var(--text-soft);
  line-height: 1.45;
}

.info-value a {
  color: var(--accent);
  text-decoration: none;
}

.info-value a:hover {
  text-decoration: underline;
}

/* WhatsApp: ícono + número, en un target de 44px de alto para que se
   entienda que es tocable. */
.info-wa {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 44px;
  padding: 0 var(--sp-2);
  white-space: nowrap;
}

.info-wa svg {
  width: 18px;
  height: 18px;
  flex: none;
}

@media (min-width: 560px) {
  .info {
    grid-template-columns: repeat(3, 1fr);
  }

  .info-item {
    border-bottom: none;
    border-right: 1px solid var(--border);
  }

  .info-item:last-child {
    border-right: none;
  }
}

/* line-height:0 mata la franja fantasma que los iframes dejan debajo. */
.map {
  line-height: 0;
}

.map iframe {
  width: 100%;
  height: 280px;
  border: 0;
  display: block;
  /* Desatura el mapa de Google para que no choque con la paleta oscura. */
  filter: grayscale(0.4) contrast(1.05);
}

/* -------------------------------------------------------------------------
   7. FOOTER
   ------------------------------------------------------------------------- */
.site-footer {
  text-align: center;
  padding: var(--sp-5) var(--sp-5) 30px;
  font-size: 11px;
  color: var(--text-dim);
  letter-spacing: 0.08em;
  line-height: 1.8;
}

.site-footer a {
  color: var(--text-mute);
  text-decoration: none;
  transition: color var(--t) ease;
}

.site-footer a:hover {
  color: var(--accent);
}

/* Cada dato es un item que nunca se parte a media palabra.
   El footer es flex con gap en vez de puntos medios entre items: con un
   separador de texto, al envolver la línea el "·" queda huérfano al inicio
   de la siguiente, y CSS no tiene forma de saber dónde cae el corte. */
.site-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  column-gap: var(--sp-6);
  row-gap: 2px;
}

.f-item {
  white-space: nowrap;
}

/* Los links del footer también son targets táctiles. */
a.f-item {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* -------------------------------------------------------------------------
   8. COMPONENTES COMPARTIDOS (club y admin)
   ------------------------------------------------------------------------- */
.field {
  margin-bottom: var(--sp-4);
}

.label {
  display: block;
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-mute);
  margin-bottom: 6px;
}

.input {
  width: 100%;
  height: 48px;
  background: var(--bg-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 14px;
  padding: 0 var(--sp-3);
  transition: border-color var(--t) ease;
}

.input:focus {
  outline: none;
  border-color: var(--accent);
}

.input::placeholder {
  color: var(--text-dim);
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 4px var(--sp-2);
  border-radius: var(--radius);
  border: 1px solid var(--border-strong);
  color: var(--text-mute);
}

.badge.is-pendiente {
  border-color: rgba(var(--accent-rgb), 0.5);
  color: var(--accent);
}

.badge.is-aprobado {
  border-color: var(--success);
  color: var(--success);
}

.badge.is-rechazado,
.badge.is-expirado {
  border-color: var(--danger);
  color: var(--danger);
}

/* -------------------------------------------------------------------------
   9. ANIMACIONES
   ------------------------------------------------------------------------- */
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes stepIn {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes mdIn {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes bdIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes toastIn {
  from { opacity: 0; transform: translate(-50%, 12px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

/* -------------------------------------------------------------------------
   10. RESPONSIVE
   ------------------------------------------------------------------------- */
@media (max-width: 480px) {
  .hero {
    padding: var(--sp-12) var(--sp-3) var(--sp-8);
  }

  .hero-name {
    font-size: 48px;
  }

  /* 120px: por debajo de eso el "BARBER SHOP" del logo deja de leerse. */
  .hero-logo {
    width: 120px;
    height: 120px;
  }

  .actions {
    align-self: stretch;
  }

  .actions .btn,
  .actions .btn-ghost {
    width: 100%;
    min-width: 0;
    padding-left: var(--sp-5);
    padding-right: var(--sp-5);
  }

  /* Footer: un dato por línea. */
  .site-footer {
    flex-direction: column;
    column-gap: 0;
    row-gap: 0;
    line-height: 1.6;
  }

  .f-item {
    width: 100%;
  }

  a.f-item {
    justify-content: center;
  }
}

/* Cabeceras de sección del club y el panel: 18px en móvil, 20px desde acá.
   Un solo punto de quiebre para las tres (club-titulo, sec-head h2,
   admin-seccion) en vez de repetirlo en cada bloque. */
@media (min-width: 720px) {
  .sec-head h2,
  .admin-seccion {
    font-size: 20px;
  }
}

/* -------------------------------------------------------------------------
   11. ACCESIBILIDAD
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* -------------------------------------------------------------------------
   12. BÚNKER CLUB — pantallas de acceso
   ------------------------------------------------------------------------- */
.wrap-club {
  max-width: 460px;
  justify-content: center;
  padding-top: var(--sp-8);
  padding-bottom: var(--sp-8);
}

.club-head {
  text-align: center;
  margin-bottom: var(--sp-6);
}

.club-logo {
  display: block;
  width: 88px;
  height: 88px;
  margin: 0 auto var(--sp-5);
  color: var(--text);
}

.club-logo svg {
  width: 100%;
  height: 100%;
}

.club-titulo {
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 400;
  letter-spacing: 0.16em;
  color: var(--text);
  line-height: 1.05;
  margin-bottom: var(--sp-3);
}

@media (min-width: 720px) {
  .club-titulo { font-size: 30px; }
}

.club-bajada {
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-mute);
  max-width: 34ch;
  margin: 0 auto;
}

.club-bajada strong {
  color: var(--text-soft);
  font-weight: 600;
  /* Un correo largo no puede desbordar en 360px. */
  overflow-wrap: anywhere;
}

.panel-form {
  padding: var(--sp-6) var(--sp-5);
}

.form-nota {
  font-size: 11px;
  line-height: 1.6;
  color: var(--text-mute);
  text-align: center;
  margin-top: var(--sp-4);
}

.opcional {
  color: var(--text-dim);
  letter-spacing: 0.1em;
}

/* Separador "o" entre el formulario y la acción alternativa. */
.form-sep {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin: var(--sp-5) 0;
  color: var(--text-dim);
  font-size: 10px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

.form-sep::before,
.form-sep::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}

/* Los 6 dígitos, en mono y bien separados: se leen del correo y se tipean. */
.input-codigo {
  font-family: var(--font-mono);
  font-size: 26px;
  font-weight: 700;
  letter-spacing: 0.4em;
  text-align: center;
  /* Compensa el letter-spacing del último carácter para que se vea centrado. */
  text-indent: 0.4em;
  height: 64px;
}

.input-referido {
  font-family: var(--font-mono);
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

/* Código de referido que llegó por un link ?ref=: bloqueado hasta que se
   pide explícitamente cambiarlo. */
.input-bloqueado {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.input-bloqueado .input {
  flex: 1;
  color: var(--text-mute);
  background: var(--bg-1);
}

.link-cambiar {
  flex: none;
  font-size: 12px;
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  padding: 0 var(--sp-1);
}

.link-cambiar:hover { text-decoration: underline; }

/* Teléfono: <select> nativo de país + número. Antes el select se
   llevaba un tercio del ancho para que entrara el nombre del país; ahora
   cada <option> es solo bandera + prefijo ("🇨🇱 +56"), así que un ancho
   fijo angosto alcanza y el número se lleva el resto. */
.input-telefono {
  display: flex;
  gap: var(--sp-2);
}

.input-pais {
  flex: 0 0 110px;
  min-width: 0;
  padding: 0 var(--sp-2);
}

.input-telefono .input:not(.input-pais) {
  flex: 1;
  min-width: 0;
}

/* Avisos */
.alerta {
  border: 1px solid var(--border-strong);
  border-left-width: 3px;
  border-radius: var(--radius);
  padding: var(--sp-3) var(--sp-4);
  font-size: 14px;
  line-height: 1.5;
  margin-bottom: var(--sp-5);
}

.alerta-error {
  border-color: var(--danger);
  color: var(--danger);
  background: rgba(200, 91, 91, 0.07);
}

.alerta-info {
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(var(--accent-rgb), 0.07);
}

.alerta-ok {
  border-color: var(--success);
  color: var(--success);
  background: rgba(132, 187, 110, 0.07);
}

/* Botones apilados dentro de un panel */
.panel-form .btn + .btn-ghost,
.panel-form .btn-ghost + .btn {
  margin-top: var(--sp-3);
}

/* Los botones a ancho completo dentro de un panel no necesitan el padding
   lateral generoso del CTA del landing: ahí el texto largo se parte en dos
   líneas sin razón. */
.panel-form .btn-block,
.panel-form .btn-ghost.btn-block {
  padding-left: var(--sp-4);
  padding-right: var(--sp-4);
}

/* Link secundario bajo un formulario. El brief lo pide "pequeño": un botón
   fantasma a ancho completo competía con el CTA y ademas partia el texto
   en dos lineas en 360px. */
.link-sutil {
  margin-top: var(--sp-5);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
  text-align: center;
  font-size: 13px;
  color: var(--text-mute);
}

.link-sutil a {
  color: var(--accent);
  text-decoration: none;
  font-weight: 600;
  /* Target táctil, sin romper la línea de texto. */
  display: inline-block;
  padding: 12px 4px;
}

.link-sutil a:hover {
  text-decoration: underline;
}

/* -------------------------------------------------------------------------
   13. LA TARJETA
   Adaptada de docs/tarjeta-prototipo.html. La estructura, los materiales
   por nivel y las animaciones son las del prototipo; lo unico que cambia
   son los tokens, que salen de la seccion 1 en vez de repetirse.
   ------------------------------------------------------------------------- */
.wrap-tarjeta {
  max-width: 440px;
  padding-bottom: 120px;
}

/* --- Cabecera ---------------------------------------------------------- */
.top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 56px;
}

.brand {
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1;
  font-weight: 400;
  letter-spacing: 0.18em;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  /* Es un link a la portada: cuenta como target táctil. */
  min-height: 44px;
  color: var(--text);
  text-decoration: none;
}

.brand i {
  width: 0;
  height: 0;
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-bottom: 10px solid var(--accent);
}

.top a:not(.brand) {
  font-size: 12px;
  color: var(--text-mute);
  text-decoration: none;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  padding: 0 var(--sp-2);
  transition: color var(--t) ease;
}

.top a:not(.brand):hover { color: var(--text); }

/* --- Entrada escalonada ------------------------------------------------ */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  animation: reveal 600ms var(--ease-carta) forwards;
}

.reveal:nth-child(2) { animation-delay: 60ms; }
.reveal:nth-child(3) { animation-delay: 140ms; }
.reveal:nth-child(4) { animation-delay: 220ms; }
.reveal:nth-child(5) { animation-delay: 300ms; }
.reveal:nth-child(6) { animation-delay: 380ms; }
.reveal:nth-child(7) { animation-delay: 460ms; }
.reveal:nth-child(8) { animation-delay: 540ms; }

@keyframes reveal { to { opacity: 1; transform: none; } }

/* --- La tarjeta v3 -------------------------------------------------------
   Copiada literal de docs/tarjeta-v3.html: mismas capas, mismos tamaños,
   mismas animaciones. Solo se sustituyen tres cosas: el <img> del logo por
   el asset real del repo, los textos por variables del servidor, y el QR
   de la librería QRCode.js del cliente por el SVG que ya genera el server
   (mismo paquete `qrcode` que usa /admin/qr).

   Dos adaptaciones que sí cambian algo, explicadas donde ocurren: el ancho
   de la escena no cuelga de un <main> propio (esta tarjeta vive dentro de
   /club, con su propio header y secciones abajo), y los nombres .scene,
   .card-btn/.card-btn--solid, .face.back reemplazan a los del prototipo
   (.scene coincide, pero .btn/.actions/.toast NO se reusan: esos nombres
   ya son el botón dorado, las acciones del landing y el toast de todo el
   sitio — reutilizarlos tal cual rompería esas pantallas).

   El giro (tilt) NO usa custom properties heredadas para --rx/--ry: eso
   invalidaria el estilo de toda la tarjeta en cada frame (ver tarjeta.js).
   El JS escribe el transform directo en el estilo de #tilt. El brillo
   (glare) si usa custom properties, pero puestas en el propio elemento sin
   hijos: no hay subarbol que invalidar. La regla de acá abajo con
   var(--rx,0deg) es la del prototipo tal cual — con el JS actual queda
   inerte en cuanto se mueve el dedo (gana el estilo inline), pero es el
   valor de reposo correcto cuando se suelta.
   ------------------------------------------------------------------------- */
.scene {
  --thick: 7px;
  --r: 20px;
  --lv-a: #5a5a57;
  --lv-b: #242422;
  --lv-hi: #9a9a95;
  width: min(92vw, 400px);
  max-width: 100%;
  margin: var(--sp-4) auto 0;
  padding: 18px 0;
  perspective: 1100px;
  container-type: inline-size;
}

.scene[data-nivel="SOCIO"] { --lv-a: #b9b9b3; --lv-b: #4a4a47; --lv-hi: #f0f0ea; }
.scene[data-nivel="VETERANO"] { --lv-a: var(--accent); --lv-b: #5a3f18; --lv-hi: #f2d39c; }
.scene[data-nivel="LEYENDA"] { --lv-a: #f0cf95; --lv-b: #8a6a30; --lv-hi: #fff6df; }

.tilt {
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform 90ms linear;
  will-change: transform;
}

.tilt.idle { animation: idle 7s ease-in-out infinite; }

@keyframes idle {
  0%, 100% { transform: rotateX(4deg) rotateY(-9deg); }
  50% { transform: rotateX(-3deg) rotateY(9deg); }
}

.flip {
  position: relative;
  aspect-ratio: 1.586;
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
  transition: transform 700ms cubic-bezier(0.2, 0.8, 0.2, 1);
  cursor: pointer;
}

.flip.is-back { transform: rotateY(180deg); }

/* Safari (a diferencia de Chrome) no perdona un reverso mal cubierto: el
   frente se ve espejado durante y después del giro si algún descendiente
   con transform propio (las capas .lay con translateZ, .edge, .skin,
   .backwrap) se queda sin su propio backface-visibility — no alcanza con
   declararlo en .face y confiar en que "baje": no es una propiedad que
   herede, así que .face * lo pone en cada descendiente, y encima se repite
   explícito en las clases con translateZ propio por si el universal
   selector pierde contra algo más especifico. Ver tarjeta.js para el
   respaldo por JS (visibility a mitad del giro) para lo que ni así cubra. */
.face {
  position: absolute;
  inset: 0;
  border-radius: var(--r);
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.face *,
.face .lay,
.face .edge,
.face .skin,
.face .backwrap {
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.face.back { transform: rotateY(180deg); }

/* Grosor real: tres capas apiladas hacia atras. */
.edge {
  position: absolute;
  inset: 0;
  border-radius: var(--r);
  background: #141412;
  box-shadow: 0 0 0 1px #0a0a09;
}

.edge:nth-child(1) { transform: translateZ(calc(var(--thick) * -0.33)); }
.edge:nth-child(2) { transform: translateZ(calc(var(--thick) * -0.66)); background: #0f0f0e; }
.edge:nth-child(3) {
  transform: translateZ(calc(var(--thick) * -1));
  background: #0a0a09;
  box-shadow: 0 40px 70px -20px rgba(0, 0, 0, 0.95);
}

/* Piel: texturas planas, sin 3D. */
.skin {
  position: absolute;
  inset: 0;
  border-radius: var(--r);
  overflow: hidden;
  background:
    linear-gradient(120deg, rgba(255, 255, 255, 0.045), transparent 35%, transparent 70%, rgba(0, 0, 0, 0.5)),
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.012) 0 1px, transparent 1px 4px),
    #0c0c0b;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06) inset;
}

.skin::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1.5px;
  background: linear-gradient(140deg, var(--lv-a), transparent 30%, transparent 70%, var(--lv-b));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
}

.tri {
  position: absolute;
  left: -8%;
  top: -22%;
  width: 116%;
  height: 150%;
  fill: none;
  stroke: #fff;
  stroke-width: 0.9;
  opacity: 0.07;
  pointer-events: none;
}

.glare {
  position: absolute;
  inset: 0;
  background: radial-gradient(240px 240px at var(--gx, 70%) var(--gy, 20%), rgba(255, 255, 255, 0.14), transparent 60%);
  pointer-events: none;
  mix-blend-mode: screen;
}

.shine {
  position: absolute;
  inset: -40%;
  background: linear-gradient(115deg, transparent 44%, rgba(255, 255, 255, 0.07) 50%, transparent 56%);
  transform: translateX(-60%);
  animation: shine 6s ease-in-out infinite;
  will-change: transform;
  pointer-events: none;
}

@keyframes shine {
  0%, 72% { transform: translateX(-60%); }
  100% { transform: translateX(60%); }
}

/* Destello del ascenso: una capa que sube y baja de opacidad, no un filter
   sobre toda la tarjeta (eso obliga a repintarla entera en cada frame). */
.card-flash {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(60% 60% at 50% 50%, rgba(255, 240, 210, 0.85), rgba(217, 165, 94, 0.3) 60%, transparent 78%);
}

.flip.level-up .front .card-flash { animation: flash 1400ms var(--ease-carta); }

@keyframes flash {
  0% { opacity: 0; }
  28% { opacity: 0.9; }
  55% { opacity: 0.45; }
  100% { opacity: 0; }
}

/* --- Frente: capas con profundidad -------------------------------------- */
.front .lay { position: absolute; }

.logo { left: 5cqw; top: 4.5cqw; width: 26cqw; transform: translateZ(34px); }
.logo img { width: 100%; height: auto; display: block; filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.7)); }

/* .card-badge (no .badge): esa clase ya es la insignia de estado del panel
   (sección 8) — antes de este cambio ambas compartían el nombre y, al no
   haber container-type fuera de .scene, el font-size en cqw caía al
   viewport: los badges "Visible"/"Automática" del panel se veían a ~42px. */
.card-badge {
  right: 5cqw;
  top: 5cqw;
  transform: translateZ(26px);
  font-family: var(--font-display);
  font-size: 3.3cqw;
  line-height: 1;
  font-weight: 400;
  letter-spacing: 0.22em;
  padding: 2cqw 3cqw 1.75cqw;
  border-radius: 999px;
  color: #070707;
  background: linear-gradient(135deg, var(--lv-hi), var(--lv-a) 50%, var(--lv-b));
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.45) inset, 0 8px 16px -6px rgba(0, 0, 0, 0.9);
}

/* El prototipo declara .pts dos veces (deja left/bottom/transform/fuente y
   agrega right/display/gap encima); acá va fusionado en una sola regla con
   el mismo resultado final. En v4 los valores son cqw: escalan con el
   ancho real de la tarjeta (gracias a container-type en .scene) en vez de
   con el viewport, así el número nunca vuelve a chocar con el logo. */
.pts {
  left: 5cqw;
  right: 5cqw;
  bottom: 17.5cqw;
  transform: translateZ(46px);
  font-family: var(--font-display);
  font-size: 19cqw;
  line-height: 0.82;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--text);
  text-shadow: 0 10px 18px rgba(0, 0, 0, 0.8);
  display: flex;
  align-items: flex-end;
  gap: 2.5cqw;
}

.pts small {
  font-family: var(--font-body);
  font-size: 2.4cqw;
  line-height: 1.5;
  font-weight: 500;
  letter-spacing: 0.3em;
  color: var(--text);
  text-shadow: none;
  padding-bottom: 1cqw;
  max-width: 26cqw;
}

/* "N reservados": no está en el prototipo v3, pero el v4 sí lo resuelve —
   un <b> en bloque dentro de .pts small, que cae a su propia línea sin
   necesitar flex-wrap en el contenedor .pts. */
.pts small b {
  display: block;
  font-weight: 500;
  color: var(--accent);
  letter-spacing: 0.12em;
}

/* El "+100" que sube al lado del numero: tampoco está en el prototipo,
   es el delta que ya existía y el brief pidió reconectar. */
.pts-delta {
  position: absolute;
  left: 0;
  top: -26px;
  font-family: var(--font-mono);
  font-size: 20px;
  font-weight: 700;
  color: var(--accent);
  pointer-events: none;
  opacity: 0;
}

.pts-delta.go { animation: delta 1100ms var(--ease-carta) forwards; }
.pts-delta.neg { color: var(--danger); }

@keyframes delta {
  0% { opacity: 0; transform: translateY(0); }
  15% { opacity: 1; }
  100% { opacity: 0; transform: translateY(-40px); }
}

.foot {
  left: 5cqw;
  right: 5cqw;
  bottom: 5cqw;
  transform: translateZ(16px);
  display: grid;
  gap: 2.25cqw;
}

/* Barra estilo "navaja" del logo: linea fina con un punto al final. */
.bar {
  position: relative;
  height: 1.5px;
  background: rgba(255, 255, 255, 0.14);
}

.bar i {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: 0;
  background: var(--lv-a);
  transition: width 900ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.bar i::after {
  content: "";
  position: absolute;
  right: -3px;
  top: -2.75px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--lv-hi);
  box-shadow: 0 0 8px var(--lv-a);
}

.meta {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 3cqw;
}

/* v4 corta el nombre largo con puntos suspensivos en vez de dejarlo
   quebrar de línea (overflow-wrap:anywhere en v3): con max-width en cqw
   ya no hace falta que .meta envuelva, así que flex-wrap también se va. */
.name {
  font-family: var(--font-display);
  font-size: 4.2cqw;
  line-height: 1;
  font-weight: 400;
  letter-spacing: 0.1em;
  color: var(--text);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 68cqw;
}

.name small {
  display: block;
  font-family: var(--font-body);
  font-size: 2.2cqw;
  line-height: 1;
  font-weight: 500;
  letter-spacing: 0.22em;
  color: var(--text-mute);
  margin-top: 1.25cqw;
}

.mono {
  font-family: var(--font-mono);
  font-size: 2.7cqw;
  font-weight: 700;
  letter-spacing: 0.16em;
  color: var(--text-mute);
  flex: none;
}

.mono b { color: var(--text); }

/* --- Reverso -------------------------------------------------------------
   .back.skin en vez del .back bare del prototipo: es la misma regla sobre
   el mismo elemento (la clase "back" siempre va junto a "face" en el
   markup), pero sin dejar un nombre tan genérico suelto en la hoja. */
.face.back .skin { background: linear-gradient(120deg, rgba(255, 255, 255, 0.03), transparent 40%), #0b0b0a; }

.wmark {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 78%;
  height: auto;
  transform: translate(-50%, -50%);
  opacity: 0.10;
  pointer-events: none;
}

.stripe {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 12px;
  background: linear-gradient(90deg, var(--lv-b), var(--lv-a), var(--lv-b));
  opacity: 0.6;
}

.backwrap {
  position: absolute;
  inset: 0;
  padding: 5cqw;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4cqw;
  align-items: center;
  transform: translateZ(30px);
}

.qr {
  background: #f6f4ee;
  padding: 2.25cqw;
  border-radius: 3cqw;
  width: 33cqw;
  height: 33cqw;
  display: grid;
  place-items: center;
  box-shadow: 0 14px 26px -12px rgba(0, 0, 0, 0.95);
}

/* El prototipo genera el QR en el navegador con QRCode.js y lo mete en
   un <img>/<canvas> a 100% (ancho/alto del contenedor); acá lo genera el
   server (mismo paquete `qrcode` de /admin/qr) como SVG inline, así que
   la regla apunta a svg, con el mismo 100% para escalar con .qr. */
.qr svg { width: 100%; height: 100%; display: block; }

.invite { display: grid; gap: 2cqw; min-width: 0; }

.invite .t {
  font-family: var(--font-display);
  font-size: 6.5cqw;
  line-height: 0.95;
  font-weight: 400;
  letter-spacing: 0.05em;
  color: var(--text);
}

.invite p { font-size: 2.9cqw; line-height: 1.45; color: var(--text-mute); }
.invite p b { color: var(--text); font-weight: 600; }

/* El prototipo usa un <div> de solo lectura para el código; acá es un
   <button data-copiar> para reconectar "copiar código", que ya existía.
   Por eso lleva cursor, color, transition y estados de hover/copiado que
   el prototipo no necesitaba. min-height sigue en px, no en cqw: es el
   piso de 44px de zona táctil (WCAG), no una medida visual de la tarjeta
   — a 19cqw en el ancho mínimo de tarjeta (~330px) el bloque de texto por
   sí solo mide bastante menos que eso. */
.code {
  font-family: var(--font-mono);
  font-size: 3.6cqw;
  font-weight: 700;
  letter-spacing: 0.18em;
  padding: 2.25cqw 2.5cqw;
  border: 1px dashed rgba(255, 255, 255, 0.28);
  border-radius: 8px;
  text-align: center;
  background: rgba(0, 0, 0, 0.4);
  color: var(--text);
  cursor: pointer;
  width: 100%;
  min-height: 44px;
  transition: border-color var(--t) ease, color var(--t) ease;
}

.code:hover { border-color: rgba(255, 255, 255, 0.5); }
.code.copiado { color: var(--success); border-color: var(--success); }

/* --- Ascenso de nivel ---------------------------------------------------
   El giro completo (moneda) va en .flip, que no comparte el transform con
   el tilt (eso vive en #tilt, un elemento distinto). Sin filter:
   brightness — el brillo lo pone .card-flash con opacity. */
.flip.level-up { animation: levelUp 1400ms var(--ease-carta); }

@keyframes levelUp {
  0% { transform: rotateY(0) scale(1); }
  35% { transform: rotateY(180deg) scale(0.96); }
  36% { transform: rotateY(-180deg) scale(0.96); }
  70% { transform: rotateY(0) scale(1.02); }
  100% { transform: rotateY(0) scale(1); }
}

/* --- Acciones bajo la tarjeta: ver código / compartir --------------------
   .actions/.btn/.btn--solid son los nombres del prototipo, pero .actions
   y .btn ya son de todo el sitio (el CTA del landing, los botones del
   panel): reusarlos tal cual les pisaría el diseño. .card-actions y
   .card-btn/.card-btn--solid son la MISMA hoja de estilos del prototipo,
   solo renombrada para no chocar. */
.card-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.card-btn {
  min-height: 44px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: transparent;
  color: var(--text);
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.14em;
  cursor: pointer;
  transition: background 180ms, transform 120ms;
}

.card-btn:hover { background: rgba(255, 255, 255, 0.07); }
.card-btn:active { transform: scale(0.98); }

.card-btn--solid { background: var(--text); color: #070707; border-color: var(--text); }
.card-btn--solid:hover { background: #fff; }

.card-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.levelup-toast {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
  z-index: 25;
  opacity: 0;
  /* Sin backdrop-filter: desenfocar todo lo que hay detras es de lo mas
     caro que se le puede pedir a un telefono. El fondo oscurecido basta. */
  background: radial-gradient(60% 40% at 50% 50%, rgba(10, 10, 10, 0.96), rgba(10, 10, 10, 0.82));
}

.levelup-toast.show { animation: luToast 2200ms var(--ease-carta); }
.levelup-toast div { text-align: center; }

.levelup-toast small {
  display: block;
  font-size: 11px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--sp-2);
}

.levelup-toast b {
  font-family: var(--font-display);
  font-size: clamp(44px, 14vw, 72px);
  line-height: 1;
  font-weight: 400;
  letter-spacing: 0.14em;
  color: var(--text);
  text-shadow: 0 0 40px rgba(var(--accent-rgb), 0.6);
}

@keyframes luToast {
  0% { opacity: 0; transform: scale(0.9); }
  15% { opacity: 1; transform: scale(1); }
  80% { opacity: 1; }
  100% { opacity: 0; transform: scale(1.04); }
}

/* --- Pulsos --------------------------------------------------------------
   Se activan con una clase en .flip (ancestro), pero el pulso visual va en
   .front .skin: es la superficie visible, .flip no pinta nada por si sola. */
.flip.pulse-gold .front .skin { animation: pulseGold 900ms var(--ease-carta); }

@keyframes pulseGold {
  0% { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06) inset, 0 0 0 0 rgba(var(--accent-rgb), 0.55); }
  100% { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06) inset, 0 0 0 26px rgba(var(--accent-rgb), 0); }
}

.flip.pulse-redeem .front .skin { animation: pulseRedeem 700ms var(--ease-carta); }

@keyframes pulseRedeem {
  0% { filter: brightness(1); }
  50% { filter: brightness(1.18); }
  100% { filter: brightness(1); }
}

/* --- Secciones y listas ------------------------------------------------ */
.sec { margin-top: var(--sp-6); }

.sec .btn-ghost.btn-block { margin-top: var(--sp-3); }

/* --- Voucher pendiente: el canje que espera mostrarse en caja ---------- */
.voucher-pendiente {
  margin-top: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid rgba(var(--accent-rgb), 0.5);
  border-radius: var(--radius-lg);
  background: rgba(var(--accent-rgb), 0.08);
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-soft);
}

.voucher-pendiente + .voucher-pendiente { margin-top: var(--sp-2); }
.voucher-pendiente b { color: var(--text); }

/* Clase propia, no ".mono": esa la reutiliza el frente de la tarjeta en
   cqw (relativo al ancho de .scene) y este voucher vive fuera de ella,
   sin container-type de por medio — cqw ahí cae al viewport completo. */
.voucher-codigo {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--accent);
}

/* --- Banner de Cupos Club: teaser compacto arriba de las pestañas ------ */
.cupos-banner {
  margin-top: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg-1);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

.cupos-banner-txt { flex: 1; min-width: 180px; }
.cupos-banner-txt b { display: block; font-size: 14px; color: var(--text); }
.cupos-banner-txt span { display: block; font-size: 12px; color: var(--text-mute); margin-top: 2px; }
.cupos-banner .btn-ghost { flex: none; min-height: 44px; }

/* --- Pestañas: Premios / Sumar / Referidos / Historial / (Cupos) -------
   Fija en su sitio (no sticky). Con JS, tarjeta.js oculta todo menos el
   panel activo; sin JS, .tab-panel nunca lleva `hidden` en el HTML
   servido y todas quedan visibles apiladas, como siempre. */
.tabs {
  display: flex;
  gap: var(--sp-2);
  margin-top: var(--sp-6);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  border-bottom: 1px solid var(--border);
}

/* Bajo 720px la navegación es la barra inferior, no estas pestañas —
   sin JS también: sus <a> siguen en el HTML (funcionan como anclas),
   pero la fila de pestañas de arriba no tiene sentido dos veces. */
@media (max-width: 719.98px) {
  .tabs { display: none; }
}

.tabs::-webkit-scrollbar { display: none; }

.tab {
  flex: none;
  min-height: 44px;
  padding: 0 var(--sp-3);
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  font-family: var(--font-display);
  font-size: 14px;
  letter-spacing: 0.08em;
  color: var(--text-mute);
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--t) ease, border-color var(--t) ease;
}

.tab:hover { color: var(--text); }

.tab[aria-selected="true"] {
  color: var(--text);
  border-bottom-color: var(--accent);
}

/* El panel de después de las pestañas no necesita el margen grande de
   .sec de siempre: las pestañas ya hacen de separador visual. Se llama
   .tab-panel y no .panel: esa clase ya existe (sección 6, superficie
   genérica del landing) y le habría metido fondo/borde/overflow:hidden
   de más a cada pestaña.
   min-height reserva sitio para que la página no salte al cambiar de
   pestaña entre paneles de alturas distintas (ej. Referidos vacío vs.
   Historial con 8 filas). */
.tab-panel {
  margin-top: var(--sp-5);
  min-height: 200px;
}

/* Los paneles NO usan la cascada .reveal (esa queda solo para la tarjeta
   y los botones de abajo, en la carga inicial): al cambiar de pestaña
   `hidden` se saca y se pone de vuelta, y un panel que reaparece con
   .reveal repite la animación de 600ms con transform entera cada vez.
   Acá un fade corto y sin transform, para que el cambio de pestaña se
   sienta inmediato. */
.panel-fade { animation: panelFade 150ms ease; }

@keyframes panelFade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.sec-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: var(--sp-3);
}

.sec-head h2 {
  font-family: var(--font-display);
  font-size: 18px;
  line-height: 1;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text);
}

.sec-head span { font-size: 12px; color: var(--text-mute); }

.list {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

/* [hidden] (regla del navegador) pierde contra .row{display:flex} porque
   las dos tienen la misma especificidad y la del navegador va primero en
   la cascada: sin esto, "Ver más" (tarjeta.js) ocultaba filas con
   el.hidden = true y igual quedaban visibles. */
.row[hidden] { display: none; }

.row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 10px var(--sp-4);
  /* 52px es el piso, no un techo: una fila de una sola línea (Sumar,
     Referidos) queda justo ahí. Premios (título + descripción + puntos)
     e Historial (título + fecha o nota) muestran más de una línea de
     contenido real y crecen por sobre eso — recortar la descripción del
     premio o la fecha del movimiento para forzar 52px exactos perdería
     información, así que no se hace. */
  min-height: 52px;
  border-top: 1px solid var(--border);
}

.row:first-child { border-top: 0; }

.row-icono {
  flex: none;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-md);
  background: var(--bg-2);
  color: var(--accent);
}

.row-icono svg { width: 18px; height: 18px; }

.row-main { flex: 1; min-width: 0; }
.row-title { font-weight: 500; font-size: 14px; color: var(--text); overflow-wrap: anywhere; }
.row-sub { font-size: 12px; color: var(--text-mute); margin-top: 2px; overflow-wrap: anywhere; }
.row-dias { color: var(--accent); font-weight: 500; }

.row-pts {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--text-soft);
  white-space: nowrap;
}

.rewards .row-pts { display: block; margin-top: 3px; color: var(--accent); }
.ways .row-pts { color: var(--accent); font-weight: 700; }

.hist .row-pts { font-weight: 700; }
.hist .row-pts.pos { color: var(--success); }
.hist .row-pts.neg { color: var(--danger); }

.row--vacia {
  justify-content: center;
  color: var(--text-dim);
  font-size: 14px;
  min-height: 72px;
}

/* --- Pago: datos de transferencia (pestaña PAGO) -------------------------
   Misma superficie .list que las otras pestañas; cada fila es etiqueta
   chica + valor en mono + botón "Copiar" de 44px. Sin JS los botones se
   esconden desde no-js-tarjeta.css y el bloque se lee igual. */
.pago-fila {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 10px var(--sp-4);
  min-height: 60px;
  border-top: 1px solid var(--border);
}

.pago-fila:first-child { border-top: 0; }
.pago-main { flex: 1; min-width: 0; }

.pago-etq {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-mute);
}

.pago-valor {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 500;
  color: var(--text);
  margin-top: 2px;
  overflow-wrap: anywhere;
  -webkit-user-select: all;
  user-select: all;
}

.pago-copiar {
  flex: none;
  min-height: 44px;
  padding: 0 var(--sp-4);
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  color: var(--text-soft);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: border-color var(--t) ease, color var(--t) ease;
}

.pago-copiar:hover { border-color: var(--accent); color: var(--text); }
.pago-copiar.copiado { border-color: var(--success); color: var(--success); }
.pago-copiar:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Arriba de la lista, no debajo como el "Ver más" de las otras pestañas. */
.sec .btn-ghost.pago-copiar-todo { margin: 0 0 var(--sp-3); }

.pago-nota {
  margin-top: var(--sp-3);
  font-size: 12px;
  color: var(--text-mute);
  text-align: center;
}

/* --- Botones de la tarjeta --------------------------------------------- */
.btn--gold,
.btn--locked {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 36px: son inline dentro de una fila de la tarjeta, no un target
     táctil de página completa. .btn--locked ni siquiera es interactivo
     (cursor: default) — no necesita el piso de 44px. */
  min-height: 36px;
  padding: 0 var(--sp-4);
  border: 0;
  border-radius: var(--radius-md);
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: filter var(--t) ease, transform var(--t) ease;
}

.btn--gold { background: var(--accent); color: var(--accent-ink); cursor: pointer; }
.btn--gold:hover { filter: brightness(1.06); }
.btn--gold:active { transform: scale(0.97); }

.btn--locked {
  background: var(--bg-2);
  color: var(--text-mute);
  font-family: var(--font-mono);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: none;
  cursor: default;
}

/* --- Insignias del historial ------------------------------------------- */
.badge--pend,
.badge--canje {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 4px var(--sp-2);
  border-radius: 99px;
  border: 1px solid;
  white-space: nowrap;
}

.badge--pend { color: var(--accent); border-color: rgba(var(--accent-rgb), 0.4); }
.badge--canje { color: var(--text-soft); border-color: var(--border-strong); }

/* --- Toast ------------------------------------------------------------- */
.toast {
  position: fixed;
  left: 50%;
  bottom: max(24px, env(safe-area-inset-bottom));
  transform: translate(-50%, 20px);
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  color: var(--text);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-lg);
  font-size: 14px;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t) ease, transform var(--t) ease;
  z-index: 20;
  white-space: nowrap;
  max-width: 90vw;
}

.toast.show { opacity: 1; transform: translate(-50%, 0); }

/* -------------------------------------------------------------------------
   13b. BARRA INFERIOR Y SHEETS (móvil, < 720px) — item 4
   La tarjeta es la protagonista: en pantallas chicas la principal es
   solo cabecera + tarjeta + sus botones + voucher/cupos si hay, todo lo
   demás vive en sheets que sube la barra de abajo. Desde 720px no
   cambia nada: siguen las pestañas de siempre bajo la tarjeta.

   Todo lo que se anime acá es transform/opacity, nunca layout ni filter
   sobre la tarjeta — el overlay oscurece con su propia opacidad, no con
   un filter encima de .scene.

   El CSS de acá ASUME JavaScript (así el sheet nace ya en su sitio, sin
   un cambio de layout post-carga que dispare CLS): .tab-panel entra
   fijo y fuera de pantalla por defecto. layout.html carga
   /css/no-js-tarjeta.css con <noscript> para deshacer esto en el único
   caso real en que hace falta — sin ese navegador no hay forma de abrir
   un sheet, así que los paneles vuelven al flujo de siempre. */

.barra-inferior { display: none; }

@media (max-width: 719.98px) {
  .barra-inferior {
    display: flex;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    height: calc(56px + env(safe-area-inset-bottom));
    padding-bottom: env(safe-area-inset-bottom);
    background: #0b0b0a;
    border-top: 1px solid var(--border);
    z-index: 40;
  }
}

.barra-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: 56px;
  color: var(--text-mute);
  text-decoration: none;
  transition: color var(--t) ease;
}

.barra-item.is-activo { color: var(--accent); }

.barra-icono svg { width: 20px; height: 20px; display: block; }

.barra-etiqueta {
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 0.06em;
  line-height: 1;
}

.sheet-overlay { display: none; }

@media (max-width: 719.98px) {
  .sheet-overlay {
    display: block;
    position: fixed;
    inset: 0;
    background: #000;
    opacity: 0;
    pointer-events: none;
    transition: opacity 220ms var(--ease-settle);
    z-index: 44;
  }

  .sheet-overlay.is-visible {
    opacity: 0.6;
    pointer-events: auto;
  }

  /* Con el sheet abierto, la página de atrás no se puede arrastrar —
     el scroll que importa es el interno del sheet (overflow-y arriba). */
  body.sheet-bloqueo { overflow: hidden; }

  /* [hidden] es del navegador (display:none) y pierde contra cualquier
     regla de author con la misma especificidad — mismo motivo que
     .row[hidden] en la sección de la tarjeta. Acá se aprovecha ADEMÁS:
     la visibilidad del sheet la maneja transform/opacity, no display,
     porque display:none no se puede animar. */
  .tab-panel {
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    max-height: 85vh;
    margin: 0;
    background: var(--bg-1);
    border: 1px solid var(--border);
    border-bottom: 0;
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    padding: var(--sp-2) var(--sp-5) calc(var(--sp-6) + 56px + env(safe-area-inset-bottom));
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    z-index: 45;
    transform: translateY(100%);
    opacity: 0;
    pointer-events: none;
    transition: transform 220ms var(--ease-settle), opacity 220ms var(--ease-settle);
  }

  /* will-change solo durante la animación (la agrega/saca tarjeta.js en
     los dos extremos de la transición) — dejarlo puesto todo el rato
     que el sheet está abierto es promover una capa GPU que no hace
     falta la mayor parte del tiempo. */
  .tab-panel.sheet-animando { will-change: transform, opacity; }

  .tab-panel.sheet-abierto {
    transform: translateY(0);
    opacity: 1;
    pointer-events: auto;
  }
}

.sheet-cabecera { display: none; }

@media (max-width: 719.98px) {
  .sheet-cabecera {
    display: flex;
    align-items: center;
    justify-content: center;
    position: sticky;
    top: 0;
    background: var(--bg-1);
    min-height: 32px;
    padding-top: var(--sp-2);
    margin: 0 calc(var(--sp-5) * -1) var(--sp-2);
    padding-left: var(--sp-5);
    padding-right: var(--sp-5);
  }

  .sheet-asa {
    width: 36px;
    height: 4px;
    border-radius: 999px;
    background: var(--border-strong);
  }

  .sheet-cerrar {
    position: absolute;
    right: var(--sp-5);
    top: var(--sp-2);
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    background: transparent;
    border: 0;
    border-radius: var(--radius);
    color: var(--text-mute);
    cursor: pointer;
  }

  .sheet-cerrar svg { width: 18px; height: 18px; }
  .sheet-cerrar:hover { color: var(--text); }
}

/* =========================================================================
   14. PANEL DEL DUENO
   El dueno lo va a usar desde su telefono, parado al lado de la silla.
   Nada de tablas: cada registro es una tarjeta apilada que se lee de un
   vistazo y cuyos botones se tocan sin apuntar.
   ========================================================================= */
.wrap-admin {
  max-width: 720px;
  padding-top: var(--sp-4);
  padding-bottom: var(--sp-10);
}

.admin-top {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 56px;
  margin-bottom: var(--sp-4);
}

.admin-marca {
  display: block;
  /* 44px: es un link a la portada del panel y cuenta como target táctil. */
  width: 44px;
  height: 44px;
  flex: none;
  color: var(--text);
}

.admin-marca svg { width: 100%; height: 100%; }

.admin-top-txt {
  flex: 1;
  min-width: 0;
}

.admin-seccion {
  display: block;
  font-family: var(--font-display);
  font-size: 18px;
  letter-spacing: 0.14em;
  color: var(--text);
  line-height: 1.1;
  overflow-wrap: anywhere;
}

/* El link de salir del panel. Vivia en la seccion 13 vieja y se perdio al
   reemplazarla por la tarjeta del prototipo. */
.tar-salir {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--sp-2);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-mute);
  text-decoration: none;
  white-space: nowrap;
  flex: none;
  transition: color var(--t) ease;
}

.tar-salir:hover { color: var(--accent); }

.admin-usuario {
  display: block;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-top: 2px;
}

/* --- Navegacion -------------------------------------------------------- */
/* En movil se desliza en horizontal; es el unico scroll lateral permitido
   y esta contenido en su propia caja, no en la pagina. Desde 720px el
   contenedor (.wrap-admin) ya no crece mas alla de esos 720px, asi que
   ese es el punto real donde conviene envolver en dos filas en vez de
   seguir agrandando el scroll. */
.admin-nav-wrap {
  position: relative;
  margin-bottom: var(--sp-4);
}

.admin-nav {
  display: flex;
  gap: var(--sp-2);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--border);
}

.admin-nav::-webkit-scrollbar { height: 6px; }
.admin-nav::-webkit-scrollbar-track { background: transparent; }
.admin-nav::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 999px; }

/* Aviso de que hay mas pestañas a la derecha: admin.js prende esta clase
   segun cuanto falte por scrollear (no es fija), asi desaparece sola al
   llegar al final. Vive en el wrap, no en .admin-nav: puesta ahi adentro
   scrollearia con el contenido en vez de quedarse pegada al borde. */
.admin-nav-wrap.nav-mas::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: var(--sp-2);
  width: 32px;
  background: linear-gradient(to right, transparent, var(--bg) 85%);
  pointer-events: none;
}

@media (min-width: 720px) {
  .admin-nav {
    flex-wrap: wrap;
    overflow-x: visible;
  }
  .admin-nav-wrap::after { display: none; }
}

.nav-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 40px;
  padding: 0 var(--sp-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-mute);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--t) ease, border-color var(--t) ease, background var(--t) ease;
}

.nav-item:hover {
  color: var(--text);
  border-color: var(--border-bright);
}

.nav-item.is-activo {
  color: var(--accent-ink);
  background: var(--accent);
  border-color: var(--accent);
}

.nav-globo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--danger);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0;
}

.nav-item.is-activo .nav-globo {
  background: var(--accent-ink);
  color: var(--accent);
}

/* --- Registros --------------------------------------------------------- */
.registros {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.registro {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  /* Más compacto que --sp-4 (16px): Canjes/Clientes/Cupos muestran varias
     líneas reales por registro (nombre, monto, badge, concepto, fecha,
     a veces código y nota) — no entran en una fila de 56-64px sin perder
     información, pero sí pueden ir más apretados. */
  padding: 10px var(--sp-4);
}

.registro-link {
  display: block;
  text-decoration: none;
  transition: border-color var(--t) ease, background var(--t) ease;
}

.registro-link:hover {
  border-color: var(--border-bright);
  background: var(--bg-2);
}

.reg-linea1 {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
}

.reg-cliente {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  overflow-wrap: anywhere;
}

a.reg-cliente {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

a.reg-cliente:hover { color: var(--accent); }

.reg-saldo {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--accent);
  white-space: nowrap;
}

.reg-linea2 {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: 4px;
}

.reg-concepto {
  font-size: 12px;
  color: var(--text-soft);
  overflow-wrap: anywhere;
}

.reg-email {
  font-size: 12px;
  color: var(--text-mute);
  overflow-wrap: anywhere;
}

.reg-fecha,
.reg-meta {
  font-size: 11px;
  color: var(--text-dim);
  white-space: nowrap;
}

.reg-mono {
  font-family: var(--font-mono);
  letter-spacing: 0.1em;
}

.reg-codigo {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--accent);
}

.reg-nota {
  font-size: 12px;
  color: var(--text-mute);
  margin-top: 6px;
  overflow-wrap: anywhere;
}

.reg-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: 12px;
  color: var(--accent);
  text-decoration: underline;
}

/* Los dos botones ocupan la mitad cada uno: se aciertan con el pulgar. */
.reg-acciones {
  display: flex;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
  padding-top: var(--sp-2);
  border-top: 1px solid var(--border);
}

.reg-acciones .btn,
.reg-acciones .btn-ghost {
  flex: 1;
  padding-left: var(--sp-2);
  padding-right: var(--sp-2);
}

.btn-peligro {
  color: var(--danger);
  border-color: rgba(200, 91, 91, 0.45);
}

.btn-peligro:hover {
  color: var(--danger);
  border-color: var(--danger);
  background: rgba(200, 91, 91, 0.08);
}

/* --- Buscador ---------------------------------------------------------- */
.buscador {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-4);
}

.buscador .input { flex: 1; min-width: 0; }
.buscador .btn { flex: none; }

.buscador-grande + .btn-ghost.btn-block { margin-bottom: var(--sp-4); }

/* --- Ficha del cliente ------------------------------------------------- */
.ficha-saldos {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  margin-bottom: var(--sp-6);
}

.ficha-saldo {
  padding: var(--sp-4) var(--sp-3);
  text-align: center;
  border-right: 1px solid var(--border);
}

.ficha-saldo:last-child { border-right: none; }

.ficha-label {
  display: block;
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 6px;
}

.ficha-valor {
  display: block;
  font-family: var(--font-mono);
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
}

/* --- Días de canje (premios de Cupos Club) ------------------------------ */
.dias-canje {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: 4px;
}

.dia-check {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 0 var(--sp-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  font-size: 12px;
  color: var(--text-soft);
  text-transform: uppercase;
  cursor: pointer;
}

/* --- Editables (premios y acciones) ------------------------------------ */
.editables {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  margin-bottom: var(--sp-6);
}

.editable {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--sp-4);
}

.editable-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  row-gap: var(--sp-2);
  margin-bottom: var(--sp-4);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border);
}

.editable-tipo {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  color: var(--text-dim);
  /* Algunos tipos (CORTE_ESTUDIANTE, LIMPIEZA_FACIAL) son largos: sin esto
     empujaban los botones de orden fuera de los 360px y metían scroll
     horizontal a toda la página. */
  overflow-wrap: anywhere;
  min-width: 0;
}

.editable-orden {
  display: flex;
  gap: 6px;
  margin-left: auto;
}

.editable-nota {
  font-size: 12px;
  line-height: 1.55;
  color: var(--text-mute);
  margin-bottom: var(--sp-4);
}

/* --- Cuerpo editable, plegado por defecto -------------------------------
   El formulario completo (nombre, puntos, vigencia, días, ícono) y la
   vista previa solo se arman al tocar la fila con el nombre y los
   puntos. Subir/bajar/ocultar quedan en .editable-top, siempre visibles:
   son de un solo toque y Miller los usa para reordenar sin entrar a
   editar nada. */
.editable-resumen {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  min-height: 44px;
  padding: var(--sp-2) 0;
  cursor: pointer;
  list-style: none;
  font-size: 14px;
  color: var(--text);
}

.editable-resumen::-webkit-details-marker { display: none; }
.editable-resumen::marker { content: ''; }

.editable-resumen-nombre { overflow-wrap: anywhere; }

.editable-resumen-pts {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--accent);
  white-space: nowrap;
  flex: none;
}

/* Cheurón en vez del triángulo nativo, para no mezclar estilos de navegador
   con el resto del sistema. */
.editable-resumen::after {
  content: '';
  flex: none;
  width: 7px;
  height: 7px;
  margin-left: 2px;
  border-right: 2px solid var(--text-mute);
  border-bottom: 2px solid var(--text-mute);
  transform: rotate(-45deg);
  transition: transform var(--t) ease;
}

.editable-cuerpo[open] .editable-resumen::after { transform: rotate(45deg); }

.editable-cuerpo form { margin-top: var(--sp-3); }

.btn-icono {
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  color: var(--text-soft);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  transition: border-color var(--t) ease, color var(--t) ease;
}

.btn-icono:hover:not(:disabled) {
  border-color: var(--accent);
  color: var(--accent);
}

.btn-icono:disabled {
  opacity: 0.28;
  cursor: not-allowed;
}

/* Vista previa de como lo ve el cliente */
.previa {
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px dashed var(--border-strong);
}

.previa-titulo {
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: var(--sp-3);
}

/* La previa es una muestra, no algo con lo que se interactua. */
.previa .btn,
.previa .btn-ghost {
  pointer-events: none;
}

.campo-ayuda {
  font-size: 11px;
  line-height: 1.55;
  color: var(--text-dim);
  margin-top: var(--sp-2);
}

/* Cuando va sola, fuera de un .field (ej. la ayuda de arriba de /admin/cupos). */
.campo-ayuda-suelta {
  margin: 0 0 var(--sp-4);
}

.input-color {
  padding: 4px;
  cursor: pointer;
}

.input-num {
  font-family: var(--font-mono);
  font-weight: 700;
}

.input-area {
  height: auto;
  padding: var(--sp-3);
  line-height: 1.5;
  resize: vertical;
  font-family: var(--font-body);
}

.bloque-nota-top {
  text-align: left;
  margin: 0 0 var(--sp-4);
  font-size: 12px;
  color: var(--text-mute);
}

/* --- QR ---------------------------------------------------------------- */
.hoja-qr {
  background: #ffffff;
  color: #0a0a0a;
  border-radius: var(--radius-lg);
  padding: var(--sp-8) var(--sp-6);
  text-align: center;
  margin-bottom: var(--sp-5);
}

.hoja-logo {
  width: 96px;
  height: 96px;
  margin: 0 auto var(--sp-4);
  color: #0a0a0a;
}

.hoja-logo svg { width: 100%; height: 100%; }

.hoja-titulo {
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 400;
  letter-spacing: 0.16em;
  color: #0a0a0a;
  margin-bottom: 6px;
}

.hoja-bajada {
  font-size: 13px;
  color: #4a4540;
  margin-bottom: var(--sp-6);
}

.qr-marco {
  position: relative;
  width: 260px;
  max-width: 100%;
  margin: 0 auto var(--sp-5);
}

.qr-marco svg {
  width: 100%;
  height: auto;
  display: block;
}

/* El logo tapa el centro; por eso el QR se genera con correccion H. */
.qr-logo {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 22%;
  height: 22%;
  background: #ffffff;
  border-radius: 6px;
  padding: 4px;
  color: #0a0a0a;
  display: flex;
  align-items: center;
  justify-content: center;
}

.qr-logo svg { width: 100%; height: 100%; }

.hoja-url {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: #0a0a0a;
  letter-spacing: 0.04em;
  overflow-wrap: anywhere;
}

.hoja-pie {
  font-size: 11px;
  color: #807a6e;
  margin-top: var(--sp-3);
}

.acciones-qr {
  text-align: center;
}

.acciones-qr .btn { width: 100%; }

@media (min-width: 560px) {
  .acciones-qr .btn { width: auto; min-width: 240px; }
}

/* --- Impresion: solo la hoja, en A5 ------------------------------------ */
@media print {
  /* Sin margen de pagina: si no, Chrome mete su propio encabezado y pie. */
  @page {
    size: A5;
    margin: 0;
  }

  html, body {
    background: #ffffff !important;
    background-image: none !important;
    color: #0a0a0a !important;
  }

  .no-imprimir { display: none !important; }

  .wrap-admin {
    max-width: none;
    padding: 0;
  }

  .hoja-qr {
    border-radius: 0;
    margin: 0;
    padding: 14mm 10mm;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    box-shadow: none;
  }

  .qr-marco { width: 78mm; }
}

/* -------------------------------------------------------------------------
   15. SUMAR PUNTOS
   La pantalla que Miller usa en la silla. Un objetivo: de abrir /admin a
   sumar un corte en menos de 5 segundos, con una mano.
   ------------------------------------------------------------------------- */
.buscador-grande .input {
  height: 48px;
  font-size: 16px; /* 16px o iOS hace zoom al enfocar */
  /* Mismo radio que los botones de esta fila (--radius-md), no el --radius
     de 4px de los input normales: acá los tres (input, Buscar, Nuevo
     cliente) tienen que verse como un solo grupo. */
  border-radius: var(--radius-md);
}

/* height, no min-height: con .buscador { align-items: center } ya no
   hace falta, pero un min-height deja que el flex-stretch de un
   ancestro sin align-items explícito lo estire más allá de 48px — ya
   pasó una vez (Buscar terminaba en 60px). height fijo no da ese margen. */
.buscador-grande .btn {
  height: 48px;
}

/* --- Fila del buscador + "Nuevo cliente" --------------------------------
   Apilados en móvil (el buscador arriba, el botón abajo a ancho completo,
   como ya estaba); desde 720px van en la misma fila, el buscador
   ocupando el resto y el botón como secundario a la derecha. */
.buscador-fila {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-2);
  margin-bottom: var(--sp-4);
}

.buscador-fila .buscador { flex: 1; min-width: 0; margin-bottom: 0; }

/* 48px como el buscador de al lado, no los 44px de .btn-ghost.btn-sm de
   base: "+ Nuevo cliente" es el tercero del mismo grupo visual. */
.nuevo-cliente { flex: none; height: 48px; }

@media (min-width: 720px) {
  .buscador-fila { flex-direction: row; align-items: center; }
  .nuevo-cliente { width: auto; white-space: nowrap; }
}

/* --- Resultados --------------------------------------------------------- */
.resultados {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-bottom: var(--sp-5);
}

.resultado {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 2px var(--sp-3);
  min-height: 56px;
  padding: var(--sp-3) var(--sp-4);
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  text-decoration: none;
  transition: border-color var(--t) ease, background var(--t) ease;
}

.resultado:hover,
.resultado:focus-visible {
  border-color: var(--accent);
  background: var(--bg-2);
}

/* El cliente elegido: mismo resalte que el hover, pero fijo — así la
   lista de últimos atendidos no pierde a quién se le está sumando. */
.resultado.is-seleccionado {
  border-color: var(--accent);
  background: rgba(var(--accent-rgb), 0.07);
}

.resultado-tag {
  grid-column: 1;
  justify-self: start;
  margin-top: 4px;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-ink);
  background: var(--accent);
  padding: 3px 8px;
  border-radius: 999px;
}

.resultado-nombre {
  grid-column: 1;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
}

.resultado-meta {
  grid-column: 1;
  display: flex;
  gap: var(--sp-3);
  font-size: 11px;
  color: var(--text-mute);
}

.resultado-nivel {
  font-family: var(--font-display);
  letter-spacing: 0.18em;
  color: var(--accent);
}

.resultado-saldo {
  grid-column: 2;
  grid-row: 1 / span 2;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-soft);
  white-space: nowrap;
}

/* --- Panel del cliente elegido ------------------------------------------ */
.sumar-panel {
  background: var(--bg-1);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  padding: var(--sp-4);
  margin-bottom: var(--sp-6);
}

.sumar-cab {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-bottom: var(--sp-4);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--sp-4);
}

.sumar-nombre {
  display: block;
  font-family: var(--font-display);
  font-size: 20px;
  letter-spacing: 0.1em;
  color: var(--text);
  text-decoration: none;
  line-height: 1.1;
  overflow-wrap: anywhere;
}

.sumar-nombre:hover { color: var(--accent); }

.sumar-nivel {
  font-family: var(--font-display);
  font-size: 12px;
  letter-spacing: 0.24em;
  color: var(--accent);
}

.sumar-saldo {
  text-align: right;
  flex: none;
  white-space: nowrap;
}

.sumar-saldo-n {
  font-family: var(--font-mono);
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
}

.sumar-saldo-l {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--text-mute);
  margin-left: 4px;
}

/* --- Los botones de accion ---------------------------------------------- */
/* 44px: no son botones de servicio (esos son .servicio-btn, en la grilla
   aparte, y sí quedan en 56px). */
.acciones-grandes {
  display: grid;
  gap: var(--sp-2);
}

.accion-form { display: contents; }

.accion-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  width: 100%;
  min-height: 44px;
  padding: 0 var(--sp-4);
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: border-color var(--t) ease, background var(--t) ease, transform var(--t-fast) ease;
}

.accion-btn:hover {
  border-color: var(--accent);
  background: rgba(var(--accent-rgb), 0.07);
}

.accion-btn:active { transform: scale(0.985); }

.accion-txt { overflow-wrap: anywhere; }

.accion-pts {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--accent);
  white-space: nowrap;
}

/* --- Deshacer sin JavaScript -------------------------------------------- */
.deshacer-barra {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3);
  margin-bottom: var(--sp-4);
  border: 1px solid rgba(var(--accent-rgb), 0.4);
  border-radius: var(--radius);
  background: rgba(var(--accent-rgb), 0.06);
  font-size: 14px;
  color: var(--text-soft);
}

/* --- Aviso de referido pendiente ----------------------------------------- */
/* Ya no es un botón solo: "Es nuevo, acreditar" y "Ya era cliente" van en
   fila propia debajo del texto, no lado a lado con él — con dos formularios
   el flex de una sola fila de antes quedaba muy apretado. */
.aviso-referido {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-3);
  margin-bottom: var(--sp-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg-2);
  font-size: 14px;
  color: var(--text-soft);
}

.aviso-referido p { margin: 0; }

.aviso-referido-acciones {
  display: flex;
  gap: var(--sp-2);
}

.aviso-referido-acciones form { flex: 1; }
.aviso-referido-acciones .btn-ghost { width: 100%; }
.aviso-referido b { color: var(--text); }

/* --- Servicios: grilla de dos, primero en la pantalla ------------------- */
.servicios-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-2);
}

@media (min-width: 720px) {
  .servicios-grid { grid-template-columns: repeat(3, 1fr); }
}

.servicio-btn {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 4px;
  width: 100%;
  min-height: 56px;
  padding: var(--sp-2) var(--sp-3);
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  color: var(--text);
  font-family: var(--font-body);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--t) ease, background var(--t) ease, transform var(--t-fast) ease;
}

.servicio-btn:hover {
  border-color: var(--accent);
  background: rgba(var(--accent-rgb), 0.07);
}

.servicio-btn:active { transform: scale(0.985); }

.servicio-txt {
  font-size: 12px;
  font-weight: 500;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.servicio-pts {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--accent);
}

/* --- Compra de productos, dentro de "más formas de sumar" --------------- */
.field-productos {
  margin-top: var(--sp-4);
}

.field-productos .label { margin-bottom: 6px; }
.field-productos .opcional { text-transform: none; letter-spacing: 0; color: var(--accent); }

.custom-monto {
  display: flex;
  gap: var(--sp-2);
}

.custom-monto .input { flex: 1; min-width: 0; }

/* --- Ajuste manual y "más formas de sumar", plegados -------------------- */
.ajuste,
.mas-formas {
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}

.ajuste summary,
.mas-formas > summary {
  display: flex;
  align-items: center;
  min-height: 44px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-mute);
  cursor: pointer;
}

.ajuste summary:hover,
.mas-formas > summary:hover { color: var(--accent); }
.ajuste form { margin-top: var(--sp-3); }
.mas-formas .acciones-grandes { margin-top: var(--sp-3); }

/* --- Boton dentro del toast --------------------------------------------- */
.toast-accion {
  margin-left: var(--sp-4);
  padding: 6px var(--sp-3);
  min-height: 36px;
  background: none;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  color: var(--accent);
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
}

.toast-accion:hover { background: rgba(var(--accent-rgb), 0.12); }

/* --- Niveles en el panel ------------------------------------------------ */
.niveles { display: grid; gap: var(--sp-4); }

.nivel-fila {
  display: grid;
  grid-template-columns: 1fr 120px auto;
  gap: var(--sp-3);
  align-items: end;
  padding-bottom: var(--sp-4);
  border-bottom: 1px solid var(--border);
}

.nivel-fila:last-child { border-bottom: 0; padding-bottom: 0; }
.nivel-fila .field { margin-bottom: 0; }

@media (max-width: 480px) {
  .nivel-fila { grid-template-columns: 1fr 1fr; }
  .nivel-fila button { grid-column: 1 / -1; }
}

.reg-nivel {
  font-family: var(--font-display);
  letter-spacing: 0.18em;
  color: var(--accent);
}

.ficha-nivel {
  /* Fila propia: la rejilla de arriba es de 3 columnas y meterlo en una
     sola lo desbordaba en 360px. */
  grid-column: 1 / -1;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-top: 1px solid var(--border);
}

.ficha-nivel-n {
  font-family: var(--font-display);
  font-size: 20px;
  letter-spacing: 0.2em;
  color: var(--accent);
}

.ficha-nivel-f {
  font-size: 11px;
  color: var(--text-mute);
  text-align: right;
}

/* -------------------------------------------------------------------------
   16. SECCIONES DEL PANEL
   Vivian en la seccion 13 vieja y se fueron al reemplazarla por la tarjeta
   del prototipo. El panel las seguia usando, y por eso su texto quedaba
   apilado sin estilos.
   ------------------------------------------------------------------------- */
.bloque {
  margin-bottom: var(--sp-6);
}

.bloque-titulo {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-mute);
  margin-bottom: var(--sp-3);
  line-height: 1.2;
}

/* "Nueva acción" plegada por defecto: mismo cheurón que .editable-resumen,
   sobre .bloque-titulo en vez de duplicar la regla para un solo caso. */
.bloque-plegado > summary.bloque-titulo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 44px;
  margin-bottom: 0;
  cursor: pointer;
  list-style: none;
}

.bloque-plegado > summary.bloque-titulo::-webkit-details-marker { display: none; }
.bloque-plegado > summary.bloque-titulo::marker { content: ''; }

.bloque-plegado > summary.bloque-titulo::after {
  content: '';
  flex: none;
  width: 7px;
  height: 7px;
  margin-left: var(--sp-2);
  border-right: 2px solid var(--text-mute);
  border-bottom: 2px solid var(--text-mute);
  transform: rotate(-45deg);
  transition: transform var(--t) ease;
}

.bloque-plegado[open] > summary.bloque-titulo::after { transform: rotate(45deg); }
.bloque-plegado[open] > summary.bloque-titulo { margin-bottom: var(--sp-3); }
.bloque-plegado .panel-form { margin-top: var(--sp-3); }

.bloque-nota {
  font-size: 11px;
  line-height: 1.55;
  color: var(--text-dim);
  margin-top: var(--sp-3);
  text-align: center;
}

.bloque-nota-top {
  text-align: left;
  margin: 0 0 var(--sp-4);
  font-size: 12px;
  color: var(--text-mute);
}

.lista-vacia {
  padding: var(--sp-6) var(--sp-5);
  text-align: center;
  font-size: 14px;
  color: var(--text-dim);
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}

/* El importe de una fila de la cola de canjes. */
.reg-puntos {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
  color: var(--text-mute);
}

.reg-puntos.suma { color: var(--success); }
.reg-puntos.resta { color: var(--accent); }

/* --- Vista previa ------------------------------------------------------- */
/* Es una foto de la fila real del cliente, no un control: `inert` la saca
   del orden de foco y esto remata que no se pueda tocar. */
.previa-caja {
  pointer-events: none;
  user-select: none;
}

/* La ficha del cliente: el titulo de cada dato va arriba y el valor abajo,
   asi que la fila no necesita el alto minimo de la tarjeta. */
.list .row-sub:first-child {
  margin-top: 0;
  margin-bottom: 2px;
}
