/* ============================================
   comparTICKET — Diseño v5
   ============================================ */

/* Las fuentes se cargan con <link rel="preconnect"> en el <head> de cada
   página. Con @import aquí el navegador no descubría que hacían falta
   hasta haber descargado y leído esta hoja entera. */

:root {
  --bg: #ECEAE4;
  --bg-deep: #E5E2DA;
  --paper: #FEFEF8;
  --black: #18181B;
  --dark: #27272A;
  --printer-1: #0C0C0E;
  --printer-2: #1A1A1D;
  --printer-3: #26262A;
  --printer-edge: #3A3A40;
  --gray-900: #3F3F46;
  --gray-700: #52525B;
  --gray-500: #71717A;
  --gray-400: #A1A1AA;
  --gray-300: #D4D4D8;
  --gray-200: #E4E4E7;
  --gray-100: #F4F4F5;
  --gray-50:  #FAFAFA;
  --green: #16A34A;
  --green-light: #DCFCE7;
  --blue: #2563EB;
  --blue-light: #DBEAFE;
  --red:  #DC2626;
  --red-light: #FEE2E2;
  --orange: #EA580C;
  --accent: #FF6B35;      /* signature accent */
  --accent-2: #2563EB;
  /* La reserva va SIEMPRE justo detras de la buena: es la que se usa hasta
     que llega, y esta calibrada para ocupar lo mismo (ver los @font-face de
     abajo). Sin ella, al llegar la fuente se recolocaba la pagina entera. */
  --sans: 'DM Sans', 'DM Sans reserva', -apple-system, BlinkMacSystemFont, sans-serif;
  --display: 'Bricolage Grotesque', 'Bricolage reserva', 'DM Sans', sans-serif;
  --mono: 'Space Mono', 'Space Mono reserva', 'Courier New', monospace;
  --shadow-printer: 0 18px 52px rgba(0,0,0,0.28), 0 6px 16px rgba(0,0,0,0.20);
  --shadow-ticket: 4px 14px 36px rgba(0,0,0,0.10), 0 2px 6px rgba(0,0,0,0.06);
  --shadow-btn: 0 4px 14px rgba(0,0,0,0.13);
  --radius: 16px;
  --radius-sm: 10px;
  --radius-xs: 7px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* EL FOCO DE TECLADO. Hay una decena de sitios sueltos por este fichero que
   quitan el `outline` nativo (inputs, botones sin borde, selects) porque un
   anillo azul por defecto no pegaba con el resto — pero se lo quitaron a
   TODO el mundo, no solo al ratón. Alguien navegando solo con el teclado se
   queda sin saber dónde está.

   En vez de tocar esos diez sitios uno a uno, una única regla global con
   `:focus-visible` —que el navegador ya distingue solo del clic de ratón—
   y el !important justo para ganarle a esos `outline: none` más
   específicos sin reescribirlos. El ratón sigue viéndose exactamente igual
   que antes; el teclado, por fin, ve algo. */
:focus-visible {
  outline: 2px solid var(--accent) !important;
  outline-offset: 2px !important;
}

html {
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-family: var(--sans);
  background: var(--bg);
  color: var(--black);
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  overflow-x: hidden;
}

.page {
  width: 100%;
  max-width: 430px;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  position: relative;
  /* Sin el `env()`, en un iPhone con barra de gestos el último botón visible
     -"Marcar lo mío" al compartir, "Grupos" en la portada- quedaba debajo de
     esa barra: los 12px de siempre no reservaban su hueco real, que en esos
     móviles ronda los 20-34px. */
  padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
}

/* =============================================
   TOP NAV BAR
   ============================================= */

.top-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* El viewport pasa a extenderse bajo el notch/la isla dinámica (ver
     viewport-fit=cover en el <head>) para que el resto de SafeArea funcione
     de verdad — pero eso significa que esta barra, fija arriba en cada
     pantalla, necesita su propio hueco o el notch se la comería. */
  padding: calc(14px + env(safe-area-inset-top, 0px)) 18px 10px;
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--bg);
}

.top-bar-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1rem;
  text-align: center;
  flex: 1;
  letter-spacing: -0.02em;
}

/* Brand logo: artistic comparTICKET */
.brand-logo {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.02rem;
  letter-spacing: -0.03em;
  color: var(--black);
  user-select: none;
}
.brand-logo .bl-compar {
  font-weight: 500;
  font-style: italic;
  color: var(--gray-700);
  letter-spacing: -0.02em;
}
/* El nombre, tal cual es en el resto de la app: "compar" en gris claro y
   "TICKET" en negro macizo. Llevaba un degradado de negro a naranja recortado
   sobre el texto que no esta en ningun otro sitio -ni en el icono, ni en el
   banner, ni en la cabecera de las otras pantallas- y hacia que la marca se
   leyera distinta en cada pantalla. Un nombre no cambia de color segun donde
   se mire. */
.brand-logo .bl-ticket {
  font-weight: 800;
  color: var(--black);
  letter-spacing: -0.02em;
}
.brand-logo .bl-mark {
  display: inline-block;
  width: 18px;
  height: 18px;
  position: relative;
}

.top-bar-btn {
  /* 44px, no 36: es el botón de "atrás" y aparece en casi cada pantalla —
     justo lo que más se toca con prisa y una sola mano. */
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--black);
  transition: background 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.top-bar-btn:hover { background: rgba(0,0,0,0.06); }
.top-bar-btn svg { width: 22px; height: 22px; fill: currentColor; }

/* El de "Compartir app" de la portada: mismo boton redondo, pero con el
   nombre debajo del icono en la fuente de ticket, en pequeno -para que se
   entienda de un vistazo que comparte la app y no otra cosa. Por eso no
   puede medir 36px fijos como el resto: crece lo que el texto pida. */
.top-bar-btn-labeled {
  width: auto;
  height: auto;
  flex-direction: column;
  gap: 2px;
  /* Medido en vivo: con 4px/8px el ancho real se queda en 42px, un pelo
     por debajo del mínimo táctil aunque el alto ya sobraba. */
  padding: 6px 9px;
  border-radius: var(--radius-xs);
}
.top-bar-btn-labeled svg { width: 18px; height: 18px; }
.top-bar-btn-labeled span {
  font-family: var(--mono);
  font-size: 0.56rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--gray-500);
  white-space: nowrap;
}

/* =============================================
   PRINTER ASSEMBLY — more 3D
   ============================================= */

.printer-assembly {
  /* EL ANCHO DEL PAPEL, EN UN SOLO SITIO. La boca se calcula a partir de el
     (ver .printer-slot-line), asi que no pueden descuadrarse. Estaban sueltos
     y en `.pantalla-ancha` el papel se iba al 93 % con la boca en el 90 %: el
     ticket salia por una ranura mas estrecha que el, que es imposible. */
  --papel-ancho: 82%;
  position: relative;
  padding: 0 16px;
  margin-bottom: 0;
}

/* Outer "body" of the printer machine */
.printer-body {
  position: relative;
  border-radius: 18px 18px 4px 4px;
  /* 40 px abajo y no 22: hace falta carcasa POR DEBAJO de la boca para que se
     vea maquina a los lados del papel cuando sale. */
  padding: 18px 22px 40px;
  min-height: 96px;
  box-shadow: var(--shadow-printer);
  /* DETRAS del papel. Estaba en 3 —delante— y por eso la carcasa tapaba el
     ticket hasta su canto de abajo: asomaba "de debajo del dibujo" en vez de
     salir por la boca. El papel de una impresora de verdad cuelga POR DELANTE
     de la maquina; es un orden de capas, no una geometria. */
  z-index: 1;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background:
    linear-gradient(180deg,
      var(--printer-1) 0%,
      var(--printer-2) 42%,
      var(--printer-3) 75%,
      var(--printer-1) 100%);
}
.printer-body > * { position: relative; z-index: 2; }

/* Top reflection highlight */
.printer-body::before {
  content: '';
  position: absolute;
  top: 0;
  left: 10%;
  right: 10%;
  height: 32%;
  background: linear-gradient(180deg, rgba(255,255,255,0.09), rgba(255,255,255,0));
  border-radius: 18px 18px 0 0;
  pointer-events: none;
}

/* Subtle matte texture */
.printer-body::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 50% 0%, rgba(255,255,255,0.05), transparent 60%),
    repeating-linear-gradient(0deg, transparent 0 2px, rgba(255,255,255,0.015) 2px 3px);
  pointer-events: none;
}

.printer-inner {
  position: relative;
  padding: 14px 22px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  z-index: 1;
}

/* Brand name engraved on printer */
.printer-brand {
  font-family: var(--display);
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  display: inline-flex;
  align-items: baseline;
  gap: 0;
  line-height: 1;
}
.printer-brand span {
  font-weight: 400;
  color: rgba(255,255,255,0.55);
  text-shadow: 0 1px 0 rgba(0,0,0,0.4);
}
.printer-brand strong {
  font-weight: 800;
  letter-spacing: -0.02em;
  background: linear-gradient(95deg,#FFFFFF 0%, #FFC2A1 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 1px 0 rgba(0,0,0,0.35));
}

/* LED cluster on printer */
.printer-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 5px;
}
.printer-leds {
  display: flex;
  gap: 5px;
  align-items: center;
}
.printer-led {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.4);
}
.printer-led.on {
  background: radial-gradient(circle at 35% 35%, #7EFF9A 0%, #22C55E 60%, #166534 100%);
  box-shadow:
    0 0 8px #22C55E,
    0 0 2px #22C55E,
    inset 0 1px 1px rgba(255,255,255,0.4);
  animation: ledPulse 2.4s ease-in-out infinite;
}
.printer-led.idle {
  background: radial-gradient(circle at 35% 35%, #3A3A3A 0%, #1A1A1A 70%);
}
@keyframes ledPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

.printer-label {
  font-family: var(--mono);
  font-size: 0.52rem;
  font-weight: 400;
  color: rgba(255,255,255,0.28);
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

/* Dark slit at the bottom of the printer body (the slot the ticket emerges from) */
/* LA BOCA. Era una linea de 4 px pegada al canto de abajo; ahora es un hueco
   hundido de 11 px, subido 26 px para que quede carcasa por debajo.
   Y ANCHA: el 90 % del cuerpo. La de antes media el 84 % y el ticket el 82 %,
   o sea que el papel era casi tan ancho como la ranura por la que sale. Eso no
   se sostiene: la ranura tiene que ser mas ancha que lo que pasa por ella. */
.printer-slot-line {
  position: absolute;
  /* 9 px de holgura a cada lado del papel. La boca SIEMPRE mas ancha que lo
     que pasa por ella, se cambie el ancho del ticket donde se cambie. */
  left: calc((100% - var(--papel-ancho)) / 2 - 9px);
  right: calc((100% - var(--papel-ancho)) / 2 - 9px);
  bottom: 26px;
  height: 11px;
  border-radius: 3px;
  background: linear-gradient(180deg, #000 0%, #060608 45%, #111114 100%);
  box-shadow:
    inset 0 4px 7px rgba(0,0,0,1),
    inset 0 -1px 0 rgba(255,255,255,0.06),
    0 1px 0 rgba(255,255,255,0.07);
  z-index: 2;
}

/* =============================================
   TICKET — emerges from printer slot, with notches + zigzag
   ============================================= */

/* LA VENTANA POR LA QUE SALE EL PAPEL.
   Su canto de arriba ES la ranura: recorta lo que aun no ha salido, y el papel
   viaja dentro de ella desde dentro de la maquina hasta su sitio. El ticket
   sale de la boca por construccion, sin fingirlo con laminas ni con labios.
   Va DELANTE de la carcasa y se mete 26 px dentro de su silueta, justo hasta
   el canto de abajo de la boca. */
.ticket-wrap {
  /* Sin medir, cero: el papel no se mueve y se ve. Es el fallo menos malo —
     una animacion que no ocurre, en vez de un ticket invisible. */
  --papel-h: 0px;
  position: relative;
  width: var(--papel-ancho);
  margin: -26px auto 0;
  z-index: 5;
  overflow: hidden;
  filter: drop-shadow(2px 4px 14px rgba(0,0,0,0.08)) drop-shadow(0 2px 4px rgba(0,0,0,0.05));
}
/* La sombra que la ranura proyecta sobre el papel que asoma. QUIETA en el canto
   de arriba: pegada a lo que se movia bajaba con el, y era una raya negra
   recorriendo la pantalla. */
.ticket-wrap::before {
  content: '';
  position: absolute;
  z-index: 5;
  left: 0; right: 0; top: 0;
  height: 9px;
  background: linear-gradient(to bottom, rgba(0,0,0,0.3), rgba(0,0,0,0));
  pointer-events: none;
}

.ticket {
  position: relative;
  background: var(--paper);
  padding: 18px 20px 18px;
  /* CSS mask for side notches — always pixel-perfect cuts */
  -webkit-mask:
    radial-gradient(circle 11px at 0% 50%,  transparent 99%, #000 100%),
    radial-gradient(circle 11px at 100% 50%, transparent 99%, #000 100%);
  -webkit-mask-composite: source-in;
  mask:
    radial-gradient(circle 11px at 0% 50%,  transparent 99%, #000 100%),
    radial-gradient(circle 11px at 100% 50%, transparent 99%, #000 100%);
  mask-composite: intersect;
}

/* Fallback when mask-composite not supported: use inner shadows to emulate notches */
@supports not (mask-composite: intersect) {
  .ticket {
    -webkit-mask: none;
    mask: none;
  }
  .ticket::before,
  .ticket::after {
    content: '';
    position: absolute;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--bg);
    top: 50%;
    transform: translateY(-50%);
    z-index: 4;
    box-shadow: inset 0 0 4px rgba(0,0,0,0.1);
  }
  .ticket::before { left: -11px; }
  .ticket::after  { right: -11px; }
}

/* Zigzag torn bottom — using clip-path for pixel-perfect rendering */
.ticket-zigzag {
  position: relative;
  height: 10px;
  width: 100%;
  background: var(--paper);
  clip-path: polygon(
    0 0, 100% 0,
    100% 0,
    97.5% 100%, 95% 0, 92.5% 100%, 90% 0,
    87.5% 100%, 85% 0, 82.5% 100%, 80% 0,
    77.5% 100%, 75% 0, 72.5% 100%, 70% 0,
    67.5% 100%, 65% 0, 62.5% 100%, 60% 0,
    57.5% 100%, 55% 0, 52.5% 100%, 50% 0,
    47.5% 100%, 45% 0, 42.5% 100%, 40% 0,
    37.5% 100%, 35% 0, 32.5% 100%, 30% 0,
    27.5% 100%, 25% 0, 22.5% 100%, 20% 0,
    17.5% 100%, 15% 0, 12.5% 100%, 10% 0,
    7.5% 100%, 5% 0, 2.5% 100%, 0 0
  );
  margin-top: -1px; /* seamless with ticket */
}

/* EL TICKET SALIENDO DE LA IMPRESORA — TERCERA VERSION, Y LA BUENA.
 *
 * Historia corta, porque las dos anteriores fallaron por el mismo sitio y
 * conviene que no haya una cuarta:
 *
 *   1ª — Animaba `max-height` y los dos `padding` durante 3,4 s. Las tres son
 *        propiedades de MAQUETACION: el navegador recolocaba las 35 lineas de
 *        un ticket del super, y la pagina entera por debajo, en cada uno de
 *        los 200 fotogramas. A trompicones.
 *
 *   2ª — Se cambio a `clip-path`, que no toca la maquetacion, pero se le puso
 *        `will-change: clip-path`. En un elemento de 2.773 px de alto eso
 *        obliga al navegador a rasterizar una capa enorme, y hasta que
 *        termina se ve el papel sin su contenido: salia el ticket y DESPUES
 *        el texto de golpe. Peor que antes.
 *
 * La leccion de las dos: cualquier cosa que obligue a recalcular o a repintar
 * un elemento de tres mil pixeles va a ir mal en un movil, por muy elegante
 * que sea la propiedad.
 *
 * Asi que esta version solo mueve `transform` y `opacity`. Son las dos unicas
 * que no cuestan NI maquetacion NI repintado: el navegador pinta el ticket una
 * sola vez y luego se limita a desplazar esa imagen ya hecha, que es trabajo
 * de la tarjeta grafica y no del hilo principal.
 *
 * Y hay algo que esto arregla por construccion, no por suerte: el papel y su
 * contenido son EL MISMO elemento moviendose. No pueden ir cada uno por su
 * lado porque no son dos cosas.
 *
 * El caracter de impresora lo da la curva, no la propiedad: sale rapido —como
 * un rodillo que empuja— se pasa tres pixeles y se asienta. Es el gesto que
 * hace una impresora de tickets de verdad al soltar el papel.
 *
 * 560 ms. La primera version duraba 3,4 s, y ese es el rato que alguien esta
 * esperando para ver lo que tiene que pagar.
 *
 * NADA DE `will-change` AQUI. Fue exactamente lo que rompio la version 2.
 */
/* ANTES DE TENER CONTENIDO NO SE ENSENA NADA.
   El papel no existe hasta que hay algo escrito en el: se ve la impresora, y
   cuando el ticket esta listo sale entero. Ensenar la caja vacia mientras se
   espera a la API era lo que hacia que pareciera que salia a trozos. */
.ticket.esperando,
.ticket.esperando + .ticket-zigzag {
  opacity: 0;
  animation: none;
}

/* EL FOTOGRAMA QUE SE PERDIA, Y POR QUE.
   Medido en Chrome: de 44 fotogramas de la impresion, uno tardaba 40 ms en vez
   de 16,6, y con CERO tareas largas de JavaScript. O sea que no era codigo
   bloqueando: era el navegador PINTANDO el ticket por primera vez, y lo hacia
   cuando la animacion ya habia empezado.
   Tiene sentido: mientras espera esta a `opacity: 0`, y lo que es
   completamente invisible el navegador no se molesta en dibujarlo. El primer
   fotograma del movimiento era tambien el primero en que tenia que dibujar
   2.700 px de ticket.
   Asi que hay un paso intermedio: `listo` lo deja practicamente invisible
   -pero no del todo, que es la diferencia- y le pide al navegador que prepare
   su capa. Dos fotogramas despues, cuando ya esta dibujado, empieza a moverse.
   `will-change` AQUI SI es correcto: dura dos fotogramas y su proposito es
   exactamente ese. Lo que estuvo mal antes fue dejarlo puesto durante toda una
   animacion de recorte sobre un elemento de miles de pixeles. */
.ticket.listo,
.ticket.listo + .ticket-zigzag {
  opacity: 0.004;
  animation: none;
  will-change: transform, opacity;
}

/* Y al salir, UN SOLO movimiento. Cada linea del ticket trae su propia
   animacion de entrada (`claim-in`), y si corren a la vez que la del papel se
   ven dos cosas moviendose con ritmos distintos: el papel bajando y las lineas
   subiendo por dentro. Mientras se imprime, las lineas van quietas y montadas
   en el papel, que es lo que hace una impresora de verdad. */
.ticket.printing .claim-row-v2,
.ticket.printing .edit-row,
.ticket.printing .person-row {
  animation: none;
}

.ticket.printing,
.ticket.printing + .ticket-zigzag {
  /* `linear` a proposito, y no una curva. Con una `ease-out` el 95 % del
     recorrido se gastaba en los primeros 170 ms de 560: el papel aparecia de
     golpe y luego no pasaba nada, que es justo lo que se queria evitar. En
     lineal, cada porcentaje de los keyframes ES un porcentaje del tiempo, asi
     que el movimiento se reparte de verdad y se controla aqui abajo. Ademas un
     avance constante es lo que hace un rodillo: la impresora no acelera. */
  /* `linear` a proposito. El ritmo NO esta en la curva: esta en los
     fotogramas, que avanzan y se paran catorce veces. Una curva encima se lo
     comeria. El nombre y la duracion los pone el JS segun lo largo que sea el
     ticket (ver fitTicket). */
  animation: var(--papel-anim, papel-corto) var(--papel-dur, 1.5s) linear forwards;
  transform-origin: top center;
}

/* Al terminar de "imprimirse" se quitan TODAS las ataduras. A partir de aquí
 * el ticket es una caja normal: ni recortes ni alturas máximas, pase lo que
 * pase con el contenido (añadir líneas, plegar la ayuda, girar el móvil). */
/* Al terminar se sueltan todas las ataduras: a partir de aqui el ticket es una
   caja normal, pase lo que pase con el contenido. Las de `max-height`,
   `overflow` y `clip-path` son herencia de las dos versiones anteriores y se
   quedan como red: si alguna vuelve por descuido, esto la desactiva. */
.ticket.printed,
.ticket.printed + .ticket-zigzag {
  animation: none;
  /* Se suelta la capa que se reservó para la animación: mantenerla ocupa
     memoria de vídeo para nada una vez que el ticket ya no se mueve. */
  will-change: auto;
  max-height: none;
  overflow: visible;
  will-change: auto;
  opacity: 1;
  transform: none;
}
/* `clip-path: none` SOLO en el ticket, nunca en el borde dentado. Los dientes
   los dibuja un `clip-path: polygon(...)` en .ticket-zigzag: al meter las dos
   reglas juntas para ahorrar lineas, esto le borraba el poligono y el ticket
   se quedaba con el borde recto en las tres pantallas. Ahorrar dos lineas de
   CSS no vale un borde dentado. */
.ticket.printed { clip-path: none; }

/* Solo `transform` y `opacity`. Si algun dia hace falta anadir algo aqui, que
   sea una de esas dos: lo demas se paga en fotogramas perdidos.
   El papel arranca escondido detras del cuerpo de la impresora —que va por
   encima, con z-index 3— asi que se lee como que sale por la ranura. */
/* EL AVANCE A PASOS.
   Catorce empujones con una pausa entre ellos. No es un deslizamiento: un
   rodillo alimenta a tirones, y ese pulso es lo que hace que parezca una
   impresora y no un elemento que se desplaza.
   Las POSICIONES salen de una curva suave, asi que los saltos son pequenos al
   principio y al final y grandes en medio: arranca, coge ritmo y frena. El
   TIEMPO va lineal.
   Las pausas duran 18 ms a proposito —menos que un fotograma—: en una pantalla
   lenta desaparecen y queda suave, en vez de leerse como un tiron. */
@keyframes papel-corto {
  0.00% { transform: translateY(calc(var(--papel-h) * -1.0000)); }
  6.29% { transform: translateY(calc(var(--papel-h) * -0.9854)); }
  7.14% { transform: translateY(calc(var(--papel-h) * -0.9854)); }
  13.43% { transform: translateY(calc(var(--papel-h) * -0.9446)); }
  14.29% { transform: translateY(calc(var(--papel-h) * -0.9446)); }
  20.57% { transform: translateY(calc(var(--papel-h) * -0.8819)); }
  21.43% { transform: translateY(calc(var(--papel-h) * -0.8819)); }
  27.71% { transform: translateY(calc(var(--papel-h) * -0.8017)); }
  28.57% { transform: translateY(calc(var(--papel-h) * -0.8017)); }
  34.86% { transform: translateY(calc(var(--papel-h) * -0.7085)); }
  35.71% { transform: translateY(calc(var(--papel-h) * -0.7085)); }
  42.00% { transform: translateY(calc(var(--papel-h) * -0.6064)); }
  42.86% { transform: translateY(calc(var(--papel-h) * -0.6064)); }
  49.14% { transform: translateY(calc(var(--papel-h) * -0.5000)); }
  50.00% { transform: translateY(calc(var(--papel-h) * -0.5000)); }
  56.29% { transform: translateY(calc(var(--papel-h) * -0.3936)); }
  57.14% { transform: translateY(calc(var(--papel-h) * -0.3936)); }
  63.43% { transform: translateY(calc(var(--papel-h) * -0.2915)); }
  64.29% { transform: translateY(calc(var(--papel-h) * -0.2915)); }
  70.57% { transform: translateY(calc(var(--papel-h) * -0.1983)); }
  71.43% { transform: translateY(calc(var(--papel-h) * -0.1983)); }
  77.71% { transform: translateY(calc(var(--papel-h) * -0.1181)); }
  78.57% { transform: translateY(calc(var(--papel-h) * -0.1181)); }
  84.86% { transform: translateY(calc(var(--papel-h) * -0.0554)); }
  85.71% { transform: translateY(calc(var(--papel-h) * -0.0554)); }
  92.00% { transform: translateY(calc(var(--papel-h) * -0.0146)); }
  92.86% { transform: translateY(calc(var(--papel-h) * -0.0146)); }
  99.14% { transform: translateY(calc(var(--papel-h) * -0.0000)); }
  100% { transform: translateY(0); }
}

/* El mismo ritmo, para tickets que no caben en la pantalla.
   A velocidad constante, un ticket del super de 2.700 px tardaria diez segundos
   y medio en salir. Asi que el ritmo se mantiene IDENTICO durante los primeros
   416 px —que es lo que se ve y lo que se siente— y lo que sobra se termina en
   el ultimo 30 % del tiempo con una curva rapida.
   Todos los tickets arrancan exactamente igual; ninguno pasa de 2,3 s. */
@keyframes papel-largo {
  0.00% { transform: translateY(calc(416px * 0.0000 - var(--papel-h))); }
  4.40% { transform: translateY(calc(416px * 0.0146 - var(--papel-h))); }
  5.00% { transform: translateY(calc(416px * 0.0146 - var(--papel-h))); }
  9.40% { transform: translateY(calc(416px * 0.0554 - var(--papel-h))); }
  10.00% { transform: translateY(calc(416px * 0.0554 - var(--papel-h))); }
  14.40% { transform: translateY(calc(416px * 0.1181 - var(--papel-h))); }
  15.00% { transform: translateY(calc(416px * 0.1181 - var(--papel-h))); }
  19.40% { transform: translateY(calc(416px * 0.1983 - var(--papel-h))); }
  20.00% { transform: translateY(calc(416px * 0.1983 - var(--papel-h))); }
  24.40% { transform: translateY(calc(416px * 0.2915 - var(--papel-h))); }
  25.00% { transform: translateY(calc(416px * 0.2915 - var(--papel-h))); }
  29.40% { transform: translateY(calc(416px * 0.3936 - var(--papel-h))); }
  30.00% { transform: translateY(calc(416px * 0.3936 - var(--papel-h))); }
  34.40% { transform: translateY(calc(416px * 0.5000 - var(--papel-h))); }
  35.00% { transform: translateY(calc(416px * 0.5000 - var(--papel-h))); }
  39.40% { transform: translateY(calc(416px * 0.6064 - var(--papel-h))); }
  40.00% { transform: translateY(calc(416px * 0.6064 - var(--papel-h))); }
  44.40% { transform: translateY(calc(416px * 0.7085 - var(--papel-h))); }
  45.00% { transform: translateY(calc(416px * 0.7085 - var(--papel-h))); }
  49.40% { transform: translateY(calc(416px * 0.8017 - var(--papel-h))); }
  50.00% { transform: translateY(calc(416px * 0.8017 - var(--papel-h))); }
  54.40% { transform: translateY(calc(416px * 0.8819 - var(--papel-h))); }
  55.00% { transform: translateY(calc(416px * 0.8819 - var(--papel-h))); }
  59.40% { transform: translateY(calc(416px * 0.9446 - var(--papel-h))); }
  60.00% { transform: translateY(calc(416px * 0.9446 - var(--papel-h))); }
  64.40% { transform: translateY(calc(416px * 0.9854 - var(--papel-h))); }
  65.00% { transform: translateY(calc(416px * 0.9854 - var(--papel-h))); }
  69.40% { transform: translateY(calc(416px * 1.0000 - var(--papel-h))); }
  82% { transform: translateY(calc((var(--papel-h) - 416px) * -0.2500)); }
  91% { transform: translateY(calc((var(--papel-h) - 416px) * -0.0600)); }
  100% { transform: translateY(calc((var(--papel-h) - 416px) * -0.0000)); }
}

/* zigzagFollow ya no existe: el borde dentado se anima con los MISMOS
   keyframes que el ticket y en la misma regla, para que arranquen en el mismo
   fotograma. Cuando tenia animacion propia iba por su cuenta y se notaba. */

/* =============================================
   TICKET HEADER — restaurant/date
   ============================================= */

.ticket-header {
  text-align: center;
  padding-bottom: 10px;
}

.ticket-store {
  font-family: var(--mono);
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--black);
  margin-bottom: 3px;
  white-space: pre-line;
  letter-spacing: 0.02em;
  word-wrap: break-word;
}

.ticket-sub {
  font-family: var(--mono);
  font-size: 0.62rem;
  color: var(--gray-500);
  letter-spacing: 0.05em;
  line-height: 1.5;
}

.ticket-date {
  font-family: var(--mono);
  font-size: 0.62rem;
  color: var(--gray-500);
  letter-spacing: 0.05em;
  margin-top: 2px;
}

.dash-sep {
  border: none;
  height: 0;
  border-top: 1.5px dashed var(--gray-300);
  margin: 10px 0;
}
.dash-sep.heavy {
  border-top-width: 2px;
  border-color: var(--gray-300);
}

/* =============================================
   EDITABLE ITEMS — 2-row layout: name on top,
   controls below. Name wraps if long.
   ============================================= */

.edit-header {
  display: grid;
  grid-template-columns: 1fr 36px 58px 60px 24px;
  gap: 4px;
  padding: 0 0 6px;
  align-items: center;
}
.edit-header span {
  font-family: var(--mono);
  font-size: 0.56rem;
  color: var(--gray-400);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.edit-header .eh-c { text-align: center; }
.edit-header .eh-r { text-align: right; }

.edit-row {
  display: grid;
  grid-template-columns: 1fr 36px 58px 60px 24px;
  gap: 4px;
  align-items: start;
  padding: 4px 0;
  border-bottom: 1px solid var(--gray-100);
  animation: itemFade 0.35s ease forwards;
  opacity: 0;
}

.edit-row textarea.e-name,
.edit-row input.e-name {
  font-family: var(--mono);
  font-size: 0.76rem;
  font-weight: 400;
  border: none;
  padding: 4px;
  outline: none;
  background: transparent;
  border-radius: var(--radius-xs);
  transition: background 0.15s;
  width: 100%;
  color: var(--black);
  resize: none;
  overflow: hidden;
  min-height: 24px;
  line-height: 1.3;
  word-break: break-word;
  white-space: normal;
  box-sizing: border-box;
}
.edit-row textarea.e-name:focus,
.edit-row input.e-name:focus,
.edit-row input.e-qty:focus,
.edit-row input.e-price:focus { background: var(--blue-light); }

.edit-row input.e-qty,
.edit-row input.e-price {
  font-family: var(--mono);
  font-size: 0.74rem;
  font-weight: 400;
  border: none;
  padding: 4px;
  outline: none;
  background: transparent;
  border-radius: var(--radius-xs);
  transition: background 0.15s;
  width: 100%;
  color: var(--black);
  box-sizing: border-box;
  min-height: 24px;
}

.edit-row .e-qty   { text-align: center; color: var(--gray-500); }
.edit-row .e-price { text-align: right; }
.edit-row .e-total {
  text-align: right;
  font-weight: 700;
  font-size: 0.74rem;
  font-family: var(--mono);
  color: var(--black);
  padding: 6px 2px 0 0;
  white-space: nowrap;
}

.edit-row .e-del {
  width: 22px; height: 22px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--gray-400);
  cursor: pointer;
  font-size: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.15s;
  margin-top: 2px;
}
.edit-row .e-del:hover { background: var(--red-light); color: var(--red); }

@keyframes itemFade {
  from { opacity: 0; transform: translateY(-2px); }
  to   { opacity: 1; transform: translateY(0); }
}
.edit-row:nth-child(1)  { animation-delay: 0.10s; }
.edit-row:nth-child(2)  { animation-delay: 0.20s; }
.edit-row:nth-child(3)  { animation-delay: 0.30s; }
.edit-row:nth-child(4)  { animation-delay: 0.40s; }
.edit-row:nth-child(5)  { animation-delay: 0.50s; }
.edit-row:nth-child(6)  { animation-delay: 0.60s; }
.edit-row:nth-child(7)  { animation-delay: 0.70s; }
.edit-row:nth-child(8)  { animation-delay: 0.80s; }
.edit-row:nth-child(9)  { animation-delay: 0.90s; }
.edit-row:nth-child(10) { animation-delay: 1.00s; }

/* =============================================
   DATA ROWS
   ============================================= */

.data-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 5px 0;
  gap: 12px;
}
.data-label {
  font-family: var(--sans);
  font-size: 0.88rem;
  font-weight: 500;
  color: var(--gray-700);
}
.data-value {
  font-family: var(--mono);
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--black);
  white-space: nowrap;
}
.data-value.big { font-size: 1.25rem; font-weight: 700; }

/* =============================================
   CUADRE DE LA CUENTA
   El dinero que no cuadra tiene que verse, no esconderse.
   ============================================= */

/* Resumen: dinero que todavía no paga nadie */
.unassigned-row .data-label,
.unassigned-row .data-value {
  color: var(--red);
}
.unassigned-row.is-clear .data-label,
.unassigned-row.is-clear .data-value {
  color: var(--green);
}

/* Botón "?" junto a la cifra que falta por marcar */
.pending-btn {
  margin-right: 7px;
  width: 17px; height: 17px;
  padding: 0;
  border: 1.5px solid var(--red);
  border-radius: 50%;
  background: transparent;
  color: var(--red);
  font-family: var(--sans);
  font-size: 0.6rem;
  font-weight: 800;
  line-height: 1;
  cursor: pointer;
  vertical-align: middle;
}
.pending-btn:active { background: var(--red); color: #fff; }

/* Latido rojo sobre las unidades que no ha cogido nadie. Se llega aquí desde
   el resumen: con un ticket largo, saber qué faltaba obligaba a comparar la
   lista a ojo. */
/* Se declara el borde entero, no solo el color: la regla base de .unit-pill
   usa la forma abreviada `border:`, y así no queda ninguna duda de cuál gana
   ni depende del orden en que estén escritas. */
.unit-pill.pending-beat {
  border: 1.5px solid var(--red);
  color: var(--red);
  animation: pending-beat 1.25s ease-in-out infinite;
}
@keyframes pending-beat {
  0%, 100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0); }
  45%      { box-shadow: 0 0 0 4px rgba(220, 38, 38, 0.30); }
}
@media (prefers-reduced-motion: reduce) {
  .unit-pill.pending-beat {
    animation: none;
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.28);
  }
}

/* Suma de lo marcado — un escalón por debajo de las otras filas, porque es
   una comprobación de apoyo y no una cifra que nadie tenga que pagar. */
.claimed-row {
  margin-top: -2px;
}
.claimed-row .data-label,
.claimed-row .data-value {
  font-size: 0.66rem;
  color: var(--gray-400);
}
/* Mientras falte gente por marcar, que no cuadre es lo normal: se queda gris
   para no alarmar. Solo cuando han marcado todos el número significa algo. */
.claimed-row.is-final .data-label,
.claimed-row.is-final .data-value {
  font-weight: 700;
}
.claimed-row.is-ok .data-label,
.claimed-row.is-ok .data-value {
  color: var(--green);
}
.claimed-row.is-off .data-label,
.claimed-row.is-off .data-value {
  color: var(--red);
}

/* Revisión: las líneas no suman el total del ticket */
.mismatch {
  margin-top: 10px;
  padding: 12px;
  border: 1.5px dashed var(--red);
  border-radius: var(--radius-sm);
  background: var(--red-light);
}
.mm-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}
.mm-amount {
  font-family: var(--mono);
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--red);
  white-space: nowrap;
}
.mm-text {
  flex: 1 1 160px;
  font-family: var(--sans);
  font-size: 0.78rem;
  line-height: 1.35;
  color: var(--gray-900);
}
.mm-actions {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.mm-actions .btn {
  font-family: var(--mono);
  font-size: 0.72rem;
  padding: 9px 8px;
  border-radius: 8px;
  background: var(--paper);
}

/* Un botón deshabilitado tiene que parecerlo */
.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  filter: grayscale(0.4);
}

/* =============================================
   TIEMPO REAL
   ============================================= */

/* Punto de estado: guardado / sin conexión */
.live-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--green);
  transition: background 0.25s;
}
.live-dot.saved { animation: live-pulse 2.4s ease-in-out infinite; }
.live-dot.offline { background: var(--gray-400); animation: none; }

@keyframes live-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.45; transform: scale(0.82); }
}

/* Quién más está en el ticket ahora mismo */
.live-people {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  padding: 8px 0 2px;
}
.live-person {
  font-family: var(--mono);
  font-size: 0.63rem;
  padding: 3px 7px;
  border-radius: 999px;
  border: 1px solid var(--gray-300);
  color: var(--gray-700);
  background: var(--gray-50);
  white-space: nowrap;
}
.live-person.picking {
  border-color: var(--accent);
  color: var(--accent);
  background: transparent;
  animation: live-pulse 1.8s ease-in-out infinite;
}
.live-person.done {
  border-color: var(--green);
  color: var(--green);
  background: var(--green-light);
}

/* Destello al cambiar algo otra persona: hace visible el "en vivo".
   Las píldoras ya animan color y fondo para que el cambio se lea como un
   movimiento y no como un salto. */
.unit-pill {
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}
.unit-pill.just-changed {
  animation: pill-flash 0.75s ease-out;
}
@keyframes pill-flash {
  0%   { box-shadow: 0 0 0 0 rgba(255,107,53,0.55); transform: scale(1); }
  35%  { box-shadow: 0 0 0 5px rgba(255,107,53,0.22); transform: scale(1.06); }
  100% { box-shadow: 0 0 0 0 rgba(255,107,53,0); transform: scale(1); }
}

/* =============================================
   ONBOARDING Y AYUDAS
   ============================================= */

/* Etiqueta flotante de primera vez, señalando la primera píldora */
.coach-tip {
  position: absolute;
  transform: translateX(-50%);
  z-index: 60;
  background: var(--black);
  color: white;
  font-family: var(--sans);
  font-size: 0.76rem;
  font-weight: 600;
  line-height: 1.3;
  padding: 8px 12px;
  border-radius: 10px;
  max-width: 76vw;
  box-shadow: 0 8px 24px rgba(0,0,0,0.25);
  cursor: pointer;
  animation: coach-in 0.3s ease-out both;
}
.coach-tip::before {           /* pico apuntando a la píldora */
  content: '';
  position: absolute;
  top: -5px; left: 50%;
  margin-left: -5px;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 5px solid var(--black);
}
.coach-tip.leaving { animation: coach-out 0.22s ease-in both; }

@keyframes coach-in  { from { opacity: 0; transform: translateX(-50%) translateY(-6px); }
                       to   { opacity: 1; transform: translateX(-50%) translateY(0); } }
@keyframes coach-out { to   { opacity: 0; transform: translateX(-50%) translateY(-4px); } }

.unit-pill.coach-target {
  box-shadow: 0 0 0 3px rgba(255,107,53,0.35);
  animation: live-pulse 1.6s ease-in-out infinite;
}

/* Barra informativa: se ha recuperado una selección guardada en este móvil.
   Discreta a propósito — informa, no interroga. */
.identity-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 6px 0 2px;
  padding: 6px 10px;
  border-radius: 8px;
  background: var(--gray-100, #F4F4F5);
}
.identity-bar .ib-text {
  font-family: var(--mono);
  font-size: 0.63rem;
  letter-spacing: 0.02em;
  color: var(--gray-500);
}
.identity-bar .ib-text strong { color: var(--black); }
.identity-bar .ib-btn {
  flex-shrink: 0;
  border: none;
  background: none;
  padding: 2px 4px;
  font-family: var(--mono);
  font-size: 0.63rem;
  font-weight: 700;
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
}

/* Aviso: el nombre escrito ya tiene una selección guardada.
   Es el guardarraíl contra que dos personas del mismo móvil acaben
   compartiendo un claim y se pisen la selección. */
.name-taken {
  margin: 8px 0 2px;
  padding: 10px 12px;
  border: 1.5px dashed var(--accent);
  border-radius: var(--radius-sm);
  background: rgba(255, 107, 53, 0.07);
}
.name-taken .nt-text {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1.45;
  color: var(--black);
  margin-bottom: 8px;
}
.name-taken .nt-actions {
  display: flex;
  gap: 8px;
}
.name-taken .nt-actions .btn {
  flex: 1;
  font-family: var(--mono);
  font-size: 0.68rem;
  padding: 7px 6px;
  border-radius: 8px;
}

/* Campo del nombre reclamando atención al marcar sin haberlo puesto */
.name-field.needs-name input {
  border-color: var(--accent);
  background: rgba(255,107,53,0.07);
}
.name-field.needs-name label { color: var(--accent); }

/* Nombre bloqueado tras confirmar y volver con "atrás": se puede seguir
   corrigiendo la selección, pero no cambiar de identidad. El aspecto apagado
   comunica que el campo ya no responde al tacto, sin necesidad de texto. */
.name-field.locked input {
  background: var(--gray-100, #F4F4F5);
  color: var(--gray-500);
  cursor: default;
}

/* Ayuda plegable: disponible sin ocupar sitio */
.claim-help { padding: 4px 0; }
.claim-help > summary {
  cursor: pointer;
  list-style: none;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--gray-500);
  padding: 4px 0;
}
.claim-help > summary::-webkit-details-marker { display: none; }
.claim-help > summary::after { content: ' +'; font-weight: 700; }
.claim-help[open] > summary::after { content: ' −'; }

/* MEJORA 10 · EL LATIDO DE "¿COMO FUNCIONA?"
   Es la unica ayuda de la pantalla y estaba plegada, quieta, con el aspecto
   de un pie de pagina: nadie la abria. No se le cambia ni el tipo ni el
   tamano ni el color -sigue siendo texto pequeno y discreto- pero respira.
   El primer latido -4 s de ciclo, 3,5 % de recorrido- no se veia: pasaba
   demasiado desapercibido para lo unico que tenia que hacer, que es que
   alguien lo mire. Ahora late cada 3,2 s, sube un 7 % y va del 62 % al 100 %
   de opacidad, o sea que el latido se nota tambien en el contraste y no solo
   en el tamano. Sigue sin tocarsele el tipo, el tamano ni el color.
   Deja de respirar en cuanto se abre: ya ha hecho su trabajo. */
.claim-help > summary {
  /* Seis latidos y para. Antes era `infinite`, y una animacion infinita es
     trabajo infinito: el navegador no puede quedarse quieto NUNCA mientras esa
     pantalla este abierta, y eso se paga en todo lo demas —empezando por lo
     que se nota, que es desplazar la lista—. Seis latidos son veinte segundos:
     si en veinte segundos mirando la pantalla no lo ha visto, no lo va a ver,
     y a partir de ahi solo estorba. */
  animation: ayuda-respira 3.2s ease-in-out 0.8s 6;
  transform-origin: left center;
}
.claim-help[open] > summary { animation: none; }
@keyframes ayuda-respira {
  0%, 48%, 100% { opacity: 0.62; transform: scale(1); }
  64%           { opacity: 1;    transform: scale(1.07); }
  78%           { opacity: 0.82; transform: scale(0.995); }
  88%           { opacity: 0.92; transform: scale(1.02); }
}
@media (prefers-reduced-motion: reduce) {
  .claim-help > summary { animation: none; opacity: 0.9; }
}

/* Ayuda de la pantalla de revisión: qué hacer si la lectura se dejó algo */
.review-help { margin-top: 6px; }
/* Esta ayuda lleva tambien la clase .claim-help, y con ella se llevaba el
   latido de la pantalla de las casillas. Ahi si tiene sentido -es la unica
   ayuda y nadie la abria-; aqui no: en la pantalla de repasar el ticket lo que
   hay que mirar son las cifras, y un texto moviendose al lado se lleva la
   vista justo a donde no hace falta. */
.review-help > summary { animation: none; }
.review-help .rh-body {
  font-family: var(--sans);
  font-size: 0.68rem;
  line-height: 1.5;
  color: var(--gray-500);
  padding: 4px 2px 2px;
  /* El texto trae un salto de línea a propósito antes de "o vuelve atrás";
     sin esto, el \n de textContent se colapsa en un espacio y no se ve. */
  white-space: pre-line;
}

/* Botón de girar sobre la miniatura */
/* Mismo tamaño y peso visual que el botón de quitar, en la esquina opuesta */
.thumb-rot {
  position: absolute;
  left: 2px; bottom: 2px;
  width: 18px; height: 18px;
  display: flex; align-items: center; justify-content: center;
  border: none;
  border-radius: 50%;
  background: rgba(0,0,0,0.65);
  cursor: pointer;
  padding: 0;
}
.thumb-rot svg { width: 11px; height: 11px; fill: white; }
.thumb-rot:disabled { opacity: 0.5; }

.preview-add-hint.warn {
  color: var(--accent);
  font-weight: 700;
}

/* Resumen: alguien que todavía está eligiendo */
.person-row.is-picking { opacity: 0.72; }
.person-tag.picking {
  background: transparent;
  border: 1px solid var(--accent);
  color: var(--accent);
}

@media (prefers-reduced-motion: reduce) {
  .live-dot.saved, .live-person.picking, .unit-pill.just-changed { animation: none; }
  .unit-pill { transition: none; }
}

/* =============================================
   PERSON ROWS (Summary) — names only, no avatars
   ============================================= */

.person-row {
  display: block;
  padding: 10px 0 12px;
  border-bottom: 1px dotted var(--gray-200);
  animation: rowSlideIn 0.4s ease forwards;
  opacity: 0;
  font-family: var(--mono);
}
.person-row:last-child { border-bottom: none; }
@keyframes rowSlideIn {
  from { opacity: 0; transform: translateX(-6px); }
  to   { opacity: 1; transform: translateX(0); }
}
.person-row:nth-child(1) { animation-delay: 0.08s; }
.person-row:nth-child(2) { animation-delay: 0.16s; }
.person-row:nth-child(3) { animation-delay: 0.24s; }
.person-row:nth-child(4) { animation-delay: 0.32s; }
.person-row:nth-child(5) { animation-delay: 0.40s; }
.person-row:nth-child(6) { animation-delay: 0.48s; }

.person-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}

.person-name {
  flex: 1;
  font-weight: 700;
  font-size: 0.92rem;
  min-width: 0;
  color: var(--black);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: flex;
  align-items: center;
  gap: 8px;
}

.person-row .person-tag {
  font-size: 0.54rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* El mismo ámbar que ya usa la app para "esto se comparte/confirma"
     (.unit-pill.shared, .cb-fill) — rojo daba sensación de error, y aquí
     solo dice quién adelantó el dinero. */
  color: #1F1203;
  background: #F59E0B;
  padding: 3px 7px;
  border-radius: 4px;
  white-space: nowrap;
  flex-shrink: 0;
  line-height: 1;
  box-shadow: 0 1px 2px rgba(217,119,6,0.25);
}

.person-row.is-payer .person-name,
.person-row.is-payer .person-amount {
  color: var(--red);
}

.person-amount {
  font-family: var(--mono);
  /* Es LA cifra de la pantalla —lo que paga esa persona— y además se toca
     para copiarla: tiene que ganarle en peso visual al desglose de debajo. */
  font-size: 1.06rem;
  font-weight: 700;
  color: var(--black);
  flex-shrink: 0;
  white-space: nowrap;
}

/* La cifra ahora es un botón: al tocarla copia el importe pelado, listo para
   pegarlo en el banco. Se mantiene EXACTAMENTE con el mismo aspecto que
   tenía como texto —sin fondo, sin borde, sin subrayado— porque no debe
   competir con nada; solo responde al tacto. */
.person-amount {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.person-amount:active {
  opacity: 0.45;
}

/* LAS CIFRAS QUE SE COPIAN, LATIENDO
   Copiar el importe de un toque existe desde hace tiempo y no se ve por
   ninguna parte: son texto, sin borde ni fondo, iguales que las de al lado que
   no hacen nada. Quien no lo sabe no lo descubre. Un latido flojo es la forma
   mas barata de decir "esto se toca" sin meter un boton ni un icono al lado de
   una cifra de dinero, que es donde menos ruido puede haber.
   Ciclo largo -3,4 s- y solo en la escala: el color no se toca, porque el rojo
   de "este paga" significa algo y no puede parpadear. */
.person-amount,
.pantalla-grupo .tr-amount {
  display: inline-block;
  /* Cinco latidos y para, por lo mismo: eran una animacion por cada persona
     de la lista, todas infinitas y todas a la vez. Cinco son diecisiete
     segundos, de sobra para que se vea que las cifras se tocan. */
  animation: cifra-late 3.4s ease-in-out 1.4s 5;
}
@keyframes cifra-late {
  /* Pedido explícito: más grande y evidente que el latido flojo original
     -la gente no lo estaba descubriendo-. Mismo ritmo, más recorrido. */
  0%, 58%, 100% { transform: scale(1); }
  70%           { transform: scale(1.16); }
  81%           { transform: scale(0.97); }
  91%           { transform: scale(1.06); }
}
/* En cuanto copia una, deja de latir: ya sabe que se tocan, y a partir de ahi
   solo seria una cifra de dinero moviendose sin motivo. */
body.ya-copio .person-amount,
body.ya-copio .pantalla-grupo .tr-amount { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .person-amount, .pantalla-grupo .tr-amount { animation: none; }
}

/* "Recordar": solo lo ve quien puso el dinero, y solo con la cuenta cerrada.
   Discreto a propósito —es una acción social, no una alarma— pero con el
   naranja de la marca para que se encuentre. */
.person-remind {
  margin-left: auto;
  margin-right: 10px;
  padding: 3px 10px;
  font-family: inherit;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--orange);
  background: none;
  border: 1px solid var(--orange);
  border-radius: 999px;
  cursor: pointer;
  flex-shrink: 0;
  -webkit-tap-highlight-color: transparent;
}
.person-remind:active {
  background: var(--orange);
  color: #fff;
}

.person-items {
  padding-left: 6px;
  margin-top: 2px;
}
.person-item {
  padding: 2px 0 3px;
  font-size: 0.72rem;
  color: var(--gray-500);
  line-height: 1.4;
}
.person-item .pi-main {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.person-item .pi-name {
  flex: 1;
  min-width: 0;
  word-break: break-word;
}
.person-item .pi-amt {
  /* Un punto por encima del nombre del artículo: en una línea de desglose,
     lo que se busca con la vista es la cifra. El precio por unidad de
     debajo (.pi-detail-der) se queda como está, en voz baja. */
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--gray-700);
  white-space: nowrap;
  flex-shrink: 0;
}
.person-item .pi-detail {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding-left: 10px;
  font-size: 0.58rem;
  color: var(--gray-400);
  font-style: italic;
  line-height: 1.3;
  margin-top: 1px;
}
.person-item .pi-detail-izq {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.person-item .pi-detail-der {
  flex-shrink: 0;
  white-space: nowrap;
  text-align: right;
}
.person-item .shared-with {
  font-size: 0.6rem;
  color: var(--gray-400);
  font-style: italic;
  margin-left: 4px;
}

/* =============================================
   BUTTONS
   ============================================= */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 22px;
  border-radius: var(--radius);
  font-family: var(--sans);
  font-size: 0.9rem;
  font-weight: 700;
  border: none;
  cursor: pointer;
  /* Bajada rápida y lineal (se nota el toque al instante), subida con un
     pelín de rebote (cubic-bezier con overshoot): así el botón se siente
     vivo al soltar, no solo al pulsar. Es el mismo botón para todas las
     confirmaciones de la app -marcar lo tuyo, cerrar, borrar-, así que
     arreglarlo aquí una vez alcanza a todas. */
  transition: transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1),
    background-color 0.15s ease, color 0.15s ease,
    border-color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  letter-spacing: -0.01em;
}
/* La bajada es instantánea -el dedo tiene que notarlo YA-; el rebote al
   soltar lo pone la transición base de .btn, más lenta y con overshoot. */
.btn:active { transform: scale(0.97); transition: transform 0.05s linear; }
@media (prefers-reduced-motion: reduce) {
  .btn, .btn:active { transition-duration: 0.01s; }
}

.btn-dark {
  background: var(--dark);
  color: white;
  box-shadow: var(--shadow-btn);
}
.btn-dark:hover { background: #3F3F46; }
.btn-dark:disabled {
  background: var(--gray-300);
  color: var(--gray-500);
  box-shadow: none;
  cursor: not-allowed;
  transform: none;
}

.btn-blue {
  background: var(--blue);
  color: white;
  box-shadow: 0 4px 14px rgba(37,99,235,0.28);
}
.btn-blue:hover { background: #1D4ED8; }

.btn-outline {
  background: white;
  color: var(--dark);
  border: 1.5px solid var(--gray-200);
}
.btn-outline:hover { background: var(--gray-100); }

.btn-green {
  background: var(--green);
  color: white;
  box-shadow: 0 4px 14px rgba(22,163,74,0.28);
}

.btn-ghost {
  background: transparent;
  color: var(--gray-700);
  border: 1.5px solid var(--gray-200);
}
.btn-ghost:hover { background: var(--gray-100); }

.btn-accent {
  background: var(--accent);
  color: white;
  box-shadow: 0 4px 14px rgba(255,107,53,0.35);
}
.btn-accent:hover { background: #E55B28; }

.btn-full { width: 100%; }
.btn-half { flex: 1; }

.btn svg {
  width: 16px; height: 16px;
  fill: currentColor;
  flex-shrink: 0;
}
.btn-row {
  display: flex;
  gap: 10px;
  padding: 0 16px;
  margin-top: 12px;
}

/* =============================================
   BOTTOM STICKY
   ============================================= */

.bottom-sticky {
  margin-top: auto;
  position: sticky;
  bottom: 0;
  /* Mismo motivo que en .page: 22px fijos no bastan en un iPhone con barra
     de gestos, y este es el botón principal de la pantalla (Compartir
     enlace, Crear grupo...) — es justo el que no puede quedar a medio tapar. */
  padding: 20px 16px calc(22px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(0deg, var(--bg) 62%, rgba(236,234,228,0.95) 86%, transparent 100%);
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 15;
}

/* Extra bottom spacing so ticket never overlaps sticky button */
/* El hueco crece con la barra de gestos: .bottom-sticky ahora es más alto
   ahí, y si esto no crece a la vez, el último gasto de la lista vuelve a
   quedar tapado, justo el fallo que se acaba de arreglar en el botón. */
.has-sticky-bottom { padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px)); }

/* El candado de bloquear edición, junto a "Compartir enlace": menos del
   50% del ancho pero la misma altura, para que se lean como una pareja de
   acciones y no como un botón secundario perdido. */
.footer-row { display: flex; gap: 10px; }
.footer-row .btn { flex: 1 1 60%; }
.btn-toggle-lock {
  flex: 0 0 auto;
  width: 52px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  appearance: none;
  border: 1.5px solid var(--gray-300);
  border-radius: var(--radius);
  background: #fff;
  color: var(--gray-700);
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, transform .12s ease;
  -webkit-tap-highlight-color: transparent;
}
.btn-toggle-lock:active { transform: scale(0.95); }
.btn-toggle-lock svg { width: 20px; height: 20px; }
.btn-toggle-lock .ltl-cerrado { display: none; }
.btn-toggle-lock[aria-pressed="true"] {
  background: var(--dark);
  border-color: var(--dark);
  color: #fff;
}
.btn-toggle-lock[aria-pressed="true"] .ltl-abierto { display: none; }
.btn-toggle-lock[aria-pressed="true"] .ltl-cerrado { display: block; }

/* =============================================
   CAMERA / UPLOAD — with tutorial
   ============================================= */

.upload-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 24px 20px 16px;
  /* El gap se SUMABA a los margenes de la maqueta y la estiraba: donde Alvaro
     habia dejado 26 px salian 44, y el total pasaba de sus 812 a 962. Por eso
     la linea de grupos caia fuera de pantalla. Bajado a 4, los espaciados
     reales vuelven a los suyos y la portada entra donde tenia que entrar. */
  gap: 4px;
}

.upload-brand-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  margin-top: 8px;
}
.upload-brand-hero .logo-mark { font-size: 2rem; }
.upload-brand-hero .logo-text {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.6rem;
  letter-spacing: -0.04em;
  line-height: 1;
}
.upload-brand-hero .logo-text em {
  font-style: italic;
  font-weight: 500;
  color: var(--gray-500);
  letter-spacing: -0.03em;
}
.upload-brand-hero .logo-text strong {
  background: linear-gradient(95deg, var(--black) 0%, var(--accent) 95%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-weight: 800;
}
.upload-brand-hero .brand-tag {
  font-size: 0.8rem;
  color: var(--gray-500);
  font-weight: 500;
  letter-spacing: -0.01em;
}

.upload-btns-row {
  display: flex;
  gap: 18px;
  justify-content: center;
  margin-bottom: 8px;
}
.upload-option {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--sans);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--gray-700);
  padding: 8px 10px;
  transition: all 0.2s;
}
.upload-option-icon {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  background: white;
  border: 2.5px solid var(--dark);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  box-shadow: 0 6px 24px rgba(0,0,0,0.08);
}
.upload-option:hover .upload-option-icon {
  transform: scale(1.08);
  border-color: var(--accent);
  box-shadow: 0 10px 32px rgba(255,107,53,0.15);
}
.upload-option:active .upload-option-icon { transform: scale(0.94); }
.upload-option-icon svg {
  width: 32px; height: 32px;
  fill: var(--dark);
  transition: fill 0.2s;
}
.upload-option:hover .upload-option-icon svg { fill: var(--accent); }
.upload-option:hover span { color: var(--accent); }

/* Legacy compat — keep class for claim.html if used */
.camera-ring { display: none; }

.upload-title {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.25rem;
  color: var(--black);
  text-align: center;
  letter-spacing: -0.03em;
}

.upload-sub {
  font-size: 0.85rem;
  color: var(--gray-500);
  text-align: center;
  line-height: 1.5;
  max-width: 320px;
}

/* Multi-upload thumbnails */
.thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
  justify-content: center;
}
.thumb {
  position: relative;
  width: 60px; height: 60px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--gray-200);
  box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}
.thumb img { width: 100%; height: 100%; object-fit: cover; }
.thumb-rm {
  position: absolute;
  top: 2px; right: 2px;
  width: 18px; height: 18px;
  border-radius: 50%;
  border: none;
  background: rgba(0,0,0,0.65);
  color: white;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
.thumb-add {
  width: 60px; height: 60px;
  border-radius: 10px;
  border: 2px dashed var(--gray-300);
  background: rgba(255,255,255,0.5);
  color: var(--gray-500);
  font-size: 1.3rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.15s;
}
.thumb-add:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* Preview overlay */
.preview-overlay {
  position: fixed;
  inset: 0;
  /* Opaco, no al 88 %: al 88 % se transparentaban la cabecera y la firma por
     detras de las fotos y parecia que habia elementos montados unos sobre
     otros. Esta pantalla existe para mirar UNA foto; detras no va nada. */
  background: #0A0A0C;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: 50;
  animation: fadeIn 0.25s ease;
  padding: 24px;
}
.preview-overlay img {
  max-width: 100%;
  max-height: 55dvh;
  border-radius: var(--radius);
  object-fit: contain;
  box-shadow: 0 16px 48px rgba(0,0,0,0.5);
}

/* LA PANTALLA DE REVISAR LAS FOTOS, REHECHA
   Tenia un fallo de raiz: miniaturas cuadradas de 86 px con
   `object-fit: cover`. Un ticket es alto y estrecho, asi que recortarlo en un
   cuadrado deja ver un trozo del centro y NADA de su forma. Es decir: la
   pantalla cuya unica razon de existir es comprobar que el ticket esta
   derecho hacia imposible ver si estaba derecho.
   Ahora la foto se ve entera (`contain`) sobre un fondo oscuro y en vertical,
   que es la forma del papel. Dos columnas como mucho, y una sola foto ocupa
   el ancho: se trata de MIRARLA, no de tenerlas ordenadas. */
.preview-overlay .thumbs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  justify-content: center;
  align-content: start;
  width: 100%;
  max-width: 420px;
  /* Sin tope a ojo. Antes habia un `max-height: 56dvh` -455 px en un movil de
     812- que cortaba la rejilla mucho antes de que se acabase la pantalla: con
     una sola foto, la foto y el recuadro de "anadir otra" suman 604 px y caben
     de sobra, pero el tope los partia y el "+" quedaba escondido tras un
     scroll que salia de la nada. Encogiendo solo si hace falta (`0 1 auto`) se
     queda con el sitio que de verdad sobra, y el scroll pasa a ser lo que
     tenia que haber sido siempre: el ultimo recurso con muchas fotos. */
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 4px;
  /* Con el alto limitado y las filas automaticas, la rejilla APLASTA las
     primeras filas para que quepa todo en vez de dejar que se desplace: con
     tres fotos, las de arriba perdian 47 px de alto y con ellos la proporcion
     del papel, que es lo unico que esta pantalla tiene que ensenar. Con
     `max-content` cada fila conserva su tamano y lo que sobra se desplaza. */
  grid-auto-rows: max-content;
}
/* Y dentro de la ficha, ni la foto ni el boton ceden alto: sin esto vuelven a
   encogerse en cuanto algo de fuera aprieta. */
.preview-overlay .thumb-foto,
.preview-overlay .thumb-rot { flex-shrink: 0; }
/* Una sola foto: a pantalla completa, sin compartir fila con nada. */
.preview-overlay .thumbs.una { grid-template-columns: minmax(0, 1fr); max-width: 300px; }
/* En pantallas cortas -un iPhone SE mide 667- tres fotos y el aviso rojo no
   caben ni a dos columnas, y volvia el scroll. Ahi, y solo ahi, la rejilla se
   estrecha en proporcion al alto que haya: menos ancho de columna es menos
   alto de ficha, que es lo que sobraba. Por encima de 740 px no se aplica,
   asi que en un movil normal no se toca nada. */
@media (max-height: 740px) {
  .preview-overlay .thumbs { max-width: min(420px, calc(100dvh - 410px)); }
  /* Con una sola foto, ella y el "+" van uno DEBAJO del otro, asi que ahi hay
     que apretar mas que cuando comparten fila. */
  .preview-overlay .thumbs.una { max-width: min(300px, calc(100dvh - 470px)); }
  /* El selector lleva `.thumbs` a proposito: sin el pierde contra la regla de
     mas abajo, que tiene la misma fuerza y va despues en el fichero. Los
     150 px del recuadro son lo que sobra cuando va debajo de la foto. */
  .preview-overlay .thumbs .thumb-add { min-height: 110px; }
}

/* De cuatro fotos para arriba, tres columnas. A dos no caben en la pantalla y
   aparecia el scroll; a tres siempre son dos filas como mucho, con seis
   incluidas, y se ven todas de un vistazo, que es a lo que viene esta
   pantalla. Es el unico caso en que se toca el tamano, y es porque no hay
   alternativa: a dos columnas, seis fotos miden 990 px. */
.preview-overlay .thumbs.muchas { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* La ficha es una columna: la foto arriba y el boton de girar DEBAJO, como
   una fila de verdad. Antes el boton iba flotando encima de la imagen, y como
   es casi blanco, sobre un ticket blanco desaparecia por el centro: solo se
   veian sus dos extremos contra el fondo negro y parecia que el papel partia
   el boton en dos. Encima tapaba los ultimos 38 px de la foto, que es
   exactamente donde un ticket lleva el total. Ahora no se solapa nada. */
.preview-overlay .thumb {
  width: 100%;
  height: auto;
  aspect-ratio: auto;
  border-radius: 14px;
  display: flex;
  flex-direction: column;
  background: #0C0C0E;
  border: 1.5px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
}
/* El recuadro de "anadir otra" se estira hasta la altura de su fila cuando
   comparte con una foto -si no, hereda los 60 px de la regla base y queda como
   una pastilla suelta al lado de algo que mide el triple-, y cuando le toca
   fila propia el minimo evita que se quede en una rendija de 36 px. */
.preview-overlay .thumb-add {
  width: 100%;
  height: auto;
  min-height: 150px;
  align-self: stretch;
  border-radius: 14px;
  font-size: 1.9rem;
}
/* El hueco de la foto: es el que lleva la proporcion de papel. */
.preview-overlay .thumb-foto {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 4;
  overflow: hidden;
}
/* `contain`, no `cover`: se ve el ticket entero y por tanto su orientacion. */
.preview-overlay .thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* La regla general `.preview-overlay img` limita a 55dvh, pensada para una
     foto a pantalla completa. Aqui la foto ya vive dentro de su hueco. */
  max-height: none;
  border-radius: 0;
  box-shadow: none;
}

/* Tumbada: se dice en la propia foto, no solo en un texto debajo. */
.preview-overlay .thumb.tumbada {
  border-color: var(--red);
  box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.28), 0 10px 30px rgba(0, 0, 0, 0.45);
}

/* GIRAR: era un circulo de 18 px con un icono de 11. Imposible de acertar con
   el pulgar, y es la accion que hay que hacer justo cuando algo va mal. Ahora
   es una barra a lo ancho de la foto, con su palabra. */
.preview-overlay .thumb-rot {
  position: static;
  width: 100%; height: 42px;
  border-radius: 0 0 12px 12px;
  background: rgba(255, 255, 255, 0.92);
  color: #18181B;
  gap: 7px;
  font-family: var(--mono);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  transition: transform 0.12s ease, background 0.15s ease;
}
.preview-overlay .thumb-rot svg { width: 15px; height: 15px; fill: #18181B; }
.preview-overlay .thumb-rot:active { transform: scale(0.96); }
/* En la que esta tumbada, el boton se pinta de rojo: es el unico sitio donde
   se puede arreglar y tiene que verse desde el otro lado de la mesa. */
.preview-overlay .thumb.tumbada .thumb-rot {
  background: var(--red);
  color: #fff;
}
.preview-overlay .thumb.tumbada .thumb-rot svg { fill: #fff; }
.preview-overlay .thumb-rm { top: 7px; right: 7px; width: 26px; height: 26px; font-size: 15px; }

/* El aviso de que no se puede escanear asi. */
.preview-aviso {
  display: none;
  align-items: flex-start;
  gap: 9px;
  max-width: 420px;
  margin-top: 12px;
  padding: 11px 13px;
  border-radius: 10px;
  border-left: 3px solid var(--red);
  background: rgba(220, 38, 38, 0.14);
  color: #FEE2E2;
  font-family: var(--sans);
  font-size: 0.72rem;
  line-height: 1.45;
}
.preview-aviso.on { display: flex; }
.preview-aviso svg { width: 16px; height: 16px; fill: var(--red); flex-shrink: 0; margin-top: 1px; }

/* Escanear, bloqueado mientras haya una foto tumbada. */
.btn-blue:disabled { opacity: 0.4; cursor: not-allowed; }
.preview-overlay .thumb-add {
  background: rgba(255,255,255,0.08);
  border: 2px dashed rgba(255,255,255,0.4);
  color: rgba(255,255,255,0.7);
  font-size: 1.7rem;
}
.preview-overlay .thumb-add:hover {
  background: rgba(255,255,255,0.15);
  border-color: white;
  color: white;
}

.preview-add-hint {
  color: rgba(255,255,255,0.7);
  font-size: 0.8rem;
  margin-top: 14px;
  text-align: center;
  letter-spacing: 0.01em;
}
.preview-btns {
  display: flex;
  gap: 12px;
  margin-top: 20px;
  width: 100%;
  max-width: 360px;
}
.preview-btns .btn { flex: 1; }

/* Dark-mode retake button */
.btn-retake {
  background: rgba(255,255,255,0.12);
  color: white;
  border: 1.5px solid rgba(255,255,255,0.35);
}
.btn-retake:hover { background: rgba(255,255,255,0.22); }

/* =============================================
   CLAIM ROW — counter design (replaces check)
   ============================================= */

.claim-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 8px;
  margin: 0 -8px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: all 0.15s;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  border-bottom: 1px solid var(--gray-100);
  position: relative;
}
.claim-row:last-child { border-bottom: none; }
.claim-row:active { transform: scale(0.985); }

.claim-row.picked {
  background: #F0FDF4;
}

.claim-counter {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  border: 2px solid var(--gray-300);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
  background: white;
  position: relative;
}

.claim-row.picked .claim-counter {
  background: var(--green);
  border-color: var(--green);
}

.counter-check {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: scale(0.3) rotate(-45deg);
  transition: all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.counter-check svg { width: 14px; height: 14px; fill: white; }
.claim-row.picked .counter-check {
  opacity: 1;
  transform: scale(1) rotate(0);
}

.counter-num {
  font-family: var(--display);
  font-weight: 800;
  font-size: 0.88rem;
  color: white;
  position: absolute;
  bottom: 1px;
  right: 3px;
  background: rgba(0,0,0,0.2);
  min-width: 14px;
  height: 14px;
  border-radius: 7px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 3px;
  font-size: 0.6rem;
  line-height: 1;
  opacity: 0;
  transform: scale(0.5);
  transition: all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.claim-row.picked .counter-num {
  opacity: 1;
  transform: scale(1);
}

/* Reset (X) button — only visible when picked */
.claim-reset {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--gray-400);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
}
.claim-row.picked .claim-reset {
  opacity: 1;
  pointer-events: auto;
}
.claim-reset:hover { color: var(--red); background: var(--red-light); }
.claim-reset svg { width: 13px; height: 13px; fill: currentColor; }

.claim-info {
  flex: 1;
  min-width: 0;
}
.claim-name {
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 400;
  word-break: break-word;
  line-height: 1.3;
}
.claim-detail {
  font-family: var(--mono);
  font-size: 0.62rem;
  color: var(--gray-400);
  margin-top: 2px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.claim-shared-tag {
  font-size: 0.54rem;
  background: var(--blue-light);
  color: var(--blue);
  padding: 1px 5px;
  border-radius: 3px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.claim-price {
  font-family: var(--mono);
  font-weight: 700;
  font-size: 0.82rem;
  flex-shrink: 0;
  white-space: nowrap;
}

/* =============================================
   NAME INPUT FIELD
   ============================================= */

.payer-field,
.name-field { position: relative; margin-bottom: 4px; }
.payer-field input,
.payer-field label {
  font-family: var(--mono) !important;
}
.payer-field {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 4px 0;
  gap: 10px;
}
.payer-field label {
  font-size: 0.6rem;
  font-weight: 700;
  color: var(--gray-500);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  flex-shrink: 0;
}
.payer-field input {
  flex: 1;
  border: none;
  background: transparent;
  padding: 2px 6px;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--red);
  text-align: right;
  outline: none;
  border-bottom: 1.5px dashed var(--gray-300);
  border-radius: 0;
  transition: border-color 0.15s;
}
.payer-field input:focus { border-bottom-color: var(--red); }
.payer-field input::placeholder { color: var(--gray-300); font-weight: 400; }

.name-field { position: relative; margin-bottom: 12px; }
.name-field input {
  width: 100%;
  font-family: var(--sans);
  font-size: 0.95rem;
  font-weight: 600;
  padding: 13px 16px;
  border: 2px solid var(--gray-200);
  border-radius: var(--radius-sm);
  outline: none;
  background: white;
  transition: all 0.2s;
  color: var(--black);
}
.name-field input:focus {
  border-color: var(--blue);
  box-shadow: 0 0 0 4px rgba(37,99,235,0.08);
}
.name-field label {
  position: absolute;
  top: -7px;
  left: 12px;
  font-size: 0.6rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--gray-500);
  background: white;
  padding: 0 5px;
}

/* =============================================
   SHARE LINK BOX — with copy button inside
   ============================================= */

/* Vive dentro de .bottom-sticky, así que no lleva margen propio: lo que la
   separa del borde es el padding de la barra. */
.share-section { margin-top: 0; }
/* La tarjeta y el botón naranja FLOTAN sobre el ticket, cada uno por su
   cuenta, igual que flotaba el botón negro que ocupaba antes ese sitio.
   Nada de panel opaco: encuadrarlos en una caja recortaba el ticket en seco
   por la mitad. Cada uno se lee solo porque tiene su propio fondo (la
   tarjeta es blanca, el botón naranja macizo) y su propia sombra; lo único
   que pone el contenedor es un fundido corto abajo del todo, para que lo
   que se desplaza por detrás no llegue al borde de la pantalla a pelo.
   La clase la pone el JS al abrirlo. */
.bottom-sticky.con-compartir {
  background: linear-gradient(0deg,
    var(--bg) 14%, rgba(236, 234, 228, 0.55) 34%, transparent 62%);
}
/* Flotando sobre el ticket necesita despegarse más que cuando vivía dentro
   del flujo: la sombra es lo que dice que está por encima, no dentro. */
.bottom-sticky.con-compartir .share-box {
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.13), 0 2px 8px rgba(0, 0, 0, 0.06);
}
.share-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 14px;
}

.share-box {
  background: white;
  border-radius: var(--radius-sm);
  padding: 18px 16px;
  border: 1.5px dashed var(--gray-300);
  box-shadow: 0 2px 10px rgba(0,0,0,0.04);
}
.share-box .sb-title {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1rem;
  text-align: center;
  letter-spacing: -0.02em;
}
.share-box .sb-hint {
  font-size: 0.82rem;
  color: var(--gray-500);
  text-align: center;
  margin-top: 4px;
  margin-bottom: 14px;
  line-height: 1.4;
}

/* AQUI ESTABA .share-link, el recuadro con el enlace escrito. Retirado: con
   "copiar enlace" y "compartir" justo debajo, nadie lo iba a teclear a mano, y
   ocupaba tres lineas de texto ilegible encima de los botones que si se usan.
   El enlace vive ahora en una variable de ticket.js. */

.share-btn-row {
  display: flex;
  gap: 10px;
  margin-top: 12px;
}
.share-btn-row .btn { flex: 1; font-size: 0.82rem; padding: 12px; }

/* =============================================
   PROCESSING / LOADING
   ============================================= */

/* La pantalla de carga ocupa lo que queda de pantalla bajo la cabecera. Antes
   media 230 px y todo -incluida la firma- quedaba flotando a media altura, en
   mitad de un movil de 812. Ahora el contenido se centra y la firma se va
   abajo del todo, que es su sitio. */
.processing {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding: 60px 20px 46px;
  min-height: calc(100dvh - 66px);
  position: relative;
  animation: fadeIn 0.3s ease;
}
/* Un consejo de los de la pantalla de carga de los videojuegos: en letra de
   ticket, flojita, y sin robarle protagonismo al "Imprimiendo ticket". Ancho
   corto a proposito -no es un parrafo, es una frase que se lee de un golpe-. */
.loader-tip {
  max-width: 270px;
  min-height: 2.6em;
  text-align: center;
  font-family: var(--mono);
  font-size: 0.7rem;
  line-height: 1.45;
  color: var(--gray-500);
  opacity: 0;
  transition: opacity 0.5s ease;
}
.loader-tip.visible { opacity: 0.72; }
/* La firma, abajo del todo de la PANTALLA. Con `absolute` quedaba atada a la
   caja de .processing, que acaba donde acaba su `min-height` y no donde acaba
   el movil: se veia flotando a media altura. `fixed` la ata a la pantalla. El
   `env()` la aparta de la barra de gestos del iPhone, que si no se la come. */
.proc-firma {
  position: fixed;
  left: 0; right: 0;
  bottom: calc(4px + env(safe-area-inset-bottom, 0px));
  padding: 0;
  z-index: 3;
}
/* Mientras se escanea, la firma de la portada estorba: la de abajo ya esta. */
body.escaneando .page > .easter-egg:not(.proc-firma) { display: none; }
.loader-printer {
  width: 60px;
  height: 72px;
  position: relative;
}
.loader-printer .lp-slot {
  width: 52px;
  height: 16px;
  background: var(--printer-2);
  border-radius: 8px 8px 0 0;
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
.loader-printer .lp-paper {
  width: 40px;
  height: 52px;
  background: var(--paper);
  border-radius: 0 0 2px 2px;
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  animation: paperBob 1.4s ease-in-out infinite;
}
.loader-printer .lp-paper::after {
  content: '';
  position: absolute;
  top: 10px; left: 6px; right: 6px;
  height: 1.5px;
  background: var(--gray-200);
  border-radius: 1px;
  box-shadow: 0 8px 0 var(--gray-200), 0 16px 0 var(--gray-200), 0 24px 0 var(--gray-200);
}
@keyframes paperBob {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%      { transform: translateX(-50%) translateY(-5px); }
}
.loader-text {
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--black);
}
.dot-pulse::after {
  content: '';
  animation: dotAnim 1.5s steps(4) infinite;
}
@keyframes dotAnim {
  0%  { content: ''; }
  25% { content: '.'; }
  50% { content: '..'; }
  75% { content: '...'; }
}

/* =============================================
   CONFETTI
   ============================================= */

.confetti-wrap {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 200;
  overflow: hidden;
}
.confetti-bit {
  position: absolute;
  top: -10px;
  animation: confDrop 3.5s ease-in forwards;
}
@keyframes confDrop {
  0%   { transform: translateY(0) rotate(0deg) scale(1); opacity: 1; }
  100% { transform: translateY(110vh) rotate(720deg) scale(0.4); opacity: 0; }
}

/* =============================================
   SHARE IMAGE CANVAS
   ============================================= */

.share-img-wrap {
  margin: 8px 16px 12px;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-ticket);
}
.share-img-wrap canvas { width: 100%; display: block; }

/* =============================================
   UTILITIES
   ============================================= */

.hidden { display: none !important; }
.text-center { text-align: center; }
.text-mono { font-family: var(--mono); }
.text-gray { color: var(--gray-500); }
.text-sm { font-size: 0.82rem; }
.text-xs { font-size: 0.68rem; }
.fw-700 { font-weight: 700; }
.fw-800 { font-weight: 800; }
.mb-4  { margin-bottom: 4px; }
.mb-8  { margin-bottom: 8px; }
.mb-12 { margin-bottom: 12px; }
.mb-16 { margin-bottom: 16px; }
.mt-4  { margin-top: 4px; }
.mt-8  { margin-top: 8px; }
.mt-12 { margin-top: 12px; }
.mt-16 { margin-top: 16px; }
.px-16 { padding-left: 16px; padding-right: 16px; }
.gap-8 { gap: 8px; }

input[type="file"] { display: none; }

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.home-indicator {
  display: none;
}

.toast {
  position: fixed;
  /* Por encima de la barra fija de abajo: con 32px pelados, un aviso salía
     medio escondido detrás del botón principal. La altura por defecto es la
     de la barra con un solo botón; cuando crece (al abrir compartir) el JS
     actualiza --barra-alto con la medida real. */
  bottom: calc(var(--barra-alto, 96px) + 14px + env(safe-area-inset-bottom, 0px));
  left: 50%;
  transform: translateX(-50%);
  background: var(--dark);
  color: white;
  padding: 13px 20px;
  border-radius: 14px;
  font-size: 0.88rem;
  font-weight: 600;
  box-shadow: 0 8px 32px rgba(0,0,0,0.3);
  z-index: 100;
  animation: fadeIn 0.3s ease;
  /* Antes iba con `white-space: nowrap`: un aviso largo -"Bloqueado, nadie
     puede cerrarlo..."- se escribía en una sola línea infinita que se salía
     por los dos lados de la pantalla y no se podía leer entero. */
  max-width: min(360px, calc(100vw - 32px));
  text-align: center;
  line-height: 1.35;
}

::-webkit-scrollbar { width: 3px; }
::-webkit-scrollbar-thumb { background: var(--gray-300); border-radius: 2px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

@media (min-width: 500px) {
  .page { box-shadow: 0 0 80px rgba(0,0,0,0.06); }
}

/* =========================================================
   Participants field in ticket.html — matches payer-field
   ========================================================= */
.participants-field {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 4px 0;
  gap: 10px;
  margin-bottom: 4px;
}
.participants-field label {
  font-family: var(--mono);
  font-size: 0.6rem;
  font-weight: 700;
  color: var(--gray-500);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  flex-shrink: 0;
}
.participants-field input {
  flex: 1;
  max-width: 80px;
  border: none;
  background: transparent;
  padding: 2px 6px;
  font-family: var(--mono);
  font-size: 0.95rem;
  font-weight: 800;
  color: var(--black);
  text-align: right;
  outline: none;
  border-bottom: 1.5px dashed var(--gray-300);
  border-radius: 0;
  transition: border-color 0.15s;
  -moz-appearance: textfield;
}
.participants-field input::-webkit-outer-spin-button,
.participants-field input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.participants-field input:focus { border-bottom-color: var(--black); }
.participants-field input::placeholder { color: var(--gray-300); font-weight: 400; }

/* =========================================================
   Participants progress (summary.html)
   ========================================================= */
.participants-progress {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 2px;
  font-family: var(--mono);
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gray-500);
  border-bottom: 1px dotted var(--gray-200);
  margin-bottom: 6px;
}
.participants-progress .pp-label { color: var(--gray-700); }
.participants-progress .pp-count {
  font-size: 0.85rem;
  letter-spacing: 0;
  color: var(--black);
  font-weight: 800;
}
.participants-progress .pp-state {
  font-size: 0.58rem;
  color: var(--gray-500);
  text-align: right;
}
.participants-progress.complete .pp-count { color: #16A34A; }
.participants-progress.complete .pp-state { color: #16A34A; }

/* Close button disabled look */
#closeBtn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  filter: grayscale(0.5);
}

/* =========================================================
   Claim v2 — per-unit pills
   ========================================================= */
/* AQUI ESTUVO `content-visibility: auto`, Y SE RETIRO. Ahorraba un 53 % del
   coste de recalcular el diseno -medido- pero a cambio la pagina se dibujaba a
   trozos: se veia el principio, un atason, y de golpe el ticket entero. Un
   numero mejor no vale una pantalla que se monta a pedazos delante de quien la
   mira. Si alguien vuelve a ponerlo, que sepa que trae eso.

   Los 7 px de relleno con su margen negativo se quedan, que no cuestan nada y
   hacen falta igual: la casilla, al pulsarse, crece un 16 % y gira 9 grados
   -necesita 6,7 px- y solo tenia 2. Nada se mueve de sitio: 9 - 7 son los 2 de
   antes, y la linea de puntos va en un pseudoelemento insetado para que no se
   estire con la caja. */
.claim-row-v2 {
  padding: 10px 9px 12px;
  margin: 0 -7px;
  position: relative;
  animation: claim-in 0.28s both;
}
/* La linea de puntos va en un pseudoelemento y no en el borde de la fila,
   porque el borde se habria estirado esos 14 px y las separaciones habrian
   quedado mas anchas que el texto de encima. Asi se queda exactamente donde
   estaba. */
.claim-row-v2::after {
  content: '';
  position: absolute;
  left: 7px; right: 7px; bottom: 0;
  border-bottom: 1px dotted var(--gray-200);
}
.claim-row-v2:last-child::after { display: none; }
.ci-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 8px;
}
.ci-name {
  font-family: var(--mono);
  font-weight: 700;
  font-size: 0.78rem;
  color: var(--black);
  flex: 1;
  word-break: break-word;
  line-height: 1.25;
}
.ci-price {
  font-family: var(--mono);
  font-size: 0.65rem;
  font-weight: 500;
  color: var(--gray-500);
  white-space: nowrap;
  letter-spacing: 0.02em;
}
.ci-units {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: flex-start;
}
.unit-pill {
  appearance: none;
  border: 1.5px dashed var(--gray-300);
  background: white;
  border-radius: 10px;
  padding: 6px 8px 7px;
  min-width: 42px;
  /* Sin marcarlo, el contenido (número + precio en dos líneas) se queda
     por debajo de 44px de alto — y esto se toca decenas de veces por
     ticket, con prisa y sin cuenta de usuario que perdone un toque fallado.
     45, no 44 exactos: el borde de 1,5px redondea el alto real a 43. */
  min-height: 45px;
  max-width: 140px;
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 800;
  color: var(--gray-500);
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s, transform 0.1s;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  line-height: 1.1;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.unit-pill:active { transform: scale(0.95); }
/* La píldora vacía tiene que seguir ocupando sitio y pareciendo "rellenable".
   Sin el número dentro, el alto lo fija esta altura mínima, no el contenido. */
.unit-pill {
  position: relative;
  min-height: 34px;
}

/* MAS ANCHAS SEGUN LO QUE CUESTE LA UNIDAD.
   Al marcar, el precio asoma dentro de la casilla, y en una de 42 px un
   "129,90" no cabe: habia que encogerlo tanto que se leia con lupa. Asi que la
   casilla crece con las cifras, y SOLO a lo ancho —el alto se queda en 34 px
   para que las filas sigan cuadrando entre si—.
   A partir de cinco cifras no se hace nada: un articulo suelto de mas de
   10.000 no existe en un ticket, y reservar sitio para el estropearia el resto.
   El alto no se toca; el ancho sube lo justo para que la cifra entre a su
   tamano, sin que la casilla parezca otra cosa. */
.unit-pill.tres-cifras  { min-width: 56px; }
.unit-pill.cuatro-cifras { min-width: 72px; }

/* MEJORA 6 · LA CIFRA EN EL BOTON
   El total vive donde esta la mano y donde acaba el gesto: a la izquierda de
   "Confirmar", subiendo conforme marcas. Antes habia una etiqueta naranja por
   linea con el subtotal de ESE articulo, que es justo el numero que nadie
   necesita; el que se quiere saber es cuanto llevas en total.
   El brinco es de 140 ms y sin rebote: confirma que la cifra ha cambiado, no
   pide atencion. */
.btn-confirmar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  /* Los dos son para el relleno de mantener pulsado: el circulo crece desde
     donde esta el dedo y el boton lo recorta con su propia forma. */
  position: relative;
  overflow: hidden;
  /* Y estos, por iOS: un dedo quieto medio segundo encima de un texto saca la
     lupa y el menu de copiar, que es justo lo que NO puede pasar mientras se
     mantiene pulsado para confirmar. */
  -webkit-touch-callout: none;
  user-select: none;
  -webkit-user-select: none;
}

/* EL ACUSE DE RECIBO DEL TOQUE.
   Aqui estuvo el gesto de mantener pulsado: circulo creciendo, temblor,
   vibracion en rampa. La gente lo rechazo —no es intuitivo, y un boton que no
   responde al primer toque parece roto, no seguro— asi que fuera.

   Del ambar se queda el circulo, pero con otro papel: ya no mide nada ni marca
   ningun progreso. Sale del punto que se ha tocado, se abre en 260 ms y ahi se
   queda mientras la peticion viaja. Es la respuesta al toque, no una espera.

   El ambar es el de las casillas compartidas y eso sigue teniendo sentido: es
   el color de "esto es de varios", y confirmar es cuando tu parte pasa a
   serlo. */
.cb-fill {
  position: absolute;
  left: 0; top: 0;
  width: var(--cb-d, 0px);
  height: var(--cb-d, 0px);
  margin-left: calc(var(--cb-x, 50%) - var(--cb-d, 0px) / 2);
  margin-top: calc(var(--cb-y, 50%) - var(--cb-d, 0px) / 2);
  border-radius: 50%;
  background: radial-gradient(circle, #EA580C 0%, #F2760A 42%, #F59E0B 100%);
  transform: scale(0);
  pointer-events: none;
  opacity: 0;
}
.btn-confirmar.confirmado .cb-fill {
  opacity: 1;
  animation: cb-llenar 260ms cubic-bezier(0.22, 0.75, 0.3, 1) forwards;
}
@keyframes cb-llenar {
  from { transform: scale(0.06); }
  to   { transform: scale(1); }
}
/* El texto y la cifra, por encima del relleno. Y con una sombra minima cuando
   se llena: el blanco sobre ambar se lee peor que sobre negro. */
.btn-confirmar .cb-txt,
.btn-confirmar .cb-total { position: relative; z-index: 1; }
.btn-confirmar.confirmado .cb-txt { text-shadow: 0 1px 2px rgba(0, 0, 0, 0.42); }

/* Mientras viaja al servidor. Solo la opacidad del texto, que es un elemento
   pequeno: no cuesta repintado y evita que el boton parezca colgado. */
.btn-confirmar.enviando .cb-txt {
  animation: cb-enviando 1s ease-in-out infinite;
}
@keyframes cb-enviando {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}

/* Quien pide menos movimiento no quiere ni el circulo abriendose ni el texto
   respirando: se queda el boton lleno de ambar, que es la informacion. */
@media (prefers-reduced-motion: reduce) {
  .btn-confirmar.confirmado .cb-fill { animation: none; transform: scale(1); }
  .btn-confirmar.enviando .cb-txt { animation: none; }
}
.cb-total {
  font-family: var(--mono);
  font-weight: 800;
  font-size: 0.86rem;
  letter-spacing: -0.02em;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.16);
  opacity: 0;
  max-width: 0;
  overflow: hidden;
  white-space: nowrap;
  transition: opacity 0.18s ease, max-width 0.24s ease, padding 0.2s ease;
}
.cb-total.on { opacity: 1; max-width: 120px; }
/* La cifra no cambia sin mas: SALTA. Es el numero que la persona esta
   mirando mientras marca -es literalmente lo que va a pagar- asi que se
   permite mas gesto que en ningun otro sitio de la app: sube de golpe,
   se pasa de largo y vuelve. 480 ms. */
.cb-total.sube { animation: cb-sube 0.48s cubic-bezier(0.26, 1.6, 0.4, 1); }
/* El texto del boton. Sin cifra va centrado el solo; con cifra, los dos
   quedan centrados como un bloque. */
.cb-txt { white-space: nowrap; }
@keyframes cb-sube {
  0%   { transform: translateY(14px) scale(0.62) rotate(-5deg); opacity: 0; }
  34%  { transform: translateY(-6px) scale(1.28) rotate(3deg);  opacity: 1; }
  56%  { transform: translateY(2px)  scale(0.92) rotate(-1.5deg); }
  76%  { transform: translateY(-1px) scale(1.07) rotate(0.5deg); }
  100% { transform: none; }
}
.btn-confirmar:disabled .cb-total { max-width: 0; padding: 3px 0; opacity: 0; }

/* MEJORA 7 · LA CASILLA ACUSA EL TOQUE
   Marcar y desmarcar daban exactamente igual por fuera. Ahora la casilla
   acusa el gesto en su propia forma: al marcar cae de canto y se asienta con
   dos rebotes -como un sello al apoyarse-, al desmarcar se despega girando al
   reves. La primera version duraba 180 ms y giraba 4 grados: Alvaro no la veia
   siquiera. Subida a 460 ms y 9 grados, que es donde se nota sin marear. */
.unit-pill.marcada { animation: pill-sella 0.46s cubic-bezier(0.28, 1.5, 0.4, 1); }
.unit-pill.desmarcada { animation: pill-suelta 0.36s cubic-bezier(0.3, 1.4, 0.45, 1); }
/* El sello: cae de canto, se apoya con un golpe seco y se endereza. Nueve
   grados de giro y dos rebotes antes de asentar; sea cual sea el recorrido,
   siempre vuelve a cero: una casilla no se queda torcida. */
@keyframes pill-sella {
  0%   { transform: rotate(-9deg) scale(0.74); }
  30%  { transform: rotate(5deg)  scale(1.16); }
  52%  { transform: rotate(-3deg) scale(0.96); }
  72%  { transform: rotate(1.4deg) scale(1.04); }
  88%  { transform: rotate(-0.5deg) scale(0.99); }
  100% { transform: none; }
}
/* Al soltar, el giro va al reves: se despega. */
@keyframes pill-suelta {
  0%   { transform: rotate(6deg) scale(0.82); }
  45%  { transform: rotate(-3deg) scale(1.06); }
  75%  { transform: rotate(1deg) scale(0.98); }
  100% { transform: none; }
}

/* MEJORA 8 · EL BRILLO DE LO YA MARCADO
   Una casilla tuya es negra maciza y se leia plana. Un brillo diagonal muy
   tenue -blanco al 9%, de esquina a esquina- le da un plano de luz y la
   separa del fondo sin añadir ni un color nuevo ni un borde mas. Solo en las
   tuyas: es el estado que interesa distinguir de un vistazo. */
/* MEJORA 4 · EL TIC EN HUECO
   La casilla vacía no decía qué se esperaba de ella: era un rectángulo con
   borde discontinuo y nada dentro. Ahora lleva el mismo visto que va a
   quedarse al marcarla, pero en hueco -al 7%, casi imperceptible-. Se lee
   como un renglón por rellenar, no como un adorno: enseña de antemano cuál
   es el resultado de tocarla, y al marcar, el visto no aparece de la nada,
   se enciende donde ya estaba. */
.unit-pill::before {
  content: "";
  position: absolute;
  width: 15px;
  height: 15px;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  background: currentColor;
  opacity: 0.13;
  pointer-events: none;
  transition: opacity 0.18s ease;
  -webkit-mask: var(--tic-mask) center / contain no-repeat;
  mask: var(--tic-mask) center / contain no-repeat;
}
/* En cuanto la casilla tiene dueño -tuya, de otro o compartida- el tic en
   hueco sobra: ya hay un visto o un nombre de verdad ocupando ese sitio. */
.unit-pill.mine::before,
.unit-pill.theirs::before,
.unit-pill.shared::before { opacity: 0; }
:root {
  --tic-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z'/%3E%3C/svg%3E");
}
/* Al pasar el dedo o el ratón, la casilla se despierta: el borde se tiñe del
   naranja de la marca. Es la señal de "esto se pulsa" que antes daba el
   número. */
.unit-pill:not(.mine):not(.theirs):not(.shared):hover {
  border-color: var(--orange);
  background: #FFF8F4;
}

/* EL DESTELLO DEL PRECIO.
   Al marcar una unidad, su precio surge grande en el centro de la píldora y
   se desvanece enseguida, dejando paso al visto o al nombre. Dura poco a
   propósito: no es información permanente —el precio ya está en la cabecera
   de la línea— sino la respuesta a "¿qué acabo de hacer?".
   Va en currentColor, así que se lee sobre el negro de "mío" y sobre el
   ámbar de "compartido" sin tener que saber cuál es. */
.up-price {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: 0.9rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: currentColor;
  pointer-events: none;
  /* Nunca parte la cifra en dos lineas: un precio a medias no se entiende. El
     tamano lo ajusta el JS para que quepa (ver `ajustarPrecio` en claim.js). */
  white-space: nowrap;
  animation: up-price-pop 0.66s cubic-bezier(0.2, 0.9, 0.25, 1) forwards;
}
/* MEJORA 5 · EL PRECIO SE CONVIERTE EN VISTO
   Antes salian a la vez el precio, el simbolo del euro y el visto, los tres
   encima del otro: no se entendia que estaba pasando, parecia un parpadeo.

   Ahora es UN gesto en dos tiempos, no tres cosas simultaneas. Primero
   asoma el precio -solo la cifra, sin el euro: el euro ya esta en la
   cabecera de la linea y aqui solo estorba-, se encoge hacia el centro, y
   justo cuando se va, el visto crece desde ese mismo punto. Se lee como que
   el precio SE TRANSFORMA en el visto, que es exactamente lo que ha pasado:
   ese importe ya es tuyo. */
@keyframes up-price-pop {
  0%   { opacity: 0; transform: scale(0.42); }
  22%  { opacity: 1; transform: scale(1.16); }
  46%  { opacity: 1; transform: scale(1); }
  76%  { opacity: 0; transform: scale(0.52); }
  100% { opacity: 0; transform: scale(0.52); }
}
/* El visto entra cuando el precio ya se esta yendo, no a la vez. El retardo
   es lo que convierte dos animaciones en un solo gesto. */
.unit-pill.morphing .up-check {
  animation: up-check-nace 0.36s cubic-bezier(0.2, 1.3, 0.4, 1) 0.3s both;
}
@keyframes up-check-nace {
  from { opacity: 0; transform: scale(0.35); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .up-price { animation: up-price-fade 0.5s linear forwards; }
  @keyframes up-price-fade { 0%, 60% { opacity: 1; } 100% { opacity: 0; } }
  .unit-pill.morphing .up-check { animation: none; }
  .unit-pill.marcada, .unit-pill.desmarcada { animation: none; }
  .cb-total.sube { animation: none; }
}



/* La pista, una sola vez y bajo el primer artículo con varias unidades. */
.ci-hint {
  margin-top: 7px;
  font-family: var(--mono);
  font-size: 0.6rem;
  font-weight: 500;
  color: var(--gray-500);
  letter-spacing: 0.01em;
}


.unit-pill .up-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  min-height: 0;
  width: 100%;
}
.unit-pill .up-body:empty { display: none; }
.unit-pill .up-claim {
  font-family: var(--mono);
  font-size: 0.54rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.15;
  text-align: center;
  word-break: break-word;
  text-transform: lowercase;
  max-width: 100%;
}
.unit-pill .up-claim + .up-claim { margin-top: 1px; }
.unit-pill .up-check {
  width: 14px;
  height: 14px;
  fill: currentColor;
  flex-shrink: 0;
}
/* State: mine (claimed by me, alone) */
/* MEJORA 8 · EL BRILLO DE LO YA MARCADO
   Va en la MISMA declaracion que el color, no en una regla aparte: la forma
   abreviada `background:` reinicia `background-image`, asi que un brillo
   declarado por separado mas arriba lo borraba esta linea sin avisar. Es la
   misma trampa contra la que avisa el comentario del borde unas reglas mas
   abajo, y aqui se cayo en ella igual.
   Un plano de luz diagonal muy tenue para que el negro macizo no se lea
   plano. Nada de color nuevo: solo blanco a muy baja opacidad. */
.unit-pill.mine {
  background: linear-gradient(134deg,
      rgba(255, 255, 255, 0.16) 0%,
      rgba(255, 255, 255, 0.05) 38%,
      rgba(255, 255, 255, 0) 60%),
    var(--black);
  color: white;
  border: 1.5px solid var(--black);
}
/* State: theirs (claimed only by someone else) */
.unit-pill.theirs {
  background: var(--gray-100, #F4F4F5);
  color: var(--gray-700);
  border: 1.5px solid var(--gray-300);
}
/* State: shared (me + at least one other) */
.unit-pill.shared {
  background: #F59E0B;
  color: #1F1203;
  border: 1.5px solid #D97706;
}
.unit-pill.shared .up-claim { color: #1F1203; opacity: 0.85; }

/* EL VISTO QUE DA PASO A LOS NOMBRES.
   Al marcar una casilla que ya tenía otra persona, los nombres aparecían de
   golpe y no quedaba claro que el toque hubiera hecho algo: la casilla ya
   tenía texto antes y después. Ahora se confirma primero con un visto —lo
   tuyo ha entrado— y ese visto se retira dejando ver con quién se comparte.
   Se lee como una frase de dos tiempos en medio segundo, no como un
   parpadeo. */
.unit-pill .up-visto {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  animation: up-visto-pasa 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.unit-pill .up-visto svg { width: 17px; height: 17px; fill: currentColor; }
@keyframes up-visto-pasa {
  0%   { opacity: 0; transform: scale(0.35); }
  26%  { opacity: 1; transform: scale(1.14); }
  42%  { opacity: 1; transform: scale(1); }
  64%  { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(0.84); }
}
/* Los nombres esperan debajo y entran cuando el visto ya se está yendo: el
   solape es lo que hace que se lea como un gesto y no como dos. */
.unit-pill.visto-entra .up-body {
  animation: up-nombres-entran 0.5s ease both;
}
@keyframes up-nombres-entran {
  0%, 52% { opacity: 0; transform: translateY(3px); }
  100%    { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .unit-pill .up-visto { animation: none; opacity: 0; }
  .unit-pill.visto-entra .up-body { animation: none; }
}

@keyframes claim-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

/* =========================================================
   Claim-page tutorial (compact inline, inside the ticket)
   ========================================================= */
.claim-tut {
  padding: 6px 2px 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.claim-tut .ct-step {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-family: var(--mono);
  font-size: 0.62rem;
  color: var(--gray-700);
  line-height: 1.35;
}
.claim-tut .ct-num {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--black);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.55rem;
  font-weight: 800;
  font-family: var(--mono);
  margin-top: 1px;
}
.claim-tut .ct-txt {
  flex: 1;
  letter-spacing: 0.01em;
}

/* =========================================================
   Easter egg — "por alvaro saez ;)" (very subtle)
   ========================================================= */
.easter-egg {
  text-align: center;
  font-family: var(--mono);
  font-size: 0.62rem;
  font-style: italic;
  color: rgba(0, 0, 0, 0.32);
  letter-spacing: 0.05em;
  padding: 12px 0 18px;
  user-select: none;
}

/* =============================================
   GRUPOS — viajes y pisos compartidos
   =============================================
   Mismo lenguaje que el resto: papel térmico, monoespaciada para las cifras,
   naranja solo donde hay que mirar. Un grupo es "la carpeta de tickets", no
   otra aplicación, así que nada aquí introduce formas nuevas.
   ============================================= */

/* Título de sección dentro del ticket */
.sec-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-family: var(--mono);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--gray-500);
  margin: 4px 0 8px;
}
.empty-line {
  font-family: var(--sans);
  font-size: 0.7rem;
  color: var(--gray-400);
  padding: 8px 2px;
  font-style: italic;
}

/* --- ¿Quién eres? Pastillas con los miembros del grupo ------------------
   En un grupo el nombre no se escribe: se toca. Así "Álvaro", "alvaro" y
   "Alvarito" no pueden ser tres personas distintas al cuadrar el viaje. */
.who-block { padding: 2px 0 4px; }
.who-label {
  font-family: var(--mono);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--gray-500);
  margin-bottom: 7px;
}
.who-pills { display: flex; flex-wrap: wrap; gap: 6px; }

.who-pill {
  appearance: none;
  border: 1.5px dashed var(--gray-300);
  background: #fff;
  border-radius: 999px;
  padding: 6px 12px;
  /* Sin cuentas de usuario, esta pildora es como te identificas cada vez —
     y sin esto se quedaba en ~28px de alto, la mas pequeña de toda la app. */
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--gray-500);
  cursor: pointer;
  transition: background .16s, color .16s, border-color .16s, transform .1s;
  -webkit-tap-highlight-color: transparent;
}
.who-pill:active { transform: scale(0.95); }
.who-pill.active {
  background: var(--black);
  border-color: var(--black);
  border-style: solid;
  color: var(--paper);
}
.who-pill.small { font-size: 0.63rem; padding: 5px 10px; }

/* Una vez sabes quién eres, el selector estorba: se queda pequeño y aparte. */
.who-block.picked .who-pill:not(.active) { display: none; }
.who-block.picked { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.who-block.picked .who-label { margin-bottom: 0; }

/* Tu enlace personal, para llevarte tu nombre a otro móvil. Solo tiene
   sentido cuando ya has elegido quién eres, así que hasta entonces no está. */
.who-block:not(.picked) .who-link { display: none; }
.who-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-left: auto;
  padding: 4px 8px;
  appearance: none;
  border: none;
  background: transparent;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 0.6875rem;   /* era 0,56rem (9px): es un boton, no letra pequena */
  font-weight: 700;
  color: var(--gray-500);
}
.who-link svg { width: 13px; height: 13px; }

/* Anadir a alguien (solo quien creo el grupo). Mismo tono que el enlace
   personal: una accion secundaria, no un boton mas de la lista de nombres. */
.who-add {
  display: inline-flex;
  margin-top: 8px;
  padding: 6px 8px;
  appearance: none;
  border: 1.5px dashed var(--gray-300);
  border-radius: var(--radius-xs);
  background: transparent;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--gray-500);
}
.who-add:active { color: var(--accent); border-color: var(--accent); }
.who-block.picked .who-add { margin-top: 0; }
.who-add-form {
  display: flex;
  gap: 8px;
  flex-basis: 100%;
  margin-top: 8px;
}
.who-add-form.hidden { display: none; }
.who-add-form input {
  /* El mismo campo que el del formulario de gastos (.ef-row input). */
  flex: 1;
  min-width: 0;
  appearance: none;
  border: 1.5px solid var(--gray-300);
  border-radius: 8px;
  padding: 9px 10px;
  font-family: var(--mono);
  font-size: 0.74rem;
  background: #fff;
  color: var(--black);
}
.who-add-form input:focus { outline: none; border-color: var(--accent); }
.who-add-form .btn { padding: 9px 16px; flex-shrink: 0; }
.who-link:active { color: var(--accent); }

/* El aviso de que esta sesión puede perderse (navegador embebido, o sin
   almacenamiento). Ocupa su propia línea entera: es una explicación, no una
   etiqueta suelta. */
.aviso-sesion {
  flex-basis: 100%;
  margin-top: 8px;
  padding: 9px 11px;
  border-left: 3px solid var(--accent);
  border-radius: 0 8px 8px 0;
  background: rgba(255,107,53,.07);
  font-family: var(--sans);
  font-size: 0.63rem;
  line-height: 1.45;
  color: var(--gray-700);
}

/* --- Tu saldo, en grande -------------------------------------------------
   Es lo primero que quiere ver cualquiera al abrir el grupo: ¿debo o me
   deben? El resto de la pantalla es el detalle de esa respuesta. */
.my-balance {
  margin: 12px 0 4px;
  padding: 14px 16px;
  border-radius: var(--radius-sm);
  border: 1.5px dashed var(--gray-300);
  text-align: center;
  animation: balanceIn .34s cubic-bezier(0.22, 0.61, 0.36, 1);
}
@keyframes balanceIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.my-balance.is-positive { border-color: var(--green); background: var(--green-light, rgba(22,163,74,.07)); }
.my-balance.is-negative { border-color: var(--red);   background: var(--red-light, rgba(220,38,38,.07)); }
.my-balance.is-zero     { border-color: var(--gray-300); background: var(--gray-100, #F4F4F5); }

.mb-label {
  font-family: var(--mono);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--gray-500);
}
.my-balance.is-positive .mb-label { color: var(--green); }
.my-balance.is-negative .mb-label { color: var(--red); }

.mb-amount {
  font-family: var(--mono);
  font-size: 1.7rem;
  font-weight: 700;
  line-height: 1.15;
  margin: 4px 0 2px;
  color: var(--black);
}
.my-balance.is-positive .mb-amount { color: var(--green); }
.my-balance.is-negative .mb-amount { color: var(--red); }

.mb-hint {
  font-family: var(--sans);
  font-size: 0.66rem;
  color: var(--gray-500);
  line-height: 1.4;
}

/* --- Saldo de cada uno --------------------------------------------------- */
.bal-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 7px 2px;
  border-bottom: 1px solid #EDEDF0;
}
.bal-row:last-child { border-bottom: none; }

.bal-name {
  font-family: var(--mono);
  font-size: 0.74rem;
  font-weight: 700;
  color: var(--black);
  display: flex;
  align-items: center;
  gap: 6px;
}
.bal-tag {
  font-family: var(--mono);
  font-size: 0.52rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: var(--black);
  color: var(--paper);
  padding: 2px 5px;
  border-radius: 4px;
}
.bal-amount {
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--gray-500);
}
.bal-row.is-positive .bal-amount { color: var(--green); }
.bal-row.is-negative .bal-amount { color: var(--red); }
.bal-row.is-me .bal-name { color: var(--accent); }

/* --- El cuadre: quién le paga a quién ------------------------------------
   No es "cada uno paga a cada uno": son las transferencias mínimas. Con seis
   personas eso baja de quince pagos a cinco. */
.tr-row {
  padding: 9px 10px;
  margin-bottom: 6px;
  border-radius: var(--radius-sm);
  border: 1.5px dashed var(--gray-300);
  background: #fff;
  animation: trIn .3s ease-out both;
}
@keyframes trIn {
  from { opacity: 0; transform: translateX(-4px); }
  to   { opacity: 1; transform: translateX(0); }
}

.tr-row.is-done { opacity: .55; border-style: solid; border-color: #E4E4E7; }

.tr-main {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--black);
}
.tr-check { color: var(--green); font-weight: 800; }
.tr-arrow { color: var(--accent); font-weight: 800; }
.tr-row.is-done .tr-arrow { color: var(--gray-400); }
.tr-amount { margin-left: auto; font-size: 0.8rem; }
/* Al tocarla copia el importe, listo para pegar en el banco. */
.tr-amount { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.tr-amount:active { opacity: 0.45; }
.tr-from, .tr-to { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 32%; }

.tr-actions { display: flex; gap: 6px; margin-top: 7px; }
.tr-btn {
  flex: 1;
  appearance: none;
  border: 1.5px solid var(--gray-300);
  background: #fff;
  border-radius: 7px;
  padding: 5px 6px;
  font-family: var(--mono);
  font-size: 0.6rem;
  font-weight: 700;
  color: var(--gray-500);
  cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.tr-btn:active { transform: scale(0.97); }
.tr-remind { border-color: var(--accent); color: var(--accent); }
.tr-paid   { border-color: var(--green);  color: var(--green); }
.tr-paid:active { background: var(--green); color: #fff; }

.all-settled {
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--green);
  text-align: center;
  padding: 12px 0;
  letter-spacing: 0.02em;
}

/* --- Listas de tickets y gastos ------------------------------------------ */
.item-row {
  display: block;
  text-decoration: none;
  color: inherit;
  padding: 8px 2px;
  border-bottom: 1px solid #EDEDF0;
}
.item-row:last-of-type { border-bottom: none; }

.item-main {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.item-name {
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--black);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.item-amount {
  font-family: var(--mono);
  font-size: 0.74rem;
  font-weight: 700;
  color: var(--black);
  flex-shrink: 0;
}
.item-sub {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--sans);
  font-size: 0.62rem;
  color: var(--gray-400);
  margin-top: 2px;
}
.item-tag {
  font-family: var(--mono);
  font-size: 0.52rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 5px;
  border-radius: 4px;
}
.item-tag.warn { background: rgba(255,107,53,.14); color: var(--accent); }

.item-del {
  margin-left: auto;
  border: none;
  background: none;
  color: var(--gray-400);
  font-size: 1rem;
  line-height: 1;
  padding: 0 4px;
  cursor: pointer;
}
.item-del:active { color: var(--red); }

.add-line-btn {
  font-family: var(--mono);
  font-size: 0.68rem;
  padding: 8px;
  border-radius: 8px;
  border-style: dashed;
  color: var(--gray-500);
}

/* --- Formulario de gasto sin ticket --------------------------------------
   En un viaje la mitad de lo que se paga no lleva ticket: el taxi, las
   entradas, la gasolina. Sin esto el grupo no cuadra con la realidad. */
.expense-form {
  margin-top: 10px;
  padding: 12px;
  border-radius: var(--radius-sm);
  border: 1.5px dashed var(--accent);
  background: rgba(255,107,53,.05);
  animation: balanceIn .28s ease-out;
}
.ef-row { display: flex; gap: 8px; margin-bottom: 10px; }
.ef-row input {
  appearance: none;
  border: 1.5px solid var(--gray-300);
  border-radius: 8px;
  padding: 9px 10px;
  font-family: var(--mono);
  font-size: 0.74rem;
  background: #fff;
  color: var(--black);
  min-width: 0;
}
.ef-row input:first-child { flex: 1; }
.ef-row input:last-child  { width: 92px; text-align: right; flex-shrink: 0; }
.ef-row input:focus { outline: none; border-color: var(--accent); }

.ef-label {
  font-family: var(--mono);
  font-size: 0.56rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--gray-500);
  margin: 8px 0 5px;
}
.ef-pills { display: flex; flex-wrap: wrap; gap: 5px; }
.ef-actions { display: flex; gap: 8px; margin-top: 12px; }

/* --- Fotos: todavía no, pero se avisa ------------------------------------ */
.soon-block {
  text-align: center;
  padding: 12px 8px 4px;
  opacity: .7;
}
.soon-title {
  font-family: var(--mono);
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--gray-500);
  margin-bottom: 3px;
}
.soon-text {
  font-family: var(--sans);
  font-size: 0.62rem;
  color: var(--gray-400);
  line-height: 1.4;
}

/* --- Las dos vias de la portada ------------------------------------------
   Una cuenta suelta ahora mismo, o un grupo que acumula gastos durante
   semanas. Antes la segunda era un enlace pequeno que no se distinguia de
   un texto mas, y nadie lo encontraba. Ahora pesan lo mismo. */

.via-label {
  font-family: var(--mono);
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--gray-400);
  text-align: center;
  margin-bottom: 12px;
}

/* MEJORA 1 · EL TROQUEL
   Medido a 375x812: la pagina ocupaba 1001 px y la linea de grupos empezaba
   a 828, o sea 16 px POR DEBAJO del corte de pantalla. La peor posicion
   posible: no se ve, y nada insinua que exista.

   Dos cosas, ninguna decorativa. Se recorta el aire muerto para que la linea
   de grupos asome por encima del corte -si asoma, se tira de ella-. Y el
   separador deja de ser una raya centrada: sangra hasta los dos bordes, como
   el troquel de un ticket de verdad. Un papel troquelado de lado a lado dice
   por si solo que sigue habiendo papel debajo; una flecha parpadeando lo
   diria peor y lo dice cualquier pagina. */
.dash-sep.via-sep {
  margin: 10px -20px 12px;
  width: calc(100% + 40px);
}

.group-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 16px 14px;
  appearance: none;
  border: 2px dashed var(--gray-300);
  border-radius: var(--radius-sm);
  background: #fff;
  font-family: var(--sans);
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--black);
  cursor: pointer;
  transition: border-color .18s, background .18s, transform .1s;
  -webkit-tap-highlight-color: transparent;
}
.group-cta:active {
  transform: scale(0.985);
  border-color: var(--accent);
  background: rgba(255,107,53,.05);
}
.group-cta .gc-people {
  width: 22px; height: 22px;
  flex-shrink: 0;
  color: var(--black);
}
/* La hucha va mas apagada y pequena: acompana, no compite con el texto. */
.group-cta .gc-pig {
  width: 17px; height: 17px;
  flex-shrink: 0;
  color: var(--accent);
  opacity: .8;
}
.group-cta:active .gc-people { color: var(--accent); }

.group-cta-sub {
  font-family: var(--sans);
  font-size: 0.68rem;
  color: var(--gray-400);
  text-align: center;
  margin-top: 7px;
}

.member-input-row { display: flex; gap: 8px; margin-bottom: 8px; }
.member-input-row input {
  flex: 1;
  appearance: none;
  border: 1.5px solid var(--gray-300);
  border-radius: 8px;
  padding: 9px 10px;
  font-family: var(--mono);
  font-size: 0.74rem;
  background: #fff;
  min-width: 0;
}
.member-input-row input:focus { outline: none; border-color: var(--accent); }

.member-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 4px; }
.member-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--black);
  color: var(--paper);
  border-radius: 999px;
  padding: 5px 8px 5px 11px;
  font-family: var(--mono);
  font-size: 0.66rem;
  font-weight: 700;
  animation: balanceIn .2s ease-out;
}
.member-chip button {
  border: none;
  background: none;
  color: var(--paper);
  opacity: .6;
  font-size: .9rem;
  line-height: 1;
  padding: 0;
  cursor: pointer;
}
.member-chip button:active { opacity: 1; }

/* En un grupo, la pantalla de marcar cambia el campo de texto por pastillas
   con los miembros. Menos fricción, y hace imposible el descuadre por nombres
   escritos de tres formas distintas. */
.group-picker { padding: 2px 0 6px; }

/* Subtitulo de la pantalla de crear grupo: explica para que sirve, asi que
   necesita mas aire que una fecha suelta. */
.ticket-date.group-purpose {
  font-family: var(--sans);
  font-size: 0.7rem;
  line-height: 1.45;
  letter-spacing: 0;
  text-transform: none;
  color: var(--gray-500);
  padding: 0 6px;
}

/* --- Grupo: apartado de GASTOS -------------------------------------------
   Las dos formas de meter dinero al grupo, una al lado de la otra y con el
   mismo peso. Antes iban en apartados distintos y una parecia secundaria. */
.add-row {
  display: flex;
  gap: 8px;
  margin: 2px 0 4px;
}
.add-btn {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 12px 8px;
  appearance: none;
  border: 1.5px dashed var(--gray-300);
  border-radius: var(--radius-sm);
  background: #fff;
  font-family: var(--mono);
  font-size: 0.63rem;
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  color: var(--gray-500);
  cursor: pointer;
  transition: border-color .16s, color .16s, background .16s, transform .1s;
  -webkit-tap-highlight-color: transparent;
}
.add-btn svg { width: 19px; height: 19px; flex-shrink: 0; }
.add-btn:active {
  transform: scale(0.97);
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(255,107,53,.05);
}

/* Nombre ya cogido por otro movil. Se ve —para saber quien esta dentro— pero
   no se puede tocar: es lo que impide suplantar a alguien y quedarse con sus
   gastos. */
.who-pill.taken {
  opacity: .42;
  border-style: solid;
  cursor: not-allowed;
  text-decoration: line-through;
}
.who-pill.taken:active { transform: none; }

/* La hucha dentro del boton de gasto sin ticket */
.add-btn .ab-pig { width: 21px; height: 21px; }

/* Estado de un ticket sin cerrar. Que YA haya votado todo el mundo es lo que
   dice "ve y cierralo"; que hayan votado todos pero no cuadre hay que decirlo
   igual de claro, porque es el momento de revisar. */
.item-tag.ok  { background: rgba(22,163,74,.14);  color: var(--green); }
.item-tag.bad { background: rgba(220,38,38,.14);  color: var(--red); }
.item-row.listo     { border-left: 3px solid var(--green); padding-left: 8px; }
.item-row.descuadra { border-left: 3px solid var(--red);   padding-left: 8px; }

/* Tus grupos, en la portada. Sin cuentas de usuario, esto es lo que evita que
   un grupo se pierda al cerrar la pestana. */
.mg-row:active { transform: scale(0.985); border-color: var(--accent); }
/* --- Escanear desde dentro de un grupo -----------------------------------
   Quien ya esta en un grupo no necesita que le presenten la aplicacion otra
   vez: se esconde todo lo que sobra y quedan los dos botones de camara y
   galeria, que es a lo unico que ha venido. */
body.en-grupo .via-sep,
body.en-grupo #viaGrupoLabel,
body.en-grupo #groupCta,
body.en-grupo #groupCtaSub,
body.en-grupo #misGrupos,
body.en-grupo #verGruposCta,
body.en-grupo .brand-logo,
body.en-grupo #viaSueltaLabel,
/* Y tambien la portada entera: el titular, el subtitulo, los tres pasos y
   el sello son la presentacion de la aplicacion a quien no la conoce. Quien
   viene de un grupo a escanear otro ticket ya la conoce; ensenarselo otra
   vez es ponerle media pantalla de scroll entre el y los dos botones a los
   que ha venido. */
body.en-grupo .hero-tit,
body.en-grupo .hero-sub,
body.en-grupo .pasos,
body.en-grupo .sello,
body.en-grupo .grupo-linea { display: none !important; }

body.en-grupo .top-acciones { display: none; }

body.en-grupo .volver-fila.hidden { display: flex !important; }

/* Sin la portada delante, lo que queda se centra en la pantalla en vez de
   quedarse colgando de la barra de arriba. */
body.en-grupo .upload-area {
  padding-top: 6px;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 18px;
  /* Centrado OPTICO, no matematico: centrados de verdad los dos botones
     quedaban por debajo de la mitad de la pantalla —la fila de volver, que
     es una linea fina arriba del todo, no pesa lo mismo a la vista que el
     hueco de abajo— y se leia como si se hubieran caido. Un pelin arriba
     del centro es donde el ojo los espera. */
  padding-bottom: 10vh;
}
/* La fila de volver se queda arriba; lo demas es lo que se centra. */
body.en-grupo .volver-fila { margin-bottom: 0; }

/* La entrada: la fila de volver primero y los dos botones justo detras,
   subiendo mientras aparecen. Es medio segundo y solo al abrir la pantalla
   -no se repite-, pero es lo que separa "ha cargado algo" de "esto va
   fino". Se anima opacidad y transform, que no tocan el diseno. */
@media (prefers-reduced-motion: no-preference) {
  body.en-grupo .upload-btns-row { animation: grupo-entra 0.42s cubic-bezier(0.22, 1, 0.36, 1) 0.06s both; }
  body.en-grupo .volver-fila { animation: grupo-entra 0.3s ease both; }
}
@keyframes grupo-entra {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* --- Dias sin pagar ------------------------------------------------------
   Mientras siguen entrando gastos la deuda todavia cambia; en cuanto el grupo
   se queda quieto, los dias empiezan a contar. El color sube con ellos. */
.tr-days {
  font-family: var(--mono);
  font-size: 0.55rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 2px 6px;
  border-radius: 4px;
  margin-left: 6px;
  white-space: nowrap;
}
.tr-days.d0 { background: var(--gray-100, #F4F4F5); color: var(--gray-400); }
.tr-days.d1 { background: rgba(255,107,53,.14); color: var(--accent); }
.tr-days.d2 { background: rgba(220,38,38,.14);  color: var(--red); }
.tr-days.d3 { background: var(--red); color: #fff; }

/* --- Resumen del grupo --------------------------------------------------- */
.stat-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 6px 2px;
  border-bottom: 1px solid #EDEDF0;
}
.stat-row:last-child { border-bottom: none; }
.stat-k {
  font-family: var(--sans);
  font-size: 0.68rem;
  color: var(--gray-500);
}
.stat-v {
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--black);
  text-align: right;
}

/* --- El easter egg: plantilla de los recordatorios ----------------------- */
#repartoTitulo { cursor: default; -webkit-tap-highlight-color: transparent; }
#repartoTitulo.egg-hit { animation: eggShake .5s ease-out; }
@keyframes eggShake {
  0%   { transform: translateX(0); }
  20%  { transform: translateX(-3px) rotate(-1.5deg); color: var(--accent); }
  45%  { transform: translateX(3px)  rotate(1.5deg);  color: var(--accent); }
  70%  { transform: translateX(-2px) rotate(-1deg);   color: var(--accent); }
  100% { transform: translateX(0); }
}

.tpl-panel {
  margin: 10px 0 4px;
  padding: 12px;
  border: 1.5px dashed var(--accent);
  border-radius: var(--radius-sm);
  background: rgba(255,107,53,.05);
  animation: balanceIn .3s ease-out;
}
.tpl-head {
  font-family: var(--mono);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--accent);
  margin-bottom: 8px;
}
.tpl-panel textarea {
  width: 100%;
  box-sizing: border-box;
  appearance: none;
  border: 1.5px solid var(--gray-300);
  border-radius: 8px;
  padding: 9px 10px;
  font-family: var(--sans);
  font-size: 0.72rem;
  line-height: 1.45;
  background: #fff;
  color: var(--black);
  resize: vertical;
}
.tpl-panel textarea:focus { outline: none; border-color: var(--accent); }
.tpl-keys {
  font-family: var(--sans);
  font-size: 0.6rem;
  color: var(--gray-400);
  margin: 7px 0;
}
.tpl-keys code {
  font-family: var(--mono);
  font-size: 0.58rem;
  background: #fff;
  border: 1px solid var(--gray-300);
  border-radius: 4px;
  padding: 1px 4px;
  margin-right: 3px;
}
.tpl-preview {
  font-family: var(--sans);
  font-size: 0.66rem;
  line-height: 1.45;
  color: var(--gray-500);
  background: #fff;
  border-radius: 8px;
  padding: 8px 10px;
  white-space: pre-line;
  margin-bottom: 4px;
}

/* =============================================
   PANTALLA DE GRUPO — escalada
   =============================================
   Aqui hay mucha mas informacion por pantalla que en un ticket suelto:
   saldos, reparto, dos historiales y el resumen. Con el ancho de un ticket
   —326 px dentro de una pagina de 430— todo salia apretado y pequeno.

   Se ensancha el papel y se sube un escalon la tipografia, SOLO en esta
   pantalla. Escanear, marcar y el resumen de un ticket se quedan exactamente
   igual: alli el formato estrecho es parte de la gracia, porque imita un
   ticket de verdad.
   ============================================= */

/* El ancho lo decide una sola clase, que llevan las cuatro pantallas con
   ticket. Si algun dia se cambia, cambian todas a la vez: no se pueden
   quedar unas anchas y otras estrechas. */
.pantalla-ancha .page { max-width: 470px; }
.pantalla-ancha .printer-assembly { padding: 0 14px; }
/* Sigue siendo mas estrecho que la impresora: si no, el papel pareceria salir
   de ningun sitio y se perderia la ilusion. */
/* En pantalla ancha el papel crece, y la boca crece con el sola: sale de la
   misma variable. */
.pantalla-ancha .printer-assembly { --papel-ancho: 93%; }
.pantalla-ancha .ticket { padding: 22px 24px; }

/* --- Cabecera --- */
.pantalla-grupo .ticket-store { font-size: 1rem; }
.pantalla-grupo .ticket-date  { font-size: 0.7rem; }
.pantalla-grupo .data-label   { font-size: 1rem; }
.pantalla-grupo .data-value   { font-size: 1.08rem; }
.pantalla-grupo .data-value.big { font-size: 1.5rem; }
.pantalla-grupo .data-row { padding: 5px 0; }

/* --- Titulos de seccion --- */
.pantalla-grupo .sec-title { font-size: 0.7rem; margin: 6px 0 10px; }
.pantalla-grupo .empty-line { font-size: 0.8rem; padding: 10px 2px; }

/* --- Quien eres --- */
.pantalla-grupo .who-label { font-size: 0.7rem; margin-bottom: 9px; }
.pantalla-grupo .who-pill { font-size: 0.8rem; padding: 8px 15px; }
.pantalla-grupo .who-pill.small { font-size: 0.74rem; padding: 7px 12px; }

/* --- Tu saldo --- */
.pantalla-grupo .my-balance { padding: 18px 16px; margin: 14px 0 6px; }
.pantalla-grupo .mb-label  { font-size: 0.7rem; }
.pantalla-grupo .mb-amount { font-size: 2.1rem; margin: 6px 0 4px; }
.pantalla-grupo .mb-hint   { font-size: 0.76rem; }

/* --- Saldos --- */
.pantalla-grupo .bal-row { padding: 9px 2px; }
.pantalla-grupo .bal-name   { font-size: 0.86rem; }
.pantalla-grupo .bal-amount { font-size: 0.9rem; }
.pantalla-grupo .bal-tag    { font-size: 0.6875rem; padding: 2px 6px; }

/* --- Reparto --- */
.pantalla-grupo .tr-row { padding: 12px 13px; margin-bottom: 8px; }
.pantalla-grupo .tr-main   { font-size: 0.84rem; gap: 7px; }
.pantalla-grupo .tr-amount { font-size: 0.94rem; }
.pantalla-grupo .tr-btn    { font-size: 0.7rem; padding: 7px 6px; }
.pantalla-grupo .tr-days   { font-size: 0.64rem; padding: 3px 7px; }
.pantalla-grupo .tr-actions { margin-top: 9px; }
.pantalla-grupo .all-settled { font-size: 0.84rem; padding: 16px 0; }

/* --- Gastos --- */
.pantalla-grupo .add-btn { font-size: 0.74rem; padding: 15px 8px; gap: 7px; }
.pantalla-grupo .add-btn svg { width: 23px; height: 23px; }
.pantalla-grupo .add-btn .ab-pig { width: 25px; height: 25px; }
.pantalla-grupo .add-row { gap: 10px; margin: 4px 0 6px; }

.pantalla-grupo .item-row { padding: 10px 2px; }
.pantalla-grupo .item-name   { font-size: 0.84rem; }
.pantalla-grupo .item-amount { font-size: 0.86rem; }
.pantalla-grupo .item-sub    { font-size: 0.72rem; margin-top: 3px; }
.pantalla-grupo .item-tag    { font-size: 0.6rem; padding: 3px 6px; }
.pantalla-grupo .item-del    { font-size: 1.15rem; }

/* --- Formulario de gasto --- */
.pantalla-grupo .expense-form { padding: 15px; }
.pantalla-grupo .ef-label { font-size: 0.66rem; }
.pantalla-grupo .ef-row input { font-size: 0.85rem; padding: 11px 12px; }
.pantalla-grupo .ef-row input:last-child { width: 108px; }

/* --- Resumen y avisos --- */
.pantalla-grupo .stat-row { padding: 8px 2px; }
.pantalla-grupo .stat-k { font-size: 0.78rem; }
.pantalla-grupo .stat-v { font-size: 0.84rem; }
.pantalla-grupo .tpl-panel textarea { font-size: 0.8rem; }
.pantalla-grupo .tpl-preview { font-size: 0.74rem; }

/* --- Titulo de seccion como interruptor ----------------------------------
   El titulo entero pliega y despliega: se toca donde se esta mirando, en vez
   de tener que apuntar a un boton pequeno a la derecha. */
/* Plegada, la seccion deja a la vista lo unico que importa: cuanto suma. */
/* Tu propio nombre dentro de un grupo. Ya lo cogiste en este movil, asi que
   no se tacha como los ajenos: se marca como tuyo y viene elegido de serie. */
.who-pill.es-tuyo {
  border-style: solid;
  border-color: var(--accent);
}


/* =========================================================================
   LAS SECCIONES DEL GRUPO
   Mismo sitio y mismo nombre que siempre; lo que cambia es que respiran.

   Antes cada cabecera era una linea con cuatro cosas apretadas —titulo,
   aclaracion, total y un boton— que se cortaban entre si en una pantalla de
   movil. Ahora van en dos alturas, que es como se imprime un ticket de
   verdad: arriba el concepto y el dinero, debajo el detalle.

   Al principio no llevaban ni flecha ni borde: solo se hundían al pulsarlas,
   sin nada que las distinguiera en reposo. Tras un fin de semana de uso real
   en un viaje, la gente las leía como líneas de información y no encontraba
   que se pudieran tocar. Ahora tienen el mismo aspecto de tarjeta —borde de
   puntos, fondo blanco— que ya usan "Escanear un ticket" y "Gasto sin
   ticket" justo encima: es el idioma visual que esta pantalla ya usa para
   decir "esto se toca", así que se aplica también aquí en vez de inventar
   uno nuevo. Y un chevron que gira, que es la señal más reconocible de
   "esto se despliega" que existe.
   ========================================================================= */
.sec-head {
  display: block;
  width: 100%;
  appearance: none;
  border: 1.5px dashed var(--gray-300);
  background: #fff;
  padding: 10px 12px 9px;
  margin: 2px 0 2px;
  text-align: left;
  cursor: pointer;
  border-radius: var(--radius-sm);
  -webkit-tap-highlight-color: transparent;
  transition: background .16s ease, transform .12s ease, border-color .16s ease;
}
.sec-head:active {
  background: rgba(0,0,0,.045);
  transform: scale(0.985);
  border-color: var(--accent);
}

/* El chevron. Gira desde el estado —lo pone group.js según desplegado[]— y
   no desde una regla de CSS: es lo que ya usa esta misma pantalla para el
   candado del reparto, y ahí getComputedStyle demostró no ser de fiar para
   comprobar que una rotación por clase se estuviera aplicando de verdad. */
.sh-chev {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  color: var(--gray-400);
  transition: transform .18s ease, color .16s ease;
}
.sec-head.abierta .sh-chev { color: var(--accent); }

.sh-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.sh-line-b { margin-top: 3px; }

/* La suma y el chevron van juntos: si el chevron fuera un tercer hijo suelto
   de .sh-line, el space-between los repartiría a los tres por igual y el
   chevron se separaría de la cifra a la que acompaña. */
.sh-right { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }

.sh-title {
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  color: var(--black);
}
.sh-sum {
  font-family: var(--mono);
  font-size: 0.86rem;
  font-weight: 800;
  color: var(--black);
  white-space: nowrap;
}
.sh-what {
  font-family: var(--sans);
  font-size: 0.66rem;
  color: var(--gray-400);
}
.sh-count {
  font-family: var(--sans);
  font-size: 0.64rem;
  color: var(--gray-400);
  white-space: nowrap;
}

/* Sin nada dentro, la cabecera baja la voz en vez de ensenar un 0,00 EUR
   que parece una cifra de verdad. */
.sec-head.sin-nada .sh-title,
.sec-head.sin-nada .sh-sum { color: var(--gray-400); font-weight: 700; }
.sec-head.sin-nada .sh-sum { font-size: 0.76rem; }

/* Abierta, la cabecera se queda pegada a su lista: asi se ve de un vistazo
   donde empieza y donde acaba lo que se ha desplegado. */
/* --- El aviso de lo que queda fuera del cuadre --------------------------
   Estaba pegado a la derecha del titulo REPARTO, en letra diminuta, y se
   partia por la mitad. Aqui abajo tiene una franja propia: la cifra manda y
   el motivo se lee entero debajo. */
.settle-note {
  display: block;
  margin: 2px 0 12px;
  padding: 9px 12px;
  border-left: 3px solid var(--accent);
  background: rgba(255,107,53,.06);
  border-radius: 0 8px 8px 0;
}
.sn-amount {
  display: block;
  font-family: var(--mono);
  font-size: 0.92rem;
  font-weight: 800;
  color: var(--accent);
  line-height: 1.15;
}
.sn-why {
  display: block;
  font-family: var(--sans);
  font-size: 0.66rem;
  color: var(--gray-500);
  margin-top: 2px;
}

/* El aviso de dinero que no encajo en ninguna linea del reparto fijado.
   Mismo formato que .settle-note -cifra arriba, motivo debajo- pero en rojo:
   a diferencia de los tickets sin cerrar, esto SI hace falta resolverlo a
   mano, con el boton de recalcular. */
.settle-note.is-warn {
  border-left-color: var(--red);
  background: var(--red-light);
}
.settle-note.is-warn .sn-amount { color: var(--red); }
.sn-fix {
  display: block;
  margin-top: 7px;
  padding: 7px 10px;
  appearance: none;
  border: 1.5px solid var(--red);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--red);
  font-family: var(--mono);
  font-size: 0.64rem;
  font-weight: 700;
  cursor: pointer;
}
.sn-fix:active { background: var(--red); color: #fff; }

/* --- Las filas de dentro -----------------------------------------------
   Antes iban tres o cuatro datos seguidos separados por puntos, y en un
   movil se partian donde caia. Ahora quien pago va a la izquierda, el resto
   a la derecha, y el estado —cuando lo hay— en su propia linea. */
.item-row { padding: 11px 4px; }
.item-main { gap: 12px; }
.item-sub {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-top: 3px;
}
.is-who {
  font-family: var(--sans);
  font-size: 0.68rem;
  color: var(--gray-500);
}
.is-meta {
  font-family: var(--sans);
  font-size: 0.64rem;
  color: var(--gray-400);
  text-align: right;
  white-space: nowrap;
}
.item-state {
  display: inline-block;
  margin-top: 7px;
  font-family: var(--mono);
  font-size: 0.58rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 5px;
}
.item-state.warn { background: rgba(255,107,53,.13); color: var(--accent); }
.item-state.ok   { background: rgba(22,163,74,.13);  color: #16A34A; }
.item-state.bad  { background: rgba(220,38,38,.13);  color: var(--red); }

/* --- Los dos iconos de cada boton de anadir ---------------------------- */
.ab-icos {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.add-btn .ab-ico { width: 20px; height: 20px; flex-shrink: 0; }

/* --- Y todo esto, a la escala de la pantalla de grupo ------------------- */
.pantalla-grupo .sh-title { font-size: 0.9rem; }
.pantalla-grupo .sh-sum   { font-size: 1rem; }
.pantalla-grupo .sh-what  { font-size: 0.74rem; }
.pantalla-grupo .sh-count { font-size: 0.72rem; }
.pantalla-grupo .sec-head { padding: 12px 6px 11px; }
.pantalla-grupo .sh-chev  { width: 16px; height: 16px; }
.pantalla-grupo .is-who   { font-size: 0.78rem; }
.pantalla-grupo .is-meta  { font-size: 0.72rem; }
.pantalla-grupo .item-state { font-size: 0.6875rem; padding: 4px 9px; }
.pantalla-grupo .sn-amount { font-size: 1.08rem; }
.pantalla-grupo .sn-why    { font-size: 0.74rem; }
.pantalla-grupo .add-btn .ab-ico { width: 23px; height: 23px; }


/* =========================================================================
   VOLVER AL GRUPO
   Era una barra naranja entera, y competia con los dos botones de escanear
   —que es a lo que se ha venido—. Ahora solo la flecha es un boton; el texto
   de al lado se limita a decir a donde vuelves.
   ========================================================================= */
.volver-fila {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 16px;
}
.volver-flecha {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border: 1.5px solid var(--gray-300);
  border-radius: 50%;
  background: #fff;
  color: var(--accent);
  text-decoration: none;
  transition: transform .12s ease, border-color .15s ease;
}
.volver-flecha:active { transform: scale(0.9); border-color: var(--accent); }
.volver-flecha svg { width: 17px; height: 17px; }
.volver-texto {
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--gray-500);
}
.volver-texto strong { color: var(--black); }

/* =========================================================================
   VER MIS GRUPOS
   Segundo boton con el mismo formato que el de crear, y no una lista colgando
   al final de la pagina: asi cabe en pantalla sin bajar, y los grupos solo
   ocupan sitio cuando se piden.
   ========================================================================= */
.group-cta-b { margin-top: 10px; }
.group-cta-b .gc-people { color: var(--gray-500); }
.gc-badge {
  min-width: 20px;
  padding: 2px 7px;
  border-radius: 10px;
  background: var(--gray-200, #E8E8EC);
  font-family: var(--mono);
  font-size: 0.62rem;
  font-weight: 800;
  color: var(--gray-500);
}
.group-cta-b.abierto {
  border-style: solid;
  border-color: var(--accent);
}
.group-cta-b.abierto .gc-badge { background: rgba(255,107,53,.16); color: var(--accent); }

.my-groups { margin-top: 8px; }

.mg-row {
  display: flex;
  align-items: stretch;
  gap: 6px;
  border-bottom: 1px dashed var(--gray-300);
}
.mg-row:last-child { border-bottom: none; }

.mg-link {
  flex: 1;
  min-width: 0;
  display: block;
  padding: 11px 4px;
  text-decoration: none;
  color: inherit;
}
.mg-name {
  display: block;
  font-family: var(--mono);
  font-size: 0.82rem;
  font-weight: 800;
  color: var(--black);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Con quien es y de cuando es. En la portada, un total suelto no dice si es
   lo que has gastado, lo que debes o lo que te deben: solo confunde. */
.mg-meta {
  display: block;
  margin-top: 2px;
  font-family: var(--sans);
  font-size: 0.66rem;
  color: var(--gray-400);
}
.mg-del {
  flex-shrink: 0;
  width: 34px;
  appearance: none;
  border: none;
  background: none;
  color: var(--gray-300);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
}
.mg-del:active { color: var(--red); }

/* =========================================================================
   UNA SECCION ABIERTA SE VE COMO UNA CAJA
   Al desplegar, sus filas quedaban al mismo nivel visual que la cabecera:
   parecian secciones hermanas, no el contenido de la que acabas de abrir.
   Ahora la cabecera y su lista forman un solo bloque —misma tinta de fondo,
   esquinas redondeadas arriba y abajo— y las filas van metidas hacia dentro,
   colgando de una linea de puntos que baja por el margen. Es el mismo recurso
   que ya usa el ticket en todas partes, no un estilo nuevo.
   ========================================================================= */
/* Las filas cuelgan de una linea de puntos que baja por el margen: es lo que
   dice "esto de aqui esta dentro de lo de arriba". */
/* La ultima fila cierra la caja con un codo, para que la linea no se corte
   en el aire. */
/* Las etiquetas de estado de un ticket abierto. Van dos: cuantos han marcado
   —en verde cuando ya estan todos— y, si aun asi las cuentas no salen, una
   segunda que lo dice. Son dos problemas distintos: que falte gente por
   marcar, y que lo marcado no sume el total. */
.item-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 7px;
}
.item-tags .item-state { margin-top: 0; }


/* =========================================================================
   UNA SECCION ABIERTA ES UNA CAJA
   Al desplegarla, sus filas quedaban al mismo nivel visual que la cabecera:
   parecian secciones hermanas, no el contenido de la que acabas de abrir.

   Ahora la cabecera y su lista se encierran juntas en un recuadro de puntos
   —la misma trama que usa el ticket en todas partes, no un estilo nuevo— y
   las filas van metidas hacia dentro. Cerrada no se dibuja nada: solo hay
   caja cuando hay algo dentro que encerrar.
   ========================================================================= */
.sec-head.abierta {
  background: rgba(0,0,0,.03);
  border: 1.5px dashed var(--gray-300);
  border-bottom: none;
  border-radius: 10px 10px 0 0;
  padding-left: 12px;
  padding-right: 12px;
  margin-bottom: 0;
}

.sec-body { display: none; }
.sec-body.abierto {
  display: block;
  background: rgba(0,0,0,.03);
  border: 1.5px dashed var(--gray-300);
  border-top: none;
  border-radius: 0 0 10px 10px;
  margin: 0 0 10px;
  padding: 2px 12px 8px;
}

/* El cuerpo ENTRA, no aparece de golpe.
   No se anima el alto a proposito: animar `height` o `max-height` obliga al
   navegador a rehacer el diseno en cada fotograma de la lista entera, que es
   justo lo que hacia que abrir una seccion fuera a tirones. Opacidad y
   `transform` los lleva la GPU y no tocan el diseno. */
@media (prefers-reduced-motion: no-preference) {
  .sec-body.abierto { animation: sec-entra .22s cubic-bezier(.2,.85,.3,1); }
}
@keyframes sec-entra {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

/* Metidas hacia dentro respecto al titulo: es lo que dice "esto cuelga de
   lo de arriba". */
.sec-body.abierto > .item-row,
.sec-body.abierto > .stat-row,
.sec-body.abierto > .empty-line {
  margin-left: 10px;
}
.sec-body.abierto > .item-row { border-bottom: 1px dashed #D8D8DF; }
.sec-body.abierto > .item-row:last-of-type { border-bottom: none; }

.pantalla-grupo .sec-head.abierta,
.pantalla-grupo .sec-body.abierto { padding-left: 14px; padding-right: 14px; }

/* Quien ya tiene grupos guardados ya ha usado la aplicacion: el tutorial de
   tres pasos deja de tener sentido, y son justo los pixeles que hacen que
   "Ver mis grupos" quede fuera de la pantalla en un movil. */

/* Los nombres del grupo, debajo de la linea de QUIEN PAGO. Solo estan
   mientras no hay nadie elegido: en cuanto se toca uno desaparecen y el
   nombre se queda en el hueco de puntos de arriba. */
.payer-picker { padding: 6px 0 2px; }

/* =========================================================================
   UN TICKET TE ESTA ESPERANDO
   Alguien cena, sube la foto y el ticket se queda ahi. Sin esto los demas no
   se enteraban —habia que abrir el historial y darse cuenta solo—, asi que
   los tickets se quedaban a medias durante dias y el reparto no cerraba.
   Sale arriba, donde se mira primero, y solo si falta TU marca.
   ========================================================================= */
.aviso-nuevo {
  display: flex;
  align-items: center;
  gap: 11px;
  margin: 10px 0 4px;
  padding: 12px 14px;
  border: 1.5px dashed var(--accent);
  border-radius: var(--radius-sm);
  background: rgba(255,107,53,.07);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  animation: avisoEntra .45s cubic-bezier(0.22, 0.61, 0.36, 1);
  transition: transform .12s ease;
}
.aviso-nuevo:active { transform: scale(0.985); }

@keyframes avisoEntra {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

/* El punto que late. Es lo unico que se mueve: en una pantalla con dinero,
   una animacion grande da la sensacion de que algo va mal. */
.an-punto {
  width: 9px;
  height: 9px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--accent);
  animation: avisoLate 1.8s ease-in-out infinite;
}
@keyframes avisoLate {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,107,53,.55); }
  70%      { box-shadow: 0 0 0 7px rgba(255,107,53,0); }
}

.an-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.an-tit {
  font-family: var(--mono);
  font-size: 0.74rem;
  font-weight: 800;
  color: var(--black);
}
.an-sub {
  font-family: var(--sans);
  font-size: 0.66rem;
  color: var(--gray-500);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.an-ir {
  flex-shrink: 0;
  font-family: var(--mono);
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

/* La fila del ticket que te espera, dentro de la lista. En seis tickets
   abiertos, saber cual es el tuyo ahorra abrirlos todos. */
.item-row.te-espera .item-name { color: var(--accent); }
.item-state.tuyo { background: var(--accent); color: #fff; }

/* Y a la escala de la pantalla de grupo */
.pantalla-grupo .an-tit { font-size: 0.84rem; }
.pantalla-grupo .an-sub { font-size: 0.74rem; }
.pantalla-grupo .an-ir  { font-size: 0.68rem; }

/* =========================================================================
   ACCESO DIRECTO EN LA PANTALLA DEL MOVIL
   Un boton fijo, "Descargar como app", siempre visible -nunca depende de
   que el navegador decida avisar por su cuenta. Al tocarlo se abren las
   dos opciones (iPhone / Android) y cada una explica o dispara lo suyo.
   ========================================================================= */
.atajo { margin-top: 14px; }
.atajo-btn {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 13px 14px;
  appearance: none;
  border: 1.5px dashed var(--gray-300);
  border-radius: var(--radius-sm);
  background: #fff;
  text-align: left;
  cursor: pointer;
  transition: border-color .15s ease, transform .12s ease;
}
.atajo-btn:active { transform: scale(0.985); border-color: var(--accent); }
.atajo-btn svg { width: 19px; height: 19px; flex-shrink: 0; color: var(--accent); }
.atajo-txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.atajo-tit {
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 800;
  color: var(--black);
}
.atajo-sub {
  font-family: var(--sans);
  font-size: 0.64rem;
  color: var(--gray-400);
  line-height: 1.35;
}

/* Las dos opciones, una al lado de la otra. Misma tarjeta que el boton de
   arriba -las dos son de verdad pulsables, las dos deben parecerlo. */
.atajo-elegir {
  display: flex;
  gap: 8px;
  margin-top: 8px;
}
.atajo-sistema {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 12px 8px;
  appearance: none;
  border: 1.5px dashed var(--gray-300);
  border-radius: var(--radius-sm);
  background: #fff;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 0.66rem;
  font-weight: 700;
  color: var(--black);
  transition: border-color .15s ease, transform .12s ease;
}
.atajo-sistema:active { transform: scale(0.97); border-color: var(--accent); }
.atajo-sistema svg { width: 22px; height: 22px; }
.atajo-sistema .atajo-android { color: #3DDC84; }

/* Las instrucciones (iPhone) o el aviso de repuesto (Android sin dialogo
   del navegador). Solo informa, no se toca: fondo suave y sin borde, para
   no confundirlo con las tarjetas de arriba que si hacen algo. */
.atajo-explica {
  margin-top: 8px;
  padding: 11px 12px;
  border-radius: var(--radius-sm);
  background: var(--gray-100);
}
.atajo-explica-fila {
  display: flex;
  align-items: flex-start;
  gap: 9px;
}
.atajo-explica-fila svg { width: 18px; height: 18px; flex-shrink: 0; color: var(--gray-500); margin-top: 1px; }

/* La pista de "ábrelo en Safari", solo en iPhone. Un tono mas discreto
   todavia: es un caso de repuesto, no el paso principal. */
.atajo-alt {
  margin-top: 6px;
  padding: 0 2px;
  font-family: var(--sans);
  font-size: 0.6rem;
  line-height: 1.4;
  color: var(--gray-400);
  font-style: italic;
}

/* =========================================================================
   IDIOMA Y MONEDA
   Al final de la pagina a proposito: se tocan una vez y no se vuelve, asi
   que no pueden quitarle sitio a lo que si se usa todos los dias.
   ========================================================================= */
.ajustes {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
  margin: 22px 0 4px;
  padding-top: 14px;
  border-top: 1.5px dashed var(--gray-300);
}
.ajuste { flex: 1; min-width: 120px; display: flex; flex-direction: column; gap: 4px; }
.ajuste-lbl {
  font-family: var(--mono);
  font-size: 0.56rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--gray-400);
}
.ajuste select {
  width: 100%;
  appearance: none;
  border: 1.5px solid var(--gray-300);
  border-radius: 8px;
  padding: 9px 26px 9px 10px;
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--black);
  background: #fff
    url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23A1A1AA'%3E%3Cpath d='M7 10l5 5 5-5z'/%3E%3C/svg%3E")
    no-repeat right 6px center / 15px;
  cursor: pointer;
}
.ajuste select:focus { outline: none; border-color: var(--accent); }

/* La moneda cambia como se escriben los importes, no cuanto valen. Decirlo
   evita que alguien crea que la aplicacion convierte divisas. */
.ajuste-nota {
  flex-basis: 100%;
  font-family: var(--sans);
  font-size: 0.6rem;
  color: var(--gray-400);
  line-height: 1.35;
}

/* Dentro de un grupo esto sobra, como todo lo demas de la portada. */
body.en-grupo .ajustes,
body.en-grupo .atajo { display: none !important; }

/* =========================================================================
   EL CANTO DE LA TARJETA DE REPARTO
   El tiempo que lleva viva la deuda se cuenta desde que se BLOQUEO el
   reparto, no desde el ultimo gasto: mientras esta abierto la cifra todavia
   puede cambiar y no hay nada que reclamar.

   Solo cambia el canto. El interior se queda igual, para que la tarjeta siga
   leyendose como las demas y el color sea un dato de fondo, no un grito.

       menos de 1 h   sin color
       1 h            amarillo
       1 dia          naranja
       2 dias         rojo
       3 dias         rojo intenso
       5 dias         violeta
       7 dias o mas   negro
   ========================================================================= */
.tr-row.e1 { border-color: #E8B93B; }
.tr-row.e2 { border-color: #F08C2E; }
.tr-row.e3 { border-color: #DC2626; }
.tr-row.e4 { border-color: #B91C1C; }
.tr-row.e5 { border-color: #86198F; }
.tr-row.e6 { border-color: #18181B; }

/* La tuya. En azul y no en naranja: el naranja es el color con el que la
   aplicacion pide cosas, y aqui solo esta senalando cual te toca a ti. El
   canto lo sigue mandando el tiempo, igual que en las demas. */
.tr-row.is-mine {
  border-color: #3B82F6;
  background: rgba(59,130,246,.06);
}
.tr-row.is-mine.e1 { border-color: #E8B93B; }
.tr-row.is-mine.e2 { border-color: #F08C2E; }
.tr-row.is-mine.e3 { border-color: #DC2626; }
.tr-row.is-mine.e4 { border-color: #B91C1C; }
.tr-row.is-mine.e5 { border-color: #86198F; }
.tr-row.is-mine.e6 { border-color: #18181B; }

/* El relojito: entre el nombre de quien cobra y el importe, gris flojo. Es un
   dato de apoyo, y no puede cambiar el alto de la tarjeta. */
.tr-clock {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-left: 6px;
  font-family: var(--sans);
  font-size: 0.58rem;
  font-weight: 400;
  color: var(--gray-400);
  white-space: nowrap;
  line-height: 1;
}
.tr-clock-ico { font-size: 0.66rem; line-height: 1; opacity: .75; }

/* =========================================================================
   BLOQUEAR EL REPARTO
   Un boton largo y, solo cuando esta bloqueado, la papelera cuadrada a su
   derecha: misma altura, lo mas estrecha posible.
   ========================================================================= */
.lock-row { display: flex; align-items: stretch; gap: 8px; margin: 12px 0 2px; }

.btn-lock {
  flex: 1;
  appearance: none;
  border: 1.5px dashed var(--gray-300);
  border-radius: var(--radius-sm);
  background: #fff;
  padding: 12px 14px;
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  color: var(--black);
  cursor: pointer;
  transition: border-color .15s ease, transform .12s ease, background .15s ease;
}
.btn-lock:active { transform: scale(0.985); }
/* Bloqueado: linea continua. El reparto ya no se mueve, y el canto lo dice. */
.btn-lock.cerrado {
  border-style: solid;
  border-color: var(--black);
  background: var(--black);
  color: #fff;
}

.btn-wipe {
  flex-shrink: 0;
  width: 46px;
  appearance: none;
  border: 1.5px solid var(--red);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--red);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background .15s ease, transform .12s ease;
}
.btn-wipe:active { transform: scale(0.94); background: rgba(220,38,38,.08); }
.btn-wipe svg { width: 17px; height: 17px; }

/* Bloqueado no entra nada nuevo: se dice al lado de los botones apagados. */
.locked-hint {
  margin: 8px 0 2px;
  padding: 9px 11px;
  border-left: 3px solid var(--black);
  background: rgba(0,0,0,.045);
  border-radius: 0 8px 8px 0;
  font-family: var(--sans);
  font-size: 0.66rem;
  color: var(--gray-500);
  line-height: 1.4;
}
.add-btn:disabled { opacity: .4; cursor: not-allowed; }
.add-btn:disabled:active { transform: none; }

.pantalla-grupo .btn-lock { font-size: 0.8rem; padding: 14px 16px; }
.pantalla-grupo .btn-wipe { width: 52px; }
.pantalla-grupo .btn-wipe svg { width: 19px; height: 19px; }
.pantalla-grupo .tr-clock { font-size: 0.66rem; }
.pantalla-grupo .locked-hint { font-size: 0.74rem; }


/* =========================================================================
   LAS TRES PANTALLAS DE TICKET, A LA ESCALA DE LA DE GRUPO
   El papel pasa de 326 a 411 px de ancho. Si las letras se quedaran donde
   estaban, el ticket se veria vacio: suben en la misma proporcion (~1,15x)
   que ya subieron en el grupo. Solo tamanos y espacios — ni una posicion,
   ni un color, ni una estructura.
   ========================================================================= */

/* --- Cabecera del papel --- */
.pantalla-ancha .ticket-store { font-size: 1rem; }
.pantalla-ancha .ticket-date  { font-size: 0.6875rem; }

/* --- Quien pago y cuantos sois --- */
.pantalla-ancha .payer-field label,
.pantalla-ancha .participants-field label { font-size: 0.7rem; }
.pantalla-ancha .payer-field input,
.pantalla-ancha .participants-field input { font-size: 0.9rem; }
.pantalla-ancha .participants-hint { font-size: 0.7rem; }

/* --- La lista de articulos --- */
.pantalla-ancha .edit-header { font-size: 0.62rem; }
.pantalla-ancha .edit-name,
.pantalla-ancha .item-line-name { font-size: 0.84rem; }
.pantalla-ancha .edit-qty,
.pantalla-ancha .edit-unit,
.pantalla-ancha .edit-total { font-size: 0.8rem; }

/* --- Totales --- */
.pantalla-ancha .data-label { font-size: 0.82rem; }
.pantalla-ancha .data-value { font-size: 0.92rem; }
.pantalla-ancha .data-value.big { font-size: 1.25rem; }

/* --- Marcar lo tuyo --- */
.pantalla-ancha .name-field input { font-size: 1.05rem; }
.pantalla-ancha .claim-item-name { font-size: 0.84rem; }
.pantalla-ancha .claim-item-price { font-size: 0.82rem; }
.pantalla-ancha .unit-pill { font-size: 0.74rem; }
.pantalla-ancha .claim-help summary { font-size: 0.74rem; }
.pantalla-ancha .ct-txt { font-size: 0.76rem; }

/* --- Resumen --- */
.pantalla-ancha .person-name { font-size: 0.9rem; }
.pantalla-ancha .person-total { font-size: 0.95rem; }
.pantalla-ancha .person-item { font-size: 0.78rem; }

/* --- Lo que se comparte con todos --- */
.pantalla-ancha .sec-title { font-size: 0.7rem; }
.pantalla-ancha .empty-line { font-size: 0.8rem; }
.pantalla-ancha .dash-sep { margin: 12px 0; }

/* =========================================================================
   TICKETS PENDIENTES DE MARCAR
   Seccion propia, justo debajo de tu saldo: es lo primero que hay que hacer
   al entrar, antes de mirar cuanto debe nadie. Aparece sola cuando hay
   alguno y desaparece al marcarlos.
   ========================================================================= */
.pendientes { animation: pendEntra .4s cubic-bezier(0.22, 0.61, 0.36, 1); }
@keyframes pendEntra {
  from { opacity: 0; transform: translateY(-5px); }
  to   { opacity: 1; transform: none; }
}

.pend-title { display: flex; align-items: center; gap: 8px; color: var(--accent); }

/* Lo unico que se mueve. En una pantalla con dinero, una animacion grande da
   la sensacion de que algo va mal. */
.pend-punto {
  width: 8px;
  height: 8px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--accent);
  animation: pendLate 1.9s ease-in-out infinite;
}
@keyframes pendLate {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,107,53,.5); }
  70%      { box-shadow: 0 0 0 7px rgba(255,107,53,0); }
}

.pend-row {
  display: block;
  text-decoration: none;
  color: inherit;
  padding: 10px 12px;
  margin-bottom: 7px;
  border: 1.5px dashed var(--accent);
  border-radius: var(--radius-sm);
  background: rgba(255,107,53,.06);
  transition: transform .12s ease;
}
.pend-row:active { transform: scale(0.985); }
.pend-main {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.pend-name {
  font-family: var(--mono);
  font-size: 0.8rem;
  font-weight: 800;
  color: var(--black);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pend-amount { font-family: var(--mono); font-size: 0.84rem; font-weight: 800; }
.pend-sub {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-top: 3px;
  font-family: var(--sans);
  font-size: 0.64rem;
  color: var(--gray-400);
}
.pend-ir {
  font-family: var(--mono);
  font-weight: 800;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* El boton de guardar apagado mientras falte algo. Quien lo pago y entre
   quienes se reparte son tan obligatorios como el nombre y el importe. */
.btn.a-falta, .btn:disabled { opacity: .4; cursor: not-allowed; }
.btn:disabled:active { transform: none; }

/* =========================================================================
   HISTORIAL COMPLETO DEL GRUPO
   Un viaje son veinte apuntes y caben en la pantalla del grupo. Un piso
   compartido, a los seis meses, son doscientos.
   ========================================================================= */
.busca-box {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 11px;
  border: 1.5px solid var(--gray-300);
  border-radius: 10px;
  background: #fff;
  margin: 4px 0 10px;
}
.busca-box:focus-within { border-color: var(--accent); }
.busca-ico { width: 16px; height: 16px; flex-shrink: 0; color: var(--gray-400); }
.busca-box input {
  flex: 1;
  min-width: 0;
  border: none;
  outline: none;
  background: none;
  font-family: var(--sans);
  font-size: 0.82rem;
  color: var(--black);
}
.busca-box input::placeholder { color: var(--gray-300); }
.busca-box input::-webkit-search-cancel-button { display: none; }
.busca-x {
  flex-shrink: 0;
  appearance: none;
  border: none;
  background: none;
  color: var(--gray-400);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
}

.orden-row { display: flex; gap: 6px; margin-bottom: 8px; }
.orden-btn {
  flex: 1;
  appearance: none;
  border: 1.5px solid var(--gray-300);
  border-radius: 8px;
  background: #fff;
  padding: 7px 6px;
  font-family: var(--mono);
  font-size: 0.66rem;
  font-weight: 700;
  color: var(--gray-500);
  cursor: pointer;
}
.orden-btn.activo { border-color: var(--black); color: var(--black); }
/* La flecha dice hacia donde ordena, y solo sale en el que esta activo. */
.orden-btn.activo.desc::after { content: ' \2193'; }
.orden-btn.activo.asc::after  { content: ' \2191'; }

.filtro-gente { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 4px; }

/* La cabecera de cada bloque: el mes, la persona o el tramo de importe,
   segun por donde se este ordenando. */
.hist-grupo {
  font-family: var(--mono);
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  color: var(--gray-400);
  margin: 14px 0 6px;
  padding-bottom: 4px;
  border-bottom: 1.5px dashed var(--gray-300);
  /* Dos columnas: el mes (o la persona, o el tramo) a la izquierda y lo que
     suma a la derecha. La cabecera ya estaba ahi separando; decir cuantos y
     cuanto no cuesta ni una fila mas de pantalla. */
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.hist-grupo > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* La cifra no se parte nunca: antes se rompe el nombre del mes, que se
   entiende igual cortado, que "214,50" en dos lineas, que no. */
.hg-suma {
  flex-shrink: 0;
  letter-spacing: 0.04em;
  font-weight: 700;
  color: var(--gray-500);
}
.hist-grupo:first-child { margin-top: 4px; }

.hist-row {
  display: block;
  text-decoration: none;
  color: inherit;
  padding: 11px 4px;
  border-bottom: 1px dashed #E6E6EA;
  transition: transform .12s ease;
}
.hist-row:last-child { border-bottom: none; }
a.hist-row:active { transform: scale(0.99); }

.hist-main {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.hist-name {
  font-family: var(--mono);
  font-size: 0.82rem;
  font-weight: 800;
  color: var(--black);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hist-amount { font-family: var(--mono); font-size: 0.86rem; font-weight: 800; white-space: nowrap; }
.hist-sub {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-top: 3px;
  font-family: var(--sans);
  font-size: 0.68rem;
  color: var(--gray-500);
}
.hist-date { color: var(--gray-400); font-size: 0.64rem; white-space: nowrap; }

.hist-tag {
  display: inline-block;
  margin-top: 6px;
  font-family: var(--mono);
  font-size: 0.56rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 5px;
}
.hist-tag.suelto  { background: var(--gray-100, #F4F4F5); color: var(--gray-500); }
.hist-tag.abierto { background: rgba(255,107,53,.14); color: var(--accent); }
.hist-tag.cerrado { background: rgba(22,163,74,.13); color: #16A34A; }

.pantalla-grupo .hist-name   { font-size: 0.9rem; }
.pantalla-grupo .hist-amount { font-size: 0.95rem; }
.pantalla-grupo .hist-sub    { font-size: 0.76rem; }
.pantalla-grupo .hist-grupo  { font-size: 0.68rem; }
.pantalla-grupo .busca-box input { font-size: 0.9rem; }
.pantalla-grupo .orden-btn   { font-size: 0.74rem; padding: 9px 6px; }
.pantalla-grupo .pend-name   { font-size: 0.9rem; }
.pantalla-grupo .pend-amount { font-size: 0.95rem; }
.pantalla-grupo .pend-sub    { font-size: 0.72rem; }

/* =========================================================================
   TUTORIALES GUIADOS (tour.js)
   Una burbuja que señala al elemento del que habla, pero SIEMPRE dentro de
   los márgenes de la pantalla — se intenta debajo, si no cabe encima, y si
   ninguno cabe se centra en mitad de la pantalla sin piquito. La posición
   se calcula en tour.js; aquí solo la forma.
   ========================================================================= */
.tour-bubble {
  position: fixed;
  z-index: 500;
  box-sizing: border-box;
  background: var(--black);
  color: #fff;
  border-radius: 14px;
  padding: 12px 14px 14px;
  box-shadow: 0 14px 34px rgba(0,0,0,.32);
  animation: tourIn .26s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
@keyframes tourIn {
  from { opacity: 0; transform: translateY(6px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}

.tb-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}
.tb-count {
  font-family: var(--mono);
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}
.tb-skip {
  appearance: none;
  border: none;
  background: none;
  color: rgba(255,255,255,.55);
  font-size: 1.15rem;
  line-height: 1;
  padding: 0 2px;
  cursor: pointer;
  margin: -4px -2px 0 0;
}
.tb-skip:active { color: #fff; }

.tb-title {
  font-family: var(--sans);
  font-size: 0.86rem;
  font-weight: 800;
  color: #fff;
  margin-bottom: 4px;
}
.tb-body {
  font-family: var(--sans);
  font-size: 0.76rem;
  line-height: 1.45;
  color: rgba(255,255,255,.82);
}
.tb-next {
  display: block;
  width: 100%;
  margin-top: 12px;
  appearance: none;
  border: none;
  border-radius: 9px;
  background: #fff;
  color: var(--black);
  font-family: var(--sans);
  font-size: 0.76rem;
  font-weight: 700;
  padding: 9px 10px;
  cursor: pointer;
}
.tb-next:active { background: var(--accent); color: #fff; }

/* El piquito. Su posición horizontal la fija tour.js en --punta-x, medida
   desde el borde izquierdo de la burbuja hasta el centro del objetivo. */
.tour-bubble.con-piquito-arriba::before,
.tour-bubble.con-piquito-abajo::before {
  content: '';
  position: absolute;
  left: var(--punta-x, 50%);
  margin-left: -6px;
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
}
.tour-bubble.con-piquito-arriba::before {
  top: -6px;
  border-bottom: 6px solid var(--black);
}
.tour-bubble.con-piquito-abajo::before {
  bottom: -6px;
  border-top: 6px solid var(--black);
}

/* El elemento señalado. Un anillo que late, en el naranja de la marca —el
   mismo recurso que ya usa la aplicación para "esto está pasando ahora".

   `scroll-margin-top` es lo que evita el fallo real que tenía esto: en el
   primer paso, `scrollIntoView({block:'center'})` centraba un objetivo que
   YA estaba visible, y ese centrado empujaba la página lo justo para que
   `.top-bar` (fija, 65px, mismo color que el fondo) tapase el titular de
   la portada por completo. Con el margen puesto aquí, el navegador reserva
   ese hueco al decidir cuánto hace falta desplazar — para cualquier paso
   del tour, no solo el primero. */
.tour-target {
  border-radius: 10px;
  scroll-margin-top: 74px;
  animation: tourPulso 1.7s ease-in-out infinite;
}
@keyframes tourPulso {
  0%, 100% { box-shadow: 0 0 0 3px rgba(255,107,53,.4); }
  50%      { box-shadow: 0 0 0 6px rgba(255,107,53,.12); }
}

/* =========================================================================
   AVISOS DENTRO DE LA APLICACIÓN (notify.js)
   El grupo se refrescaba solo, pero en silencio: las cifras cambiaban
   delante de ti sin decirte por qué. Estas tarjetas ponen nombre al cambio.

   Van arriba y no abajo: abajo está el botón de compartir, y un aviso que
   aparece justo donde va el pulgar se cierra sin querer. Y se apilan hacia
   abajo, para que el más reciente quede a la vista sin empujar a los otros.
   ========================================================================= */
.avisos-pila {
  position: fixed;
  top: max(10px, env(safe-area-inset-top));
  left: 50%;
  transform: translateX(-50%);
  z-index: 600;
  width: min(420px, calc(100vw - 24px));
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;   /* la pila no tapa; solo las tarjetas responden */
}

.aviso {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 12px;
  border-radius: 13px;
  background: var(--black);
  color: #fff;
  box-shadow: 0 10px 30px rgba(0,0,0,.28);
  animation: avisoEntraArriba .28s cubic-bezier(0.22, 0.61, 0.36, 1) both;
  /* El borde de color a la izquierda es lo que distingue un aviso bueno de
     uno que pide atención, sin tener que leerlo. */
  border-left: 3px solid var(--gray-500);
}
.aviso-ok    { border-left-color: #4ADE80; }
.aviso-aviso { border-left-color: var(--accent); }

@keyframes avisoEntraArriba {
  from { opacity: 0; transform: translateY(-10px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}
.aviso.saliendo { animation: avisoSale .2s ease-in both; }
@keyframes avisoSale {
  to { opacity: 0; transform: translateY(-8px) scale(0.98); }
}

.aviso.av-clicable { cursor: pointer; }
.aviso.av-clicable:active { transform: scale(0.985); }

.av-ico {
  flex-shrink: 0;
  font-size: 1.05rem;
  line-height: 1.25;
}
.av-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.av-tit {
  font-family: var(--sans);
  font-size: 0.78rem;
  font-weight: 700;
  color: #fff;
  line-height: 1.3;
}
.av-cue {
  font-family: var(--sans);
  font-size: 0.7rem;
  line-height: 1.35;
  color: rgba(255,255,255,.78);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.av-x {
  flex-shrink: 0;
  appearance: none;
  border: none;
  background: none;
  color: rgba(255,255,255,.5);
  font-size: 1.1rem;
  line-height: 1;
  padding: 0 2px;
  margin: -2px -2px 0 0;
  cursor: pointer;
}
.av-x:active { color: #fff; }

/* =========================================================================
   SILENCIAR LOS AVISOS
   La campana se tacha cuando están silenciados: el estado se ve de un
   vistazo, sin tener que leer el texto de al lado.
   ========================================================================= */
.ajuste-campana {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  gap: 9px;
  margin-top: 4px;
  padding: 9px 11px;
  appearance: none;
  border: 1.5px solid var(--gray-300);
  border-radius: 10px;
  background: #fff;
  cursor: pointer;
  text-align: left;
  transition: border-color .15s ease, transform .12s ease;
}
.ajuste-campana:active { transform: scale(0.985); }

.campana-ico {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--accent);
  transition: color .15s ease;
}
/* La raya que tacha la campana. Se dibuja sola de una esquina a otra en vez
   de aparecer de golpe: así se entiende que la acción es "tachar". */
.campana-tacha {
  stroke-dasharray: 26;
  /* El trazo lo pone el JavaScript según el estado; aquí solo el movimiento. */
  transition: stroke-dashoffset .22s ease;
}
.ajuste-campana.silenciado .campana-ico { color: var(--gray-400); }

.campana-txt {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--gray-500);
}
.ajuste-campana.silenciado .campana-txt { color: var(--gray-400); }

/* =========================================================================
   LAS FOTOS DEL TICKET
   Un botón de cámara en cada fila del historial que tiene foto guardada, y
   un visor a pantalla completa. Las fotos se piden al tocarlo, nunca antes.
   ========================================================================= */
.hist-pie {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 6px;
}
.hist-pie .hist-tag { margin-top: 0; }

.hist-foto {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  appearance: none;
  border: 1.5px solid var(--gray-300);
  border-radius: 8px;
  background: #fff;
  padding: 5px 9px;
  color: var(--gray-500);
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease, transform .12s ease;
}
.hist-foto:active { transform: scale(0.94); border-color: var(--accent); color: var(--accent); }
.hist-foto svg { width: 15px; height: 15px; }
.hist-foto span {
  font-family: var(--mono);
  font-size: 0.62rem;
  font-weight: 800;
}

/* --- El visor --- */
.visor {
  position: fixed;
  inset: 0;
  z-index: 700;
  background: rgba(24,24,27,.94);
  display: flex;
  flex-direction: column;
  animation: visorEntra .2s ease-out both;
}
@keyframes visorEntra { from { opacity: 0; } to { opacity: 1; } }

/* Con el visor abierto el fondo no se desplaza: si no, al arrastrar la foto
   se movía la lista de debajo. */
body.con-visor { overflow: hidden; }

.visor-barra {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: max(12px, env(safe-area-inset-top)) 16px 12px;
  flex-shrink: 0;
}
.visor-tit {
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 800;
  color: #fff;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.visor-x {
  flex-shrink: 0;
  appearance: none;
  border: none;
  background: rgba(255,255,255,.12);
  color: #fff;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
}
.visor-x:active { background: rgba(255,255,255,.25); }

.visor-cuerpo {
  flex: 1;
  overflow-y: auto;
  padding: 0 12px max(16px, env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
}
.visor-img {
  max-width: 100%;
  border-radius: 10px;
  /* Un ticket es alto y estrecho: se deja crecer hasta llenar la pantalla,
     que es como se lee de verdad. */
  box-shadow: 0 8px 30px rgba(0,0,0,.4);
}
.visor-cargando {
  color: rgba(255,255,255,.7);
  font-family: var(--sans);
  font-size: 0.8rem;
  padding: 40px 20px;
  text-align: center;
}

/* =============================================
   PORTADA
   Diseñada por Álvaro en el lienzo (opción B) y llevada aquí tal cual:
   mismos tamaños, mismos colores, mismo orden. Lo único añadido son los
   estados y las transiciones, que en una maqueta estática no existen.
   ============================================= */

.top-bar-portada {
  justify-content: space-between;
  gap: 12px;
}
.top-acciones {
  display: flex;
  align-items: flex-start;
  gap: 14px;
}

/* EL TITULAR. Entra escalonado: primero él, luego el resto. Es lo único
   animado al abrir — el resto llega detrás sin que se note el truco. */
.hero-tit {
  margin: 0 0 12px;
  font-family: var(--display);
  font-size: 2.15rem;
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.04em;
  color: var(--black);
  text-wrap: pretty;
  animation: portada-sube 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.hero-acento { color: var(--accent); }

.hero-sub {
  margin: 0 0 26px;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  line-height: 1.42;
  color: #52525BA2;
  animation: portada-sube 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.06s both;
}

/* LOS TRES PASOS, como las líneas de un ticket: papel, separadores
   discontinuos y el número en el naranja de la marca. */
.pasos {
  background: var(--paper);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-ticket);
  padding: 4px 16px 6px;
  margin-bottom: 26px;
  animation: portada-sube 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.12s both;
}
.paso {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 0;
}
.paso-n {
  font-family: var(--mono);
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--accent);
  width: 20px;
  flex-shrink: 0;
}
.paso-t {
  font-family: var(--sans);
  font-size: 0.86rem;
  font-weight: 600;
  color: var(--black);
}
.pasos .dash-sep { margin: 0; }

/* LOS DOS CÍRCULOS. La cámara va en negro macizo: es LA acción, y la
   galería la alternativa. Ambos al mismo tamaño —en el lienzo quedaron
   con tres píxeles de diferencia por el arrastre del ratón, y esa
   asimetría se lee como un fallo, no como una decisión. */
.upload-btns-row {
  animation: portada-sube 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.18s both;
}
.upload-option-icon {
  width: 102px;
  height: 102px;
}
.upload-option-icon svg { width: 38px; height: 38px; }

.upload-primaria .upload-option-icon {
  background: var(--black);
  border-color: var(--black);
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.18);
}
.upload-primaria .upload-option-icon svg { fill: var(--paper); }
.upload-primaria span { color: var(--black); font-weight: 700; }

/* El pulso de la cámara: una onda que sale del círculo cada pocos
   segundos. Es lo único que se mueve en la pantalla en reposo, así que
   es también lo que dice por dónde se empieza. */
.upload-primaria .upload-option-icon::after {
  content: '';
  position: absolute;
  inset: -2.5px;
  border-radius: 50%;
  border: 2px solid var(--accent);
  opacity: 0;
  animation: camara-pulso 3.6s ease-out infinite 1.2s;
  pointer-events: none;
}
.upload-option-icon { position: relative; }
@keyframes camara-pulso {
  0%        { transform: scale(1);    opacity: 0.55; }
  55%, 100% { transform: scale(1.28); opacity: 0; }
}

/* EL SELLO: lo único que la competencia no puede copiar sin rehacer su
   producto. Discreto a propósito; no es una promesa comercial, es un
   dato. */
.sello {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  margin-bottom: 22px;
  animation: portada-sube 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.24s both;
}
.sello-check {
  width: 13px;
  height: 13px;
  color: var(--accent);
  flex-shrink: 0;
}
.sello-txt {
  display: flex;
  flex-direction: column;
  line-height: 1.35;
}
.sello-a {
  font-family: var(--sans);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: #3F3F4676;
}
.sello-b {
  font-family: var(--sans);
  font-size: 9px;
  font-weight: 500;
  color: #3F3F4676;
  padding-left: 10px;
}

/* LOS GRUPOS. Una línea, no un botón: siguen a un toque, pero ya no
   compiten con escanear. Ese empate visual era lo que hacía que la
   portada se leyera como la de un Tricount. */
.grupo-linea {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 4px 0 20px;
  appearance: none;
  border: none;
  background: none;
  animation: portada-sube 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.3s both;
}
.gl-ico {
  width: 15px;
  height: 15px;
  color: var(--gray-500);
  flex-shrink: 0;
}
.gl-preg {
  font-family: var(--sans);
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--gray-700);
}
.gl-enlace {
  appearance: none;
  border: none;
  background: none;
  padding: 0;
  font-family: var(--sans);
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--black);
  border-bottom: 1.5px solid var(--accent);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color 0.16s ease;
}
.grupo-linea:active .gl-enlace,
.gl-enlace:active { color: var(--accent); }

.grupo-linea-btn { cursor: pointer; }
.gl-chev {
  width: 16px;
  height: 16px;
  color: var(--gray-400);
  transition: transform 0.2s ease;
}
.grupo-linea-btn.abierto .gl-chev { transform: rotate(180deg); }

/* MEJORA 2 · PAPEL BAJO EL PULGAR
   Los dos circulos son lo unico que se toca de verdad en esta pantalla, y al
   pulsarlos no pasaba nada. El encogimiento uniforme de siempre (scale .96)
   es lo que hace cualquier boton; aqui el objeto es fisico -un disparador- y
   se comporta como tal: se hunde un pelo, la sombra se recoge con el, y vuelve
   sin rebote. Nada de esto se ve por separado; se nota al soltarlo. */
.upload-option .upload-option-icon {
  transition: transform 0.14s cubic-bezier(0.3, 0.7, 0.4, 1),
              box-shadow 0.14s cubic-bezier(0.3, 0.7, 0.4, 1);
}
.upload-option:active .upload-option-icon {
  transform: translateY(2px) scale(0.975);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.16);
}

/* MEJORA 3 · LA TINTA QUE ASIENTA
   El titular entraba de una pieza. Pero la tercera linea -la naranja- es la
   que dice en que se diferencia esto de un Tricount, y llegaba a la vez que
   el resto, asi que se leia como parte del mismo bloque. Ahora asienta una
   fraccion despues, como la ultima pasada de una impresora termica. Es UN
   momento orquestado en toda la portada, no un efecto por seccion. */
.hero-acento {
  display: inline-block;
  animation: tinta-asienta 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.26s both;
}
@keyframes tinta-asienta {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

/* MEJORA 9 · GRUPOS: UN BOTON, Y DETRAS UNA HOJA
   Dos estados, y solo se ve uno. Sin grupos todavia sigue la linea de la
   maqueta -"¿Un viaje o un piso? Crea un grupo"-, que es la que explica para
   que sirve. Con grupos ya creados esa pregunta sobra, y queda este boton:
   gente, la palabra, y cuantos hay. Nada mas.
   Al tocarlo ya no se despliega un acordeon que empujaba la portada hacia
   abajo -moviendo de sitio justo lo que estabas mirando-, sino la misma hoja
   que los ajustes. Y ahi si cabe crear un grupo como accion principal, en vez
   de como enlace escondido al final de una lista. */
.grupos-btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 9px 16px 9px 13px;
  appearance: none;
  border: 1.5px solid var(--gray-300);
  border-radius: 999px;
  background: #fff;
  cursor: pointer;
  color: var(--black);
  -webkit-tap-highlight-color: transparent;
  transition: border-color 0.16s ease, transform 0.12s ease, box-shadow 0.16s ease;
}
.grupos-btn:active { transform: scale(0.975); border-color: var(--accent); }
.grupos-btn .gb-ico { width: 17px; height: 17px; color: var(--gray-500); }
.grupos-btn .gb-txt {
  font-family: var(--sans);
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}
/* La cifra en naranja macizo: es el unico dato que cambia, y es la razon por
   la que alguien vuelve a abrir esto. */
.grupos-btn .gb-num {
  font-family: var(--mono);
  font-size: 0.66rem;
  font-weight: 700;
  min-width: 19px;
  height: 19px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Crear un grupo, dentro de la hoja: es la accion principal, no un apunte. */
.mg-crear {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  /* 18 px a los lados, los mismos que la cabecera de la hoja: sin esto el
     boton llegaba a sangre y no se leia como parte del panel. */
  width: calc(100% - 36px);
  margin: 0 18px 14px;
  padding: 14px;
  appearance: none;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--black);
  color: var(--paper);
  font-family: var(--sans);
  font-size: 0.88rem;
  font-weight: 700;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.12s ease;
}
.mg-crear:active { transform: scale(0.985); }
.mg-crear svg { width: 18px; height: 18px; }
/* La lista, debajo. Con muchos grupos se desplaza ella sola en vez de estirar
   la hoja hasta salirse de la pantalla. */
.mg-lista { max-height: 46vh; overflow-y: auto; padding: 0 18px 4px; }

@keyframes portada-sube {
  from { opacity: 0; transform: translateY(9px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-tit, .hero-sub, .pasos, .upload-btns-row,
  .sello, .grupo-linea, .hero-acento { animation: none; }
  .upload-option .upload-option-icon,
  .upload-option:active .upload-option-icon { transition: none; transform: none; }
  .upload-primaria .upload-option-icon::after { animation: none; opacity: 0; }
}

/* =============================================
   AJUSTES: la hoja que sube desde abajo
   Todo lo que se toca una vez y no se vuelve —idioma, moneda, avisos,
   instalar— vivía al final de la portada ocupando media pantalla. Ahora
   se abre desde la tuerca y devuelve ese sitio al titular.
   ============================================= */
/* La hoja NO se esconde con display:none.
   Una animación de entrada no arranca de forma fiable en el mismo cuadro en
   que un elemento pasa de display:none a visible —el navegador puede saltarse
   el primer fotograma y dejarla fuera de pantalla, que es justo lo que
   pasaba—. Con transform + visibility la transición siempre corre, porque el
   elemento nunca deja de existir en el diseño. */
.hoja-velo {
  position: fixed;
  inset: 0;
  background: rgba(24, 24, 27, 0.32);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  z-index: 60;
  opacity: 0;
  visibility: hidden;
  /* visibility no se interpola: se conmuta. Al abrir, ya (0s de retardo);
     al cerrar, DESPUES de que acabe el desvanecido. Transicionarla como una
     propiedad mas dejaba la hoja congelada fuera de pantalla. */
  transition: opacity 0.24s ease, visibility 0s linear 0.24s;
}
.hoja-velo.abierta { opacity: 1; visibility: visible; transition: opacity 0.24s ease, visibility 0s; }

.hoja {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 61;
  background: var(--paper);
  border-radius: 20px 20px 0 0;
  box-shadow: 0 -14px 44px rgba(0, 0, 0, 0.22);
  max-height: 86vh;
  display: flex;
  flex-direction: column;
  padding-bottom: env(safe-area-inset-bottom, 0);
  transform: translateY(100%);
  visibility: hidden;
  transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1), visibility 0s linear 0.32s;
}
.hoja.abierta {
  transform: none;
  visibility: visible;
  transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1), visibility 0s;
}

@media (prefers-reduced-motion: reduce) {
  .hoja, .hoja-velo { transition-duration: 0.01s; }
}

/* El asa de arriba: la señal universal de "esto se arrastra o se cierra". */
.hoja-asa {
  width: 38px;
  height: 4px;
  border-radius: 2px;
  background: var(--gray-300);
  margin: 9px auto 2px;
  flex-shrink: 0;
}
.hoja-cab {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 18px 10px;
  flex-shrink: 0;
}
.hoja-tit {
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gray-500);
}
.hoja-cerrar {
  appearance: none;
  border: none;
  background: none;
  padding: 4px;
  cursor: pointer;
  color: var(--gray-500);
  -webkit-tap-highlight-color: transparent;
}
.hoja-cerrar svg { width: 20px; height: 20px; display: block; }
.hoja-cerrar:active { color: var(--black); }

.hoja-cuerpo {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 0 18px 20px;
}
.hoja-cuerpo .ajustes { border-top: none; margin-top: 0; padding-top: 0; }

.top-bar-right {
  display: flex;
  align-items: center;
  gap: 2px;
}

/* El historial de tickets, arriba a la derecha: icono a la izquierda y el
   texto en dos lineas cortas al lado ("Historial / tickets").
   Primero fue icono arriba y texto debajo, como las etiquetas de la portada,
   pero con la frase entera salian tres lineas: el boton quedaba mas alto que
   el de compartir, su icono por encima del otro, y la barra entera crecia.
   En fila mide lo mismo que los demas botones (44 px), los dos iconos quedan
   a la misma altura y el titulo del grupo no se mueve. */
.top-historial {
  flex-direction: row;
  align-items: center;
  gap: 6px;
  height: 44px;
  padding: 0 8px 0 6px;
  text-decoration: none;
}
.top-historial svg { width: 20px; height: 20px; flex-shrink: 0; }
.top-historial span {
  white-space: normal;
  max-width: 64px;
  text-align: left;
  line-height: 1.2;
  /* 11px como minimo: es la etiqueta de un boton, no letra pequena. La
     regla compartida de .top-bar-btn-labeled no se toca (la usa la
     portada); aqui solo sube la de este boton. */
  font-size: 0.6875rem;
  color: var(--black);
}

/* Borrar el grupo (o pedirlo), al final de todo. Sin aspecto de boton: una
   linea roja, pequena, centrada. Que se encuentre si se busca, pero que no
   se toque por error al ir a compartir. */
.borrar-pie {
  margin-top: 18px;
  padding-top: 12px;
  border-top: 1.5px dashed var(--gray-300);
  text-align: center;
}
.borrar-pie-btn {
  appearance: none;
  border: none;
  background: none;
  padding: 10px 14px;
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--red);
  cursor: pointer;
  border-radius: var(--radius-xs);
}
.borrar-pie-btn:active { background: var(--red-light); }
.borrar-pie-btn:disabled { color: var(--gray-400); cursor: default; }

/* La hoja de confirmación de borrado reutiliza `.hoja` tal cual: un borde de
   color en un lado de una tarjeta redondeada queda cortado por la esquina y
   es justo la clase de acento que delata una interfaz sin pensar demasiado.
   Lo que distingue esto de un ajuste cualquiera es el texto ("no hay vuelta
   atrás") y el botón rojo, no un marco. */
.hoja-danger { /* sin acento propio: hereda el aspecto normal de .hoja */ }
.borrar-explica {
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--gray-700);
  margin-bottom: 18px;
}
.borrar-campo {
  display: block;
  margin-bottom: 16px;
}
.borrar-lbl {
  /* Sin el tracking ancho de `.hoja-tit`: aquella es una palabra corta en
     mayúsculas, esta es una frase entera con el nombre del grupo dentro
     -puede ser largo- y en minúsculas. Con tracking, una frase así se lee
     peor, no mejor. */
  display: block;
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--gray-500);
  margin-bottom: 6px;
}
#borrarInput {
  width: 100%;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--gray-200);
  font-family: var(--sans);
  font-size: 0.95rem;
  background: white;
}
#borrarInput:focus { border-color: var(--red); outline: none; }

.btn-danger {
  background: var(--red);
  color: white;
  box-shadow: 0 4px 14px rgba(220,38,38,0.28);
}
.btn-danger:hover { background: #B91C1C; }
.btn-danger:disabled {
  background: var(--gray-300);
  color: var(--gray-500);
  box-shadow: none;
  cursor: not-allowed;
}

/* La firma, al fondo del todo y en voz baja. */
.firma {
  margin-top: 20px;
  padding-top: 14px;
  border-top: 1.5px dashed var(--gray-300);
  font-family: var(--mono);
  font-size: 0.58rem;
  font-weight: 400;
  letter-spacing: 0.06em;
  color: var(--gray-400);
  text-align: center;
}
.firma-legal {
  display: block;
  margin-top: 6px;
  font-family: var(--mono);
  font-size: 0.58rem;
  font-weight: 400;
  letter-spacing: 0.06em;
  color: var(--gray-400);
  text-align: center;
  text-decoration: underline;
}

/* Crear otro grupo, al final de la lista de los que ya tienes. Discreto:
   es la accion menos frecuente de las tres que hay ahi. */
.mg-nuevo {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  width: 100%;
  margin-top: 6px;
  padding: 11px 10px;
  appearance: none;
  background: none;
  border: 1.5px dashed var(--gray-300);
  border-radius: var(--radius-xs);
  font-family: var(--sans);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--gray-700);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 0.16s ease, color 0.16s ease;
}
.mg-nuevo svg { width: 16px; height: 16px; flex-shrink: 0; }
.mg-nuevo:active { border-color: var(--accent); color: var(--accent); }

/* =========================================================
   RESPALDOS QUE OCUPAN LO MISMO QUE LA FUENTE DE VERDAD
   =========================================================
   ESTE ERA EL LAGAZO. Las fuentes vienen de Google, y hasta que llegan el
   navegador escribe con la de reserva del sistema. El problema es que no
   ocupan lo mismo: MEDIDO en el navegador, el mismo texto en Arial es un
   12,1 % mas ancho que en DM Sans. Asi que cuando la fuente llegaba, TODAS las
   lineas cambiaban de tamano a la vez y el navegador rehacia la maquetacion de
   los 2.773 px del ticket de una sentada. Eso es lo que se veia como "se
   atasca y de golpe aparece todo el texto en su sitio".

   La solucion no es esperar a la fuente -eso deja la pantalla en blanco- sino
   que la de reserva ocupe EXACTAMENTE lo mismo. `size-adjust` la escala hasta
   cuadrar, y los `override` le copian la altura de mayusculas y de las colas
   de las letras. Con eso, cuando la buena entra, no se mueve ni un pixel:
   cambia la forma de las letras y nada mas.

   Los numeros salen de medir las tres fuentes contra su reserva en un canvas,
   no de una tabla de internet:

     DM Sans vs Arial ............ 88,81 %  (Arial era un 12,6 % mas ancho)
     Space Mono vs Courier New ... 101,98 %
     Bricolage vs Arial .......... 105,64 %

   Comprobado despues de ponerlos, desviacion que queda entre la fuente buena
   y su reserva: DM Sans 0,0 %, Space Mono -0,005 %, Bricolage 0,0 %. O sea que
   al llegar la fuente de verdad no se recoloca nada.

   Los `override` van divididos por el `size-adjust` porque se miden sobre la
   eme ya ajustada, no sobre la original. */
@font-face {
  font-family: 'DM Sans reserva';
  src: local('Arial'), local('Helvetica'), local('Roboto');
  size-adjust: 88.81%;
  ascent-override: 111.5%;
  descent-override: 34.9%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Space Mono reserva';
  src: local('Courier New'), local('Courier'), local('monospace');
  size-adjust: 101.98%;
  ascent-override: 109.8%;
  descent-override: 35.3%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Bricolage reserva';
  src: local('Arial'), local('Helvetica'), local('Roboto');
  size-adjust: 105.64%;
  ascent-override: 88%;
  descent-override: 25.6%;
  line-gap-override: 0%;
}
