/* ============================================================
   Bolsillo · Componentes
   ============================================================ */

/* icono-botón del header (>=44px táctil) */
.icon-btn {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: var(--r-full);
  color: var(--text-2);
  background: var(--glass-2);   /* gear neutro en círculo suave */
  border: 1px solid var(--line-2);
  /* El contexto del anillo va AQUÍ y no en el bloque del borde vivo (final de
     views.css) a propósito: .icon-btn es genérica y varias clases la
     reposicionan —.ov-close, .sheet__close, .sheet__back, .cfg-back son
     `absolute`—. Declarado aquí, todas esas reglas vienen después y ganan por
     cascada; declarado al final, les pisaba el position y descuadraba el
     cerrar de todas las hojas. */
  position: relative;
  transition: color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
.icon-btn:hover { color: var(--text-1); background: var(--glass-3); }
.icon-btn:active { transform: scale(0.94); }
.icon-btn svg { width: 22px; height: 22px; }

/* ---- Botones ---- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 48px;
  padding: 0 var(--sp-6);
  border-radius: var(--r-full);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.01em;
  transition: transform var(--dur-fast) var(--ease),
              filter var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
.btn:active { transform: scale(0.97); }
.btn svg { width: 19px; height: 19px; }

.btn--primary {
  /* CTA primario = gradiente firma (naranja→blanco→azul-violeta); texto oscuro encima */
  background: var(--grad-cta);
  color: var(--text-inverse);
  /* etiqueta blanca sobre coral: >=16px/700 (AA-large) */
  font-size: var(--fs-body);
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
  border: 1px solid var(--glass-gloss);
  box-shadow: var(--sh-ia);
}
/* press: conserva el degradado, solo lo atenúa un punto (sin salto a plano) */
.btn--primary:active { filter: brightness(0.96); }
/* hover NO oscurece: sube el brillo */
.btn--primary:hover { filter: brightness(1.06); }

.btn--ghost {
  position: relative;
  background: var(--glass-2);
  color: var(--text-1);
  /* Hairline PLANO y uniforme, no el borde vivo: en un control pequeño el
     tramo encendido se alinea con el del control de al lado y los dos juntos
     se leen como un marco suelto. */
  border: 1px solid var(--line-2);
}
.btn--ghost:hover { background: var(--glass-3); }

.btn--block { display: flex; width: 100%; }

/* Acciones de CABECERA de una vista (volver, editar). Mismo vidrio y mismo radio
   que el botón grande, solo más bajo — así el back y el "Editar" del detalle de
   un producto hermanan en la misma fila. 44px = tap target mínimo accesible.
   Ojo: es distinto de .btn--sm (38px, más abajo), que es el chip de acción
   dentro de listas y hojas ("Agregar", "Retomar"). */
.btn--head { min-height: 44px; padding: 0 var(--sp-4); font-weight: var(--fw-bold); }
.btn--head svg { width: 18px; height: 18px; }

/* Back canónico de la app: SOLO la flecha, en un círculo. Llevaba el destino
   como label ("Hoy", "Mis productos") y eso lo hacía crecer distinto en cada
   nivel; con el icono suelto el control es idéntico en todos y ocupa lo mínimo.
   El destino se anuncia por aria-label, así que no se pierde para lectores. */
.btn--back {
  gap: 0;
  padding: 0;
  width: 44px;          /* cuadrado = círculo con el radio full de .btn */
  flex: 0 0 auto;
}

/* Hubo aquí un componente de tabs con subrayado (.vtabs) para Hoy y la cartera.
   Las dos vistas usan ahora el control segmentado .seg (más abajo) + .seg--dock,
   así que se retiró junto con js/vtabs.js: un solo patrón de pestañas en la app. */

/* El borde vivo de .card/.btn--ghost/.icon-btn/.mov-search y del resto de
   containers se define junto, al final de views.css (orden de cascada). */

/* ---- Cards glass ---- */
.card {
  position: relative;
  background: var(--glass-1);    /* estilo unificado (como .settings-list de Perfil) */
  border: 1px solid transparent; /* el hairline lo pinta el borde vivo */
  border-radius: var(--r-lg);
  padding: var(--sp-5);
  box-shadow: none;             /* se define por el hairline, no por sombra (sobre el destello) */
}
.card__title {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  color: var(--text-1);
  letter-spacing: -0.01em;
}
.card__sub {
  font-size: var(--fs-sm);
  color: var(--text-2);
  margin-top: var(--sp-1);
}

/* ---- Section heading ---- */
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin: var(--sp-7) var(--sp-1) var(--sp-3);
}
.section-head:first-child { margin-top: var(--sp-2); }
.section-head__title {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: var(--fw-bold);
  letter-spacing: -0.015em;
  color: var(--text-1);
}
.section-head__link {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--text-2);
}

/* ---- Badges / pills de estado (semáforo) ---- */
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 5px 11px 5px 9px;
  border-radius: var(--r-full);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.01em;
  border: 1px solid transparent;
}
.pill__dot { width: 7px; height: 7px; border-radius: var(--r-full); }

.pill--verde { color: var(--semaforo-verde); background: var(--semaforo-verde-bg); border-color: var(--semaforo-verde-line); }
.pill--verde .pill__dot { background: var(--semaforo-verde); }
.pill--ambar { color: var(--semaforo-ambar-text); background: var(--semaforo-ambar-bg); border-color: var(--semaforo-ambar-line); }
.pill--ambar .pill__dot { background: var(--semaforo-ambar); }
.pill--rojo  { color: var(--semaforo-rojo-text);  background: var(--semaforo-rojo-bg);  border-color: var(--semaforo-rojo-line); }
.pill--rojo .pill__dot { background: var(--semaforo-rojo); }
.pill--neutral { color: var(--text-2); background: var(--glass-2); border-color: var(--line-2); }
.pill--accent { color: var(--text-1); background: var(--glass-2); border-color: var(--line-2); }

/* ---- Estado vacío ---- */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--sp-8) var(--sp-4) var(--sp-6);
  gap: var(--sp-4);
}
/* Losa del empty state: vidrio con tinte MORADO, no gris opaco. Con --bg-3 se
   leía como un cuadro negro pegado encima del canvas violeta. */
.empty__art {
  width: 96px;
  height: 96px;
  display: grid;
  place-items: center;
  border-radius: var(--r-2xl);
  color: var(--accent-light);
  background:
    radial-gradient(120% 120% at 30% 0%, rgba(169, 140, 255, .18), transparent 60%),
    var(--accent-soft);
  border: 1px solid var(--line-2);
  box-shadow: inset 0 1px 0 var(--glass-gloss), 0 12px 28px -16px var(--accent-glow);
}
.empty__art svg { width: 46px; height: 46px; }
.empty__title {
  font-size: var(--fs-h2);
  font-weight: var(--fw-bold);
  letter-spacing: -0.015em;
  color: var(--text-1);
}
.empty__text {
  font-size: var(--fs-sm);
  color: var(--text-2);
  max-width: 30ch;
  line-height: 1.5;
}
.empty .btn { margin-top: var(--sp-2); }

/* ============================================================
   Tab bar inferior + FAB
   ============================================================ */
.tabbar {
  /* Vidrio flotante tipo iPhone: pill separada ~16px de los bordes */
  /* v60 — FIXED, no absolute. Con absolute el bloque contenedor era .app-shell,
     así que cualquier cosa que cambiara SU altura se llevaba el dock consigo
     (v59 lo estiró a 100lvh y el dock quedó con 2px de 52 visibles). Anclado al
     viewport, el dock está en cuadro mida lo que mida el shell. .app-shell no
     tiene transform/filter/will-change/contain, así que no captura fixed —
     mismo anclaje que ya usan .toast y .vinculo-chip sin problemas. */
  position: fixed;
  /* v65 — el max() vive DENTRO del token, no aquí. Con `transition: left`
     declarada, el motor no re-evalúa un max(var(...)) escrito en la propiedad
     cuando cambia la custom property: se queda con el valor del primer
     cálculo. Verificado en el pane — `bottom`, que no está en la transición,
     sí se actualizaba; `left`/`right`, que sí lo están, no. Resolviendo el
     max() en el token, la propiedad recibe un valor ya plano. */
  left: var(--dock-x);
  right: var(--dock-x);
  bottom: var(--dock-b);
  z-index: var(--z-nav);
  height: var(--nav-h);
  display: grid;
  grid-template-columns: 1fr var(--sp-9) 1fr; /* Hoy | hueco del FAB | Movimientos */
  align-items: stretch;
  border-radius: var(--r-xl);
  background: var(--glass-nav);
  -webkit-backdrop-filter: blur(var(--blur-nav)) saturate(1.4);
  backdrop-filter: blur(var(--blur-nav)) saturate(1.4);
  border: 1px solid var(--glass-nav-line);
  box-shadow: var(--sh-nav);
}

.tab {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-height: 44px;
  color: var(--text-3);
  font-size: 10.5px;
  font-weight: var(--fw-semibold);
  letter-spacing: 0.02em;
  transition: color var(--dur-fast) var(--ease);
}
.tab svg { width: 23px; height: 23px; }
.tab__label { line-height: 1; }
.tab:active { transform: scale(0.93); }
/* activo = ícono RELLENO + blanco (sin acento naranja) */
.tab.is-active { color: var(--text-1); }
.tab__ico--fill { display: none; }
.tab.is-active .tab__ico--line { display: none; }
.tab.is-active .tab__ico--fill { display: block; }
/* pop sutil del ícono al seleccionar la pestaña */
@keyframes tab-pop {
  0% { transform: scale(1); }
  45% { transform: scale(1.2); }
  100% { transform: scale(1); }
}
.tab.is-active svg { animation: tab-pop 0.32s var(--ease); }
@media (prefers-reduced-motion: reduce) {
  .tab.is-active svg { animation: none; }
}
/* sin barra indicadora: el ícono relleno blanco ya marca la pestaña activa */
.tab.is-active::before { content: none; }

/* FAB central elevado */
.fab {
  position: fixed;                                 /* v60 — ver nota en .tabbar */
  z-index: var(--z-fab);
  left: 50%;
  /* +sp-4: reanclado a la barra flotante (misma cabalgadura sobre el borde) */
  bottom: calc(var(--dock-b) + var(--nav-h) - 30px);
  /* --dock-shift lo mueve body.has-toast para dejarle el sitio al toast */
  transform: translateX(-50%) translateY(var(--dock-shift, 0px));
  width: 60px;
  height: 60px;
  border-radius: var(--r-lg); /* cuadrado redondeado (20px) */
  display: grid;
  place-items: center;
  color: var(--text-inverse);
  background: var(--grad-cta);
  /* lienzo un poco mayor que el FAB: permite CORRER el mismo gradiente (misma
     intensidad) al abrir, en vez de cambiarlo. */
  background-size: 140% 140%;
  background-position: 50% 50%;
  /* + anillo interno de 1px: el borde solo no se ve porque el gradiente firma
     llega hasta el canto (background-size 140%). El inset ring lo dibuja por
     dentro y le da el mismo acabado que el CTA primario. */
  box-shadow: var(--sh-fab), inset 0 0 0 1px rgba(255, 255, 255, 0.30);
  border: 1px solid var(--glass-gloss);
  /* SIN transición de `bottom`: es una propiedad de layout (contra la regla de
     animar solo transform/opacity) y, peor, se atascaba. Cuando --dock-b
     cambia por una VARIABLE —que es como se corrige el viewport de iOS— el
     motor deja el `bottom` viejo pintado y no termina la transición: medido,
     el FAB se quedaba en 38px mientras el valor calculado ya era -28px. Sin
     transición sigue a --dock-b al instante. El colapso al hacer scroll pierde
     6px de deslizamiento; la barra sí sigue animando su altura. */
  transition: transform var(--dur-fast) var(--ease), filter var(--dur-fast) var(--ease),
              border-radius var(--dur) var(--ease),
              background-position var(--dur) var(--ease),
              /* para ceder el sitio al toast (body.has-toast) */
              opacity var(--dur-fast) var(--ease);
  will-change: transform, background-position;
  /* long-press del + (atajo de voz): sin menú de selección ni retardos de toque */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  touch-action: manipulation;
}
.fab:hover { filter: brightness(1.06); }
.fab:active { transform: translateX(-50%) translateY(var(--dock-shift, 0px)) scale(0.93); }
.fab svg {
  width: 28px; height: 28px;
  position: relative; z-index: 1;                 /* el ícono va sobre el gradiente */
  transition: transform var(--dur) var(--ease-fan);
}

/* ============================================================
   FAB radial: el + gira hasta ser una X y de él NACEN dos burbujas
   gemelas — gasto (↓ rojo) e ingreso (↑ verde). Al cerrar se recogen
   de vuelta al centro, como si partieran del mismo +.
   ============================================================ */

/* + → X: el ícono gira, el orbe se redondea y el MISMO gradiente firma se
   CORRE de posición (misma intensidad) — con una deriva viva mientras está
   abierto, en vez de cambiar el gradiente. */
body[data-fab="open"] .fab {
  border-radius: var(--r-full);                   /* + cuadrado → orbe redondo */
  animation: fabDrift 3.4s var(--ease-in-out) infinite alternate;
}
body[data-fab="open"] .fab svg {
  transform: rotate(135deg);                       /* + → X con recorrido de giro */
}
@keyframes fabDrift {
  from { background-position: 18% 82%; }
  to   { background-position: 82% 18%; }
}

/* Burbujas: mismo ancla que el FAB; en reposo, encogidas en el centro. */
.fab-bubble {
  position: fixed;                                 /* v60 — mismo ancla que .fab */
  z-index: 49;                                     /* justo debajo del FAB (50) */
  left: 50%;
  bottom: calc(var(--dock-b) + var(--nav-h) - 30px);
  width: 54px; height: 54px;
  border-radius: var(--r-full);
  display: grid; place-items: center;
  color: #fff;
  border: 1px solid var(--fab-hi);
  transform: translate(-50%, 0) scale(0.3);
  opacity: 0;
  pointer-events: none;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
  will-change: transform, opacity;
}
.fab-bubble svg { width: 24px; height: 24px; }
/* Rojo y verde, pero con el MISMO material de gradiente de la app (150deg
   light→deep + rim + glow) que el resto de controles semánticos. */
.fab-bubble--gasto   { background: var(--rojo-grad);  border-color: var(--rojo-rim);
  box-shadow: 0 8px 22px -6px var(--rojo-glow), inset 0 1px 0 var(--fab-hi); }
.fab-bubble--ingreso { background: var(--verde-grad); border-color: var(--verde-rim);
  box-shadow: 0 8px 22px -6px var(--verde-glow), inset 0 1px 0 var(--fab-hi); }

/* Abierto: brotan en arco (izq gasto / der ingreso), con pop escalonado. */
body[data-fab="open"] .fab-bubble { opacity: 1; pointer-events: auto; }
body[data-fab="open"] .fab-bubble--gasto {
  transform: translate(calc(-50% - 72px), -88px) scale(1);
  transition: transform var(--dur) var(--ease-fan), opacity var(--dur-fast) var(--ease);
}
body[data-fab="open"] .fab-bubble--ingreso {
  transform: translate(calc(-50% + 72px), -88px) scale(1);
  transition: transform var(--dur) var(--ease-fan) 45ms, opacity var(--dur-fast) var(--ease) 45ms;
}
.fab-bubble:active { filter: brightness(1.08); }

/* Velo sutil para descartar tocando fuera. */
.fab-veil {
  position: fixed;
  inset: 0;
  z-index: 48;
  background: rgba(10, 10, 12, 0.28);
  -webkit-backdrop-filter: blur(1.5px);
  backdrop-filter: blur(1.5px);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur) var(--ease);
}
body[data-fab="open"] .fab-veil { opacity: 1; pointer-events: auto; }

@media (prefers-reduced-motion: reduce) {
  .fab svg, .fab-bubble, .fab-veil,
  body[data-fab="open"] .fab-bubble--gasto,
  body[data-fab="open"] .fab-bubble--ingreso { transition-duration: 0.01ms; }
  body[data-fab="open"] .fab { animation: none; }
}

/* --- Barra de 4 pestañas: Hoy · Personas · [FAB] · Movimientos · Perfil --- */
.tabbar--4 {
  grid-template-columns: 1fr 1fr var(--sp-9) 1fr 1fr;
}
.tabbar--4 .tab { font-size: 10px; gap: 2px; }
.tabbar--4 .tab svg { width: 22px; height: 22px; }
.tabbar--4 .tab__label { white-space: nowrap; }

/* --- Nav colapsable al hacer scroll: al bajar se resume — más baja, MÁS
   ANGOSTA (los iconos se acercan) y con la barrita naranja encogida. Vuelve
   a expandirse al subir. Animación sutil pero premium. --- */
.tabbar {
  /* --dock-shift lo mueve body.has-toast para dejarle el sitio al toast */
  transform: translateY(var(--dock-shift, 0px));
  /* colapso suave: ease-in-out simétrico (sin snap) */
  transition: height var(--dur) var(--ease-in-out),
              left var(--dur) var(--ease-in-out),
              right var(--dur) var(--ease-in-out),
              /* Acuse del toast (body.has-toast): curva con rebote corto y 60ms
                 de retardo. El retardo es lo que hace que se lea como que el
                 aviso lo empujó y no como dos piezas moviéndose a la vez. */
              transform var(--dur) var(--ease-empuje) 60ms;
}
.tab__label {
  max-height: 1.4em;
  overflow: hidden;
  transition: opacity var(--dur) var(--ease-in-out), max-height var(--dur) var(--ease-in-out);
}
body.nav-min .tabbar--4 {
  height: var(--nav-h-min);
  /* se angosta un poco desde los lados (recorrido corto = movimiento sutil) */
  left: var(--dock-x-min);
  right: var(--dock-x-min);
}
body.nav-min .tab__label { opacity: 0; max-height: 0; }
/* la barrita naranja del activo también encoge */
body.nav-min .tab.is-active::before { width: 13px; height: 2px; }
body.nav-min .fab {
  bottom: calc(var(--dock-b) + var(--nav-h-min) - 30px);
}
@media (prefers-reduced-motion: reduce) {
  .tabbar, .tab__label, .fab, .tab.is-active::before { transition: none; }
}

/* Campana de notificaciones: container translúcido (igual que el hero de Hoy) + badge */
.icon-btn--notif {
  position: relative;
  width: 42px; height: 42px;
  border-radius: 14px;
  background: var(--glass-2);
  border: 1px solid var(--line-1);
  color: var(--text-2);
}
.icon-btn--notif:hover { background: var(--glass-3); color: var(--text-1); }
.notif-badge {
  position: absolute;
  top: -5px;
  right: -5px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  display: grid;
  place-items: center;
  border-radius: var(--r-full);
  background: var(--semaforo-rojo);
  color: var(--text-inverse);
  font-size: 11px;
  font-weight: var(--fw-bold);
  line-height: 1;
  box-shadow: 0 1px 6px var(--semaforo-rojo-line);
}
.notif-badge[hidden] { display: none; }

/* Piso del dock: funde el contenido que se va por detrás de la barra flotante.
   La v25 lo terminaba en var(--bg-root) cuando ese token era #41241A, así que
   pintaba ~30px de café sólido a lo ancho — el bulto más visible del "espacio
   marrón". Ahora termina en var(--bg-0), que es a la vez el canvas y (por
   diseño) --bg-root: el piso, el fondo de la app y la banda que pinta iOS son
   EL MISMO color, así que no hay losa que ver ni costura que disimular. Contra
   el fondo vacío el degradado es invisible; solo aparece cuando hay contenido
   pasando por detrás, que es su función original (la v14 la perdió al quitarle
   el backdrop-filter, que en iOS teñía el safe-area). */
.nav-blur {
  position: fixed;                                 /* v60 — acompaña al dock */
  left: 0;
  right: 0;
  bottom: 0;
  /* Alto = la MISMA reserva del contenido (--view-b). Antes era
     dock-b + nav-h + sp-9 (48) = 118px y mordía ~28px del CTA "Configurar mi
     sueldo" en reposo. Alineado a --view-b (80px) cubre exactamente la zona por
     detrás del dock —lo que debe difuminar— y suelta la zona de acción. */
  height: var(--view-b);
  z-index: 35;
  pointer-events: none;
  background: linear-gradient(180deg,
    transparent 0%,
    color-mix(in srgb, var(--bg-0) 45%, transparent) 45%,
    color-mix(in srgb, var(--bg-0) 90%, transparent) 76%,
    var(--bg-0) 92%);
}

/* ============================================================
   Bottom sheet (Registrar - placeholder)
   ============================================================ */
.scrim {
  position: absolute;
  inset: 0;
  z-index: var(--z-scrim);
  background: var(--scrim);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur) var(--ease), visibility 0s linear var(--dur);
}
.scrim.is-open { opacity: 1; visibility: visible; transition: opacity var(--dur) var(--ease); }

.sheet {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: var(--z-sheet);
  background:
    linear-gradient(180deg, var(--bg-2), var(--bg-1));
  border-top-left-radius: var(--r-2xl);
  border-top-right-radius: var(--r-2xl);
  border-top: 1px solid var(--line-2);
  box-shadow: var(--sh-sheet);
  padding: var(--sp-3) max(var(--sp-5), env(safe-area-inset-left))
           calc(var(--safe-b) + var(--sp-6))
           max(var(--sp-5), env(safe-area-inset-right));
  transform: translateY(100%);
  transition: transform var(--dur-slow) var(--ease);
}
.sheet.is-open { transform: translateY(0); }

@media (prefers-reduced-motion: reduce) {
  .sheet { transition: transform var(--dur-fast) linear; }
}

.sheet__grip {
  width: 40px; height: 4px;
  border-radius: var(--r-full);
  background: var(--line-3);
  margin: var(--sp-1) auto var(--sp-4);
}
.sheet__close {
  position: absolute;
  top: var(--sp-3);
  right: max(var(--sp-3), env(safe-area-inset-right));
  color: var(--text-3);
}
.sheet__title {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: var(--fw-bold);
  letter-spacing: -0.015em;
  margin-bottom: var(--sp-1);
  /* Reserva el ancho del botón cerrar (arriba-derecha, 40px) para que un
     título largo nunca quede debajo de él. */
  padding-right: calc(40px + var(--sp-2));
}
/* Cuando hay botón volver, reserva también la izquierda y centra el título
   entre ambos controles: nunca se solapa con back/close. */
.sheet__title--back {
  padding-left: calc(40px + var(--sp-2));
  text-align: center;
}
.sheet__sub {
  font-size: var(--fs-sm);
  color: var(--text-2);
  margin-bottom: var(--sp-5);
}

/* opciones de captura */
.capture-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-2);              /* bento apretado */
}
.capture-opt {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border-radius: var(--r-lg);    /* losa bento redondeada */
  background: var(--glass-2);    /* losa translúcida — coherente con .draft-bar y el glass del sheet */
  border: none;
  text-align: left;
  transition: transform var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
.capture-opt:hover { background: var(--glass-3); }
.capture-opt:active { transform: scale(0.97); }
/* Opción "Foto" a lo ancho (horizontal, destacada). */
.capture-opt--wide { grid-column: 1 / -1; flex-direction: row; align-items: center; gap: var(--sp-4); }
.capture-opt--wide .capture-opt__icon { flex: 0 0 auto; }
.capture-opt__body { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-width: 0; }
.capture-opt__go { color: var(--text-3); flex: 0 0 auto; }
.capture-opt__go svg { width: 20px; height: 20px; transform: rotate(-90deg); }

/* Pantalla de carga mientras la IA lee la foto del recibo. */
.foto-loading {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--sp-2); padding: var(--sp-9) var(--sp-4) var(--sp-8);
}
.foto-loading__spin {
  width: 42px; height: 42px; border-radius: var(--r-full);
  border: 3px solid var(--line-2); border-top-color: var(--text-1);
  animation: bolsillo-spin 0.8s linear infinite; margin-bottom: var(--sp-3);
}
.foto-loading__txt { font-size: var(--fs-h3); font-weight: var(--fw-semibold); color: var(--text-1); }
.foto-loading__sub { font-size: var(--fs-sm); color: var(--text-2); }
@keyframes bolsillo-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .foto-loading__spin { animation-duration: 1.8s; } }
.capture-opt__icon {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  color: var(--text-1);
  background: var(--glass-3);     /* tile anidado — contrasta sobre la losa translúcida por apilamiento */
}
.capture-opt__icon svg { width: 22px; height: 22px; }
.capture-opt__name {
  font-size: var(--fs-body);
  font-weight: var(--fw-semibold);
  color: var(--text-1);
}
.capture-opt__desc {
  font-size: var(--fs-xs);
  color: var(--text-3);
  line-height: 1.4;
}

/* nota placeholder (T2) */
.soon-note {
  margin-top: var(--sp-4);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  justify-content: center;
  font-size: var(--fs-xs);
  color: var(--text-3);
}

/* ============================================================
   Tints de categoría — cada clase fija --tint (usada por chips/iconos)
   ============================================================ */
.cat--persona1 { --tint: var(--cat-persona1); }
.cat--persona2 { --tint: var(--cat-persona2); }
.cat--persona3 { --tint: var(--cat-persona3); }
.cat--yo { --tint: var(--cat-yo); }
.cat--vivienda { --tint: var(--cat-vivienda); }
.cat--servicios { --tint: var(--cat-servicios); }
.cat--mercado { --tint: var(--cat-mercado); }
.cat--transporte { --tint: var(--cat-transporte); }
.cat--colegio { --tint: var(--cat-colegio); }
.cat--seguros { --tint: var(--cat-seguros); }
.cat--salud { --tint: var(--cat-salud); }
.cat--creditos { --tint: var(--cat-creditos); }
.cat--comisiones { --tint: var(--cat-comisiones); }
.cat--ocio { --tint: var(--cat-ocio); }
.cat--restaurantes { --tint: var(--cat-restaurantes); }
.cat--hormiga { --tint: var(--cat-hormiga); }
.cat--negocios { --tint: var(--cat-negocios); }
.cat--otros { --tint: var(--cat-otros); }

/* ============================================================
   Botones extra
   ============================================================ */
.btn--sm { min-height: 38px; padding: 0 var(--sp-4); font-size: var(--fs-xs); }
.btn--danger {
  background: var(--semaforo-rojo-bg);
  color: var(--semaforo-rojo);
  border: 1px solid var(--semaforo-rojo-line);
  font-weight: var(--fw-bold);
}
.btn--danger:hover { background: color-mix(in srgb, var(--semaforo-rojo) 22%, transparent); }
/* Un botón que borra no puede quedar pegado al que guarda: en un pulgar sobre
   vidrio son el mismo objetivo, y equivocarse en un sentido se deshace y en el
   otro no. El aire aquí no es estético, es el margen de error. */
.pre-eliminar { margin-top: var(--sp-4); }
.btn[disabled] { opacity: 0.42; pointer-events: none; }

/* ============================================================
   Sheet Registrar — scroll interno + volver
   ============================================================ */
.sheet {
  max-height: 95dvh;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
.sheet__back {
  position: absolute;
  top: var(--sp-3);
  left: max(var(--sp-3), env(safe-area-inset-left));
  color: var(--text-2);
}

/* opción de captura deshabilitada ("pronto") */
.capture-opt.is-soon { opacity: 0.5; }
.capture-opt.is-soon:hover { background: var(--glass-2); }
.capture-opt__badge {
  align-self: flex-start;
  font-size: 10px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-3);
  background: var(--glass-2);
  border: 1px solid var(--line-2);
  border-radius: var(--r-full);
  padding: 2px 8px;
}

/* ---- barra de borrador ---- */
.draft-bar {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
  border-radius: var(--r-md);
  background: var(--glass-2);
  border: none;
}
.draft-bar__ic {
  flex: 0 0 auto;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  color: var(--accent);            /* alerta de acción pendiente: acento coral, no gris tenue */
  background: var(--accent-soft);  /* relleno propio → deja de fundirse con la barra */
}
.draft-bar__ic svg { width: 18px; height: 18px; }
.draft-bar__body { flex: 1 1 auto; min-width: 0; }
.draft-bar__title { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text-1); }
.draft-bar__text { font-size: var(--fs-xs); color: var(--text-2); margin-top: 1px; }
.draft-bar__actions { display: flex; flex-direction: column; gap: var(--sp-2); flex: 0 0 auto; }

/* ---- texto libre ---- */
.free-text { margin: var(--sp-2) 0 var(--sp-4); }
.free-text__hint { font-size: var(--fs-xs); color: var(--text-3); margin-top: var(--sp-2); }

/* ---- captura por voz (dictado) ---- */
.voz-field { display: block; margin-bottom: var(--sp-3); }
/* especificidad 0,2,0 para ganarle al padding 0 vertical de .field__input */
.voz-field .voz-field__input {
  min-height: 96px;
  padding: var(--sp-3) var(--sp-4);   /* el placeholder no se pega arriba */
  resize: none;
  line-height: 1.45;
}
.voz-hint {
  font-size: var(--fs-xs);
  color: var(--text-3);
  line-height: 1.5;
  margin-bottom: var(--sp-4);
}
.voz-go { margin-top: var(--sp-1); }

/* Aviso de confianza baja en la tarjeta de revisión (ámbar = revisar). */
.voz-warn {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
  border-radius: var(--r-md);
  background: var(--semaforo-ambar-bg);
  border: 1px solid var(--semaforo-ambar-line);
}
.voz-warn__ic { color: var(--semaforo-ambar); flex: 0 0 auto; }
.voz-warn__ic svg { width: 20px; height: 20px; }
.voz-warn__txt { font-size: var(--fs-sm); color: var(--semaforo-ambar-text); line-height: 1.4; }

/* CTA "Tomar dictado": objetivo de toque prominente que invita a la voz. */
.voz-cta {
  display: flex; align-items: center; gap: var(--sp-4);
  width: 100%;
  padding: var(--sp-4);
  margin-bottom: var(--sp-4);
  border-radius: var(--r-md);
  text-align: left;
  background: var(--bg-3);
  border: none;
  transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.voz-cta:hover { background: color-mix(in srgb, var(--bg-3), var(--text-1) 7%); }
.voz-cta:active { transform: scale(0.98); }
.voz-cta__ic {
  flex: 0 0 auto; width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  color: var(--text-1); background: var(--glass-3);
}
.voz-cta__ic svg { width: 24px; height: 24px; }
.voz-cta__body { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.voz-cta__name { font-size: var(--fs-body); font-weight: var(--fw-bold); color: var(--text-1); }
.voz-cta__desc { font-size: var(--fs-xs); color: var(--text-2); }

/* Estado ESCUCHANDO: onda animada + copy. La salida (Terminar/Cancelar) va
   siempre visible debajo para que nunca quede pegado. */
.voz-listen {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--sp-2);
  padding: var(--sp-8) var(--sp-4) var(--sp-6);
}
.voz-listen__wave { display: flex; align-items: center; gap: 5px; height: 44px; }
.voz-listen__wave span {
  width: 5px; height: 14px; border-radius: var(--r-full);
  background: var(--text-1);
  animation: vozWave 1s var(--ease-in-out) infinite;
}
.voz-listen__wave span:nth-child(2) { animation-delay: 0.12s; }
.voz-listen__wave span:nth-child(3) { animation-delay: 0.24s; }
.voz-listen__wave span:nth-child(4) { animation-delay: 0.36s; }
.voz-listen__wave span:nth-child(5) { animation-delay: 0.48s; }
@keyframes vozWave { 0%, 100% { transform: scaleY(0.5); } 50% { transform: scaleY(1.7); } }
@media (prefers-reduced-motion: reduce) { .voz-listen__wave span { animation: none; } }
.voz-listen__title { font-size: var(--fs-h3); font-weight: var(--fw-bold); color: var(--text-1); }
.voz-listen__sub { font-size: var(--fs-sm); color: var(--text-2); }
.voz-listen__cancel { margin-top: var(--sp-2); }

/* Campo "Detalle" del registro (sub libre: uniformes, gasolina, dieta…). */
.reg-detalle { display: block; }
.reg-detalle .field__input { margin-top: var(--sp-1); }
.reg-detalle__hint { display: block; font-size: var(--fs-xs); color: var(--text-3); margin-top: var(--sp-2); }

/* ---- display de monto ---- */
.amt {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 4px;
  width: 100%;
  padding: var(--sp-3) 0 var(--sp-4);
  border-bottom: 1.5px solid var(--line-2);
  transition: border-color var(--dur-fast) var(--ease);
}
.amt.is-active { border-bottom-color: var(--line-3); }
.amt__cur { font-family: var(--font-num); font-size: var(--fs-h2); color: var(--text-3); font-weight: var(--fw-semibold); }
.amt__value {
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-bold);
  font-size: var(--fs-display);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--text-1);
}

/* ---- teclado numérico propio ---- */
.keypad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-2);
  margin: var(--sp-3) 0 var(--sp-5);
}
.keypad__key {
  min-height: 54px;
  border-radius: var(--r-md);
  background: var(--bg-3);
  border: none;
  color: var(--text-1);
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  font-size: 1.35rem;
  font-weight: var(--fw-semibold);
  transition: transform var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.keypad__key:hover { background: var(--glass-2); }
.keypad__key:active { transform: scale(0.95); background: var(--glass-3); }
.keypad__key--del { color: var(--text-2); }
.keypad__key--del svg { width: 24px; height: 24px; margin: 0 auto; }

/* ---- etiquetas de sección/campo ---- */
.field__label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: var(--sp-2);
}
.field__label--section { margin: var(--sp-3) 0 var(--sp-3); }

/* ---- grid de chips de categoría ---- */
.cat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
  gap: var(--sp-2);
}
.cat-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  min-height: 78px;
  padding: var(--sp-3) var(--sp-2);
  border-radius: var(--r-md);
  /* no seleccionado = losa bg-3 sin borde (bento) */
  background: var(--bg-3);
  border: none;
  box-shadow: none;
  transition: transform var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.cat-chip:active { transform: scale(0.96); }
.cat-chip__ic {
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  color: var(--text-1);
  background: var(--glass-2);
}
.cat-chip__ic svg { width: 20px; height: 20px; }
.cat-chip__label {
  font-size: 11px;
  line-height: 1.2;
  font-weight: var(--fw-medium);
  color: var(--text-2);
  text-align: center;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* seleccionado = vidrio coral glossy del FAB */
/* seleccionado = pastilla clara neutra (sin acento naranja), texto/ícono oscuro */
.cat-chip.is-sel {
  background: var(--text-1);
  border-color: transparent;
  box-shadow: var(--sh-sm);
}
.cat-chip.is-sel .cat-chip__ic { background: color-mix(in srgb, var(--text-inverse) 10%, transparent); color: var(--text-inverse); }
.cat-chip.is-sel .cat-chip__label { color: var(--text-inverse); font-weight: var(--fw-semibold); }

/* ---- selector de cuenta ---- */
.acct-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
/* Fila de chips de sugerencia que sigue a un texto de ayuda (no a un label):
   necesita aire propio para no quedar pegada al hint de arriba. */
.acct-row--sug { margin-top: var(--sp-3); }
.acct-chip {
  min-height: 40px;
  padding: 0 var(--sp-4);
  display: inline-flex; align-items: center; gap: var(--sp-2);
  border-radius: var(--r-full);
  /* no seleccionado = pastilla de vidrio translúcida con brillo superior */
  background: var(--glass-tag);
  border: 1px solid var(--line-2);
  box-shadow: inset 0 1px 0 var(--glass-gloss);
  color: var(--text-2);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.acct-chip:active { transform: scale(0.97); }
/* seleccionado = vidrio coral glossy del FAB */
.acct-chip.is-sel {
  background: var(--text-1);
  border-color: transparent;
  color: var(--text-inverse);
  box-shadow: var(--sh-sm);
  font-weight: var(--fw-semibold);
}
.acct-chip--add { color: var(--text-2); border-color: var(--line-3); border-style: dashed; }
.acct-chip--add svg { width: 16px; height: 16px; }
.acct-new { display: flex; gap: var(--sp-2); width: 100%; margin-top: var(--sp-2); }
.acct-new .field__input { flex: 1 1 auto; }

/* ---- ¿A cuántas cuotas? (solo tarjeta de crédito) ---- */
.cuotas-field { margin-top: var(--sp-4); }
.cuotas-field .field__label { display: block; margin-bottom: var(--sp-2); }
.cuotas-chips { margin-top: 0; }
.cuotas-hint { margin-top: var(--sp-2); font-size: var(--fs-xs); color: var(--text-2); }

/* ---- campos de formulario ---- */
/* display:block es CLAVE: .field se usa en <label> (inline por defecto) y en
   <div>. Sin block, margin-top NO aplica a los <label> → campos pegados.
   .toggle-row / .field--split definen su propio display más abajo y ganan. */
.field { display: block; margin-top: var(--sp-5); }
.field__input {
  width: 100%;
  min-height: 46px;
  padding: 0 var(--sp-4);
  border-radius: var(--r-md);
  background: var(--glass-1);
  border: 1px solid var(--line-2);
  color: var(--text-1);
  font-family: var(--font-ui);
  font-size: var(--fs-input); /* >=16px: evita zoom iOS */
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.field__input::placeholder { color: var(--text-3); }
.field__input:focus {
  outline: none;
  border-color: var(--line-3);
  box-shadow: 0 0 0 3px var(--glass-3);
}
.field__textarea { min-height: 62px; padding: var(--sp-3) var(--sp-4); resize: vertical; line-height: 1.4; }

/* error INLINE: se queda junto al campo (el toast se desvanece) */
.field__input.is-error {
  border-color: var(--semaforo-rojo-line);
  box-shadow: 0 0 0 3px var(--semaforo-rojo-bg);
}
.field__input.is-error:focus { border-color: var(--semaforo-rojo); }
.field__err {
  display: block;
  margin-top: var(--sp-2);
  color: var(--semaforo-rojo);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  line-height: 1.35;
}
.field__err:empty { display: none; }
.field--split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
/* min-width:0 evita que un hijo ancho (p. ej. <input type="date"> en iOS)
   reviente su columna 1fr y se solape con la vecina. */
/* Columnas de un split: flex vertical con el input anclado abajo. Así ambas
   columnas alinean sus inputs aunque un label ocupe 2 líneas (el grid ya las
   hace de igual alto con align-items:stretch). */
.field__col { display: flex; flex-direction: column; min-width: 0; }
.field__col .field__input { width: 100%; margin-top: auto; }
.field__col .field__label { margin-bottom: var(--sp-2); }
/* Un split que se queda con una sola columna visible (p. ej. el día de pago
   cuando el producto es un servicio y no hay tasa): que ocupe la fila entera en
   vez de dejar medio ancho vacío. */
.field--split.field--solo { grid-template-columns: 1fr; }
/* `hidden` tiene que ganarle a estos display. El atributo trae display:none del
   UA, pero una regla de autor —aunque sea de la misma especificidad— pisa la
   hoja del navegador: sin esto, poner .hidden = true en un .field no ocultaba
   nada. Vale para todos los formularios que muestran u ocultan campos según lo
   que el usuario elija. */
.field[hidden], .field__col[hidden], .acct-row[hidden] { display: none; }

/* Disparador de fecha: se ve como un input pero abre la hoja de fecha. */
.date-trigger {
  width: 100%;
  min-height: 46px;
  padding: 0 var(--sp-4);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  border-radius: var(--r-md);
  background: var(--glass-1);
  border: 1px solid var(--line-2);
  color: var(--text-1);
  font-family: var(--font-ui);
  font-size: var(--fs-input); /* >=16px: evita zoom iOS */
  text-align: left;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.date-trigger:hover { border-color: var(--line-3); }
.date-trigger:active { transform: scale(0.99); }
.date-trigger__val { font-weight: var(--fw-medium); }
.date-trigger__ic { flex: 0 0 auto; display: grid; place-items: center; color: var(--text-3); }
.date-trigger__ic svg { width: 18px; height: 18px; }

/* switch (toggle gasto fijo) */
.toggle-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.toggle-row .field__label { margin-bottom: 0; text-transform: none; letter-spacing: 0; font-size: var(--fs-sm); color: var(--text-2); font-weight: var(--fw-medium); }
.switch {
  position: relative;
  width: 46px; height: 28px;
  flex: 0 0 auto;
  border-radius: var(--r-full);
  /* off = vidrio esmerilado */
  background: var(--glass-3);
  border: 1px solid var(--line-2);
  box-shadow: inset 0 1px 0 var(--glass-gloss);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
  cursor: pointer;
}
.switch__dot {
  position: absolute;
  top: 2px; left: 2px;
  width: 22px; height: 22px;
  border-radius: var(--r-full);
  background: var(--switch-knob);
  box-shadow: var(--sh-sm);
  transition: transform var(--dur-fast) var(--ease);
}
/* on = mismo vidrio coral glossy del FAB (degradado + borde cálido + brillo especular) */
/* on = track claro neutro + perilla oscura (sin acento naranja) */
.switch.is-on {
  background: var(--text-1);
  border-color: transparent;
  box-shadow: var(--sh-sm);
}
.switch.is-on .switch__dot { transform: translateX(18px); background: var(--text-inverse); }

/* ============================================================
   Perfil → Pantalla: diagnóstico de viewport
   ============================================================ */
.vp-datos {
  display: flex;
  flex-direction: column;
  gap: 1px;                       /* el gap deja ver el fondo = hairline entre filas */
  background: var(--line-2);
  border-radius: var(--r-md);
  overflow: hidden;
}
.vp-dato {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  background: var(--bg-2);
}
.vp-dato__k { font-size: var(--fs-sm); color: var(--text-2); }
.vp-dato__v { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text-1); }
.vp-dato--alerta .vp-dato__v { color: var(--semaforo-rojo); }

/* Reglas de prueba (solo mientras la hoja de Pantalla está abierta).
   CORAL = donde termina el viewport que iOS nos da.
   VERDE = el borde físico de la pantalla (viewport + el déficit medido).
   Si en el equipo solo se ve la coral, iOS recorta lo que se pinta más abajo
   y el modo "pegar al borde" no puede funcionar. Es la única incógnita que
   ningún cálculo resuelve: hay que mirarla en el dispositivo. */
.vp-reglas { position: fixed; inset: 0; z-index: 100; pointer-events: none; }
.vp-regla { position: fixed; left: 0; right: 0; height: 3px; }
.vp-regla--vp { bottom: 0; background: var(--accent); }
.vp-regla--fisico { bottom: calc(-1 * var(--vp-deficit)); background: var(--semaforo-verde); }

/* toggle "detalles" */
.detalles-toggle {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%;
  margin-top: var(--sp-5);
  padding: var(--sp-3) 0;
  color: var(--text-2);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  border-top: 1px solid var(--line-1);
}
.detalles-toggle__chev { transition: transform var(--dur) var(--ease); color: var(--text-3); }
.detalles-toggle__chev svg { width: 18px; height: 18px; }
.detalles-toggle.is-open .detalles-toggle__chev { transform: rotate(180deg); }
.detalles { animation: fadeInSm var(--dur) var(--ease); }

.btn--save { margin-top: var(--sp-5); min-height: 52px; font-size: var(--fs-body); }

@keyframes fadeInSm { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .detalles { animation: none; } }

/* ============================================================
   Toast
   ============================================================ */
.toast {
  position: fixed;
  left: 50%;
  /* Ocupa el sitio del dock, no flota en medio de la pantalla: se lee como
     parte del chrome inferior y deja de tapar el gauge del balance.

     Cabe ahí porque el bloque inferior le hace sitio, no porque se esconda
     nada: el aviso entra desde abajo y EMPUJA al dock (con el FAB montado)
     hacia abajo; al terminar, el dock vuelve a su sitio y de paso empuja el
     toast hacia arriba hasta desvanecerlo. Ver body.has-toast e .is-leaving.

     v143 — QUIÉN VA DÓNDE, que es de lo que iba el bug. Antes el toast se
     metía en el carril del dock (bottom: --dock-b) y el dock bajaba 56px para
     hacerle sitio. Nunca cuadró, y el propio código lo documentaba como un
     callejón sin salida: "con el toast por encima, el FAB queda decapitado;
     por debajo, el FAB se come el final del texto". Las dos salidas eran malas
     porque la premisa lo era — dos piezas peleando por el mismo carril, y
     ninguna reordenación de la pila arregla eso.

     Ahora el toast se apoya ENCIMA del dock, en su propia banda. No hay
     colisión que resolver: el FAB se ve entero y el texto también. Y el empuje
     deja de ser un apartarse de 56px para ser lo que de verdad se lee como
     contacto — el dock cede unos pocos px, como una superficie que acusa el
     peso de algo que se le posó encima.

     v60: sin resta de --vp-piso. Existía para compensar que el shell se
     estirara a 100lvh mientras este fixed seguía en el viewport; ahora el dock
     también es fixed, así que ambos comparten ancla y la resta descuadraba. */
  bottom: calc(var(--dock-b) + var(--nav-h) + var(--fab-asoma) + var(--sp-3));
  /* Entra desde abajo, desde detrás del dock: viene de donde vive el chrome, no
     aparece de la nada en mitad de la pantalla. */
  transform: translate(-50%, 22px) scale(0.96);
  z-index: var(--z-toast);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  /* ANCHO: casi a sangre (antes se ceñía al texto y los mensajes largos
     saltaban a 2 líneas). Ahora hay sitio para una sola línea cómoda. */
  width: min(480px, calc(100vw - var(--sp-5)));
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-lg);
  /* más glass: blur más fuerte + saturación → el fondo se cuela por detrás */
  -webkit-backdrop-filter: blur(30px) saturate(1.6);
  backdrop-filter: blur(30px) saturate(1.6);
  border: 1px solid var(--line-2);
  box-shadow: var(--sh-md), inset 0 1px 0 var(--glass-gloss);
  color: var(--text-1);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  line-height: 1.35;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), visibility 0s linear var(--dur);
}
/* ENTRADA con rebote corto: sube, se pasa un pelo y se asienta. La escala
   acompaña al desplazamiento —llega "tomando cuerpo"— en vez de deslizarse
   rígido. Solo transform y opacity. */
.toast.is-show {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0) scale(1);
  transition: opacity var(--dur-fast) linear,
              transform var(--dur) var(--ease-empuje);
}

/* SALIDA: baja por donde vino y se encoge, devuelto por el dock que recupera su
   sitio. Más rápida que la entrada —una salida lenta se siente como que la app
   te hace esperar— y sin rebote: rebotar al irse contradice la causa.
   Hace falta forzar visibility porque el estado de reposo la apaga tras --dur. */
.toast.is-leaving {
  visibility: visible;
  opacity: 0;
  transform: translate(-50%, 14px) scale(0.97);
  transition: opacity var(--dur-fast) linear,
              transform var(--dur-fast) cubic-bezier(0.4, 0, 1, 1);
}

/* El dock ACUSA el aviso: cede unos pocos px, como una superficie que registra
   el peso de algo que se le posó encima, y vuelve al soltarlo. Ya no se aparta
   —el toast tiene su propia banda, encima—, así que el FAB se ve entero todo el
   rato. Solo transform (el media query de reduced-motion, más abajo, ya le
   corta la transición a ambos).

   El retardo es lo que convierte dos movimientos en una relación de causa:
   arrancando a la vez se leen como dos piezas coordinadas por fuera; cediendo
   un instante DESPUÉS, se lee que una empujó a la otra. 60ms bastan — más y
   parece que el dock reacciona tarde.

   El desplazamiento viaja como VARIABLE y no como una regla descendente
   (`body.has-toast .tabbar { transform: ... }`): así el transform se declara
   una sola vez, en la regla base de cada elemento, y aquí solo cambia su valor.
   Con la regla descendente el transform no llegaba a aplicarse —.tabbar y .fab
   ya declaran el suyo— y el dock se quedaba quieto. */
body.has-toast { --dock-shift: var(--toast-empuje); }
/* El dock lleva su curva de acuse en la regla base (busca --ease-empuje allí).
   El FAB no puede: comparte el `transform` con su :active, y retrasarlo 60ms
   dejaría el botón sintiéndose lento al pulsarlo. Así que el acuse se le pone
   SOLO mientras hay aviso, y por propiedades sueltas en vez de shorthand —el
   shorthand borraría el resto de sus transiciones—.

   ⚠️ Las tres listas son POSICIONALES: siguen el orden de la shorthand de .fab
   (transform, filter, border-radius, background-position, opacity). Si se
   reordena allí, hay que reordenar aquí o el retardo acaba en otra propiedad. */
body.has-toast .fab {
  transition-duration: var(--dur), var(--dur-fast), var(--dur), var(--dur), var(--dur-fast);
  transition-timing-function: var(--ease-empuje), var(--ease), var(--ease), var(--ease), var(--ease);
  transition-delay: 60ms, 0s, 0s, 0s, 0s;
}
.toast__msg { flex: 1 1 auto; min-width: 0; }
.toast__ic { flex: none; display: grid; place-items: center; }
.toast__ic svg { width: 20px; height: 20px; }

/* --- Variante ÉXITO: vidrio VERDE glassmorphic (translúcido sobre el canvas) --- */
.toast--ok {
  background:
    /* Foco de luz en la esquina: mismo lenguaje que el borde vivo de los
       containers, pero en verde. Es lo que le quita el aspecto plano — antes
       era un solo linear-gradient parejo, sin punto de origen de la luz. */
    radial-gradient(120% 150% at 14% -35%,
      color-mix(in srgb, var(--verde-light) 44%, transparent),
      transparent 60%),
    linear-gradient(135deg,
      color-mix(in srgb, var(--verde-light) 32%, transparent),
      color-mix(in srgb, var(--semaforo-verde) 18%, transparent)),
    rgba(11, 11, 13, 0.24);
  border-color: color-mix(in srgb, var(--verde-light) 58%, transparent);
  box-shadow:
    /* halo lejano + un rebote corto y saturado pegado al borde */
    0 14px 42px -10px var(--verde-glow),
    0 2px 16px -4px color-mix(in srgb, var(--verde-light) 32%, transparent),
    /* el filo superior en verde claro, no en blanco: lee como luz, no como gloss */
    inset 0 1px 0 var(--verde-rim);
}
.toast--ok .toast__ic {
  color: var(--verde-light);
  filter: drop-shadow(0 0 7px color-mix(in srgb, var(--verde-light) 55%, transparent));
}

/* --- Neutro / error: vidrio OSCURO translúcido --- */
.toast--info { background: rgba(20, 20, 23, 0.5); }
.toast--error {
  background:
    linear-gradient(135deg,
      color-mix(in srgb, var(--semaforo-rojo) 24%, transparent),
      color-mix(in srgb, var(--semaforo-rojo) 14%, transparent)),
    rgba(11, 11, 13, 0.28);
  border-color: color-mix(in srgb, var(--semaforo-rojo) 42%, transparent);
}
.toast--error .toast__ic { color: var(--semaforo-rojo); }

/* Susurro: baja desde arriba tras guardar un gasto. Vidrio + spark de IA;
   tocarlo abre el chat, la × lo descarta, y se va solo a los ~7s. */
.susurro {
  position: fixed;
  top: calc(env(safe-area-inset-top) + var(--sp-3));
  left: max(var(--sp-4), env(safe-area-inset-left));
  right: max(var(--sp-4), env(safe-area-inset-right));
  z-index: var(--z-toast);
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-2) var(--sp-3) var(--sp-3);
  border-radius: var(--r-lg);
  /* más translúcido: el ambiente cálido se cuela por detrás (más glass) */
  background: rgba(19, 19, 22, 0.5);
  border: 1px solid var(--glass-nav-line);
  box-shadow: var(--sh-md);
  -webkit-backdrop-filter: blur(30px) saturate(1.6);
  backdrop-filter: blur(30px) saturate(1.6);
  cursor: pointer;
  /* entrada suave: baja y aparece (sin scale, que jankea con el blur en iOS) */
  animation: susurroIn 0.44s var(--ease) both;
  will-change: transform, opacity;
}
.susurro.is-leaving { animation: susurroOut 0.34s var(--ease-in-out) both; }  /* salida: sube y desaparece */
@keyframes susurroIn { from { opacity: 0; transform: translateY(-28px); } to { opacity: 1; transform: none; } }
@keyframes susurroOut { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-28px); } }
.susurro__spark {
  flex: none; width: 32px; height: 32px;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  background: var(--grad-cta); color: var(--text-inverse);
  box-shadow: var(--sh-ia);
}
.susurro__spark svg { width: 18px; height: 18px; }
.susurro__txt { flex: 1 1 auto; min-width: 0; font-size: var(--fs-sm); line-height: 1.4; color: var(--text-1); font-weight: var(--fw-medium); }
.susurro__x {
  flex: none; width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  color: var(--text-3); font-size: 22px; line-height: 1;
}
.susurro__x:active { color: var(--text-1); }
@media (prefers-reduced-motion: reduce) {
  .susurro, .susurro.is-leaving { animation-duration: 0.01ms; }
}

/* ============================================================
   Chip de reconciliación: "¿Este es tu pago de <fijo>? Vincular".
   Sube desde abajo, POR ENCIMA del toast (que asoma más abajo), con
   el mismo vidrio del resto de avisos. Persiste ~9s o hasta que actúes.
   ============================================================ */
.vinculo-chip {
  position: fixed;
  left: 50%;
  /* apilado sobre el toast (toast + su alto de una línea + aire) */
  bottom: calc(var(--dock-b) + var(--nav-h) + 30px + var(--sp-4) + 66px);  /* v60: sin --vp-piso */
  transform: translate(-50%, 0);
  z-index: var(--z-toast);
  width: min(440px, calc(100vw - var(--sp-5)));
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-3);
  border-radius: var(--r-lg);
  background: rgba(19, 19, 22, 0.6);
  border: 1px solid var(--line-2);
  box-shadow: var(--sh-md);
  -webkit-backdrop-filter: blur(30px) saturate(1.6);
  backdrop-filter: blur(30px) saturate(1.6);
  color: var(--text-1);
  animation: vinculoIn 0.4s var(--ease) both;
  will-change: transform, opacity;
}
.vinculo-chip.is-leaving { animation: vinculoOut 0.32s var(--ease-in-out) both; }
@keyframes vinculoIn  { from { opacity: 0; transform: translate(-50%, 16px); } to { opacity: 1; transform: translate(-50%, 0); } }
@keyframes vinculoOut { from { opacity: 1; transform: translate(-50%, 0); } to { opacity: 0; transform: translate(-50%, 16px); } }
.vinculo-chip__ic {
  flex: none; width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--accent-soft); color: var(--accent);
}
.vinculo-chip__ic svg { width: 18px; height: 18px; }
.vinculo-chip__txt {
  flex: 1 1 auto; min-width: 0; margin: 0;
  font-size: var(--fs-sm); line-height: 1.3; color: var(--text-2);
}
.vinculo-chip__txt strong { color: var(--text-1); font-weight: var(--fw-semibold); }
.vinculo-chip__act {
  flex: none; height: 34px; padding: 0 var(--sp-3);
  border: 1px solid var(--fab-rim); border-radius: var(--r-md);
  background: var(--fab-grad); color: var(--text-inverse);
  font-size: var(--fs-xs); font-weight: var(--fw-bold); cursor: pointer;
  transition: transform var(--dur-fast) var(--ease);
}
.vinculo-chip__act:active { transform: scale(0.96); }
.vinculo-chip__x {
  flex: none; width: 28px; height: 28px;
  display: grid; place-items: center;
  border: none; background: transparent;
  color: var(--text-3); font-size: 20px; line-height: 1; cursor: pointer;
  border-radius: var(--r-full);
}
.vinculo-chip__x:active { color: var(--text-1); }
@media (prefers-reduced-motion: reduce) {
  .vinculo-chip, .vinculo-chip.is-leaving { animation-duration: 0.01ms; }
}

/* ============================================================
   Overlay ligero (confirmar / menú de acciones)
   ============================================================ */
.ov-scrim {
  position: fixed; inset: 0;
  z-index: var(--z-sheet);
  background: var(--scrim);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  display: flex; align-items: flex-end; justify-content: center;
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.ov-scrim.is-open { opacity: 1; }
.ov-panel {
  position: relative;
  width: 100%;
  max-width: var(--page-max);
  background: linear-gradient(180deg, var(--bg-2), var(--bg-1));
  border-top-left-radius: var(--r-2xl);
  border-top-right-radius: var(--r-2xl);
  border-top: 1px solid var(--line-2);
  box-shadow: var(--sh-sheet);
  padding: var(--sp-3) max(var(--sp-5), env(safe-area-inset-left))
           calc(var(--safe-b) + var(--sp-5)) max(var(--sp-5), env(safe-area-inset-right));
  max-height: 80dvh;
  overflow-y: auto;
  transform: translateY(100%);
  transition: transform var(--dur-slow) var(--ease);
}
.ov-scrim.is-open .ov-panel { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) { .ov-panel { transition: transform var(--dur-fast) linear; } }
.ov-grip { width: 40px; height: 4px; border-radius: var(--r-full); background: var(--line-3); margin: var(--sp-1) auto var(--sp-4); }
.ov-close { position: absolute; top: var(--sp-3); right: max(var(--sp-3), env(safe-area-inset-right)); color: var(--text-3); }
.ov-title { font-size: var(--fs-h3); font-weight: var(--fw-bold); color: var(--text-1); letter-spacing: -0.01em; }
.ov-title--menu { margin-bottom: var(--sp-3); padding-right: var(--sp-8); }
.ov-text { font-size: var(--fs-sm); color: var(--text-2); margin-top: var(--sp-2); line-height: 1.45; }
.ov-actions { display: flex; gap: var(--sp-3); margin-top: var(--sp-5); }
.ov-list { display: flex; flex-direction: column; gap: 2px; max-height: 60dvh; overflow-y: auto; }
.ov-item {
  display: flex; align-items: center; gap: var(--sp-3);
  width: 100%; min-height: 52px; padding: var(--sp-3) var(--sp-3);
  border-radius: var(--r-sm);
  color: var(--text-1); font-size: var(--fs-body); font-weight: var(--fw-medium);
  text-align: left;
  transition: background var(--dur-fast) var(--ease);
}
.ov-item:hover { background: var(--glass-2); }
.ov-item:active { background: var(--glass-3); }
.ov-item__ic { width: 30px; height: 30px; flex: 0 0 auto; display: grid; place-items: center; color: var(--text-2); }
.ov-item__ic svg { width: 20px; height: 20px; }
.ov-item--danger { color: var(--semaforo-rojo); }
.ov-item--danger .ov-item__ic { color: var(--semaforo-rojo); }

/* ---- Hoja de fecha (fecha-sheet) ---- */
.date-opt { justify-content: flex-start; }
.date-opt__title { flex: 0 0 auto; font-weight: var(--fw-semibold); }
.date-opt__sub { margin-left: auto; color: var(--text-3); font-size: var(--fs-sm); }
.date-opt__check {
  flex: 0 0 auto;
  width: 22px; height: 22px;
  margin-left: var(--sp-2);
  display: grid; place-items: center;
  color: var(--text-1);
  opacity: 0;
}
.date-opt__check svg { width: 20px; height: 20px; }
.date-opt.is-sel { background: var(--glass-3); }
.date-opt.is-sel .date-opt__title,
.date-opt.is-sel .date-opt__sub { color: var(--text-1); }
.date-opt.is-sel .date-opt__check { opacity: 1; }

.date-sep { height: 1px; background: var(--line-2); margin: var(--sp-3) 0; }

/* La fila "Elegir otra fecha" lleva un <input type="date"> transparente
   ENCIMA: tocar la fila abre la rueda nativa de iOS. */
.date-otra { position: relative; }
.date-otra .ov-item__label { flex: 1 1 auto; }
.date-otra__val { color: var(--text-3); font-size: var(--fs-sm); }
.date-otra__input {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  margin: 0; padding: 0; border: 0;
  opacity: 0;
  -webkit-appearance: none; appearance: none;
  cursor: pointer;
}
.date-actual {
  margin-top: var(--sp-3);
  text-align: center;
  font-size: var(--fs-sm);
  color: var(--text-3);
}
.date-actual::first-letter { text-transform: uppercase; }

/* ============================================================
   Movimientos — búsqueda + filtros + lista agrupada
   ============================================================ */
/* Campo de búsqueda libre (concepto, monto, categoría, cuenta). */
.mov-search {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 46px;
  padding: 0 var(--sp-2) 0 var(--sp-4);
  margin-bottom: var(--sp-4);
  border-radius: var(--r-md);
  background: var(--glass-1);
  border: 1px solid transparent;   /* el hairline lo pinta el borde vivo */
  transition: border-color var(--dur-fast) var(--ease);
}
.mov-search[hidden] { display: none; }
/* sin realce de borde al enfocar (el auto-focus no debe "marcar" el campo) */
.mov-search__ic { flex: 0 0 auto; display: grid; place-items: center; color: var(--text-3); }
.mov-search__ic svg { width: 18px; height: 18px; }
.mov-search__input {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  background: none;
  outline: none;
  color: var(--text-1);
  font-family: var(--font-ui);
  font-size: var(--fs-input); /* >=16px: evita zoom iOS */
}
.mov-search__input::placeholder { color: var(--text-3); }
.mov-search__clear {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: var(--r-full);
  color: var(--text-3);
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.mov-search__clear:hover { color: var(--text-1); background: var(--glass-2); }
.mov-search__clear[hidden] { display: none; }
.mov-search__clear svg { width: 15px; height: 15px; }

.mov-filters {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  padding-bottom: var(--sp-2);
  margin-bottom: var(--sp-3);
  /* edge-to-edge: rompe el padding lateral de .view para scrollear hasta el
     borde de la pantalla (los chips ya no se cortan antes). */
  margin-left: calc(-1 * max(var(--sp-5), env(safe-area-inset-left)));
  margin-right: calc(-1 * max(var(--sp-5), env(safe-area-inset-right)));
  padding-left: max(var(--sp-5), env(safe-area-inset-left));
  padding-right: max(var(--sp-5), env(safe-area-inset-right));
}
.mov-filters::-webkit-scrollbar { display: none; }
.mfilter {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 36px;
  padding: 0 var(--sp-3);
  border-radius: var(--r-full);
  background: var(--glass-1);
  border: 1px solid var(--line-2);
  color: var(--text-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.mfilter:active { transform: scale(0.97); }
.mfilter.is-sel { background: var(--text-1); border-color: transparent; color: var(--text-inverse); }
.mfilter--hormiga.is-sel { background: var(--semaforo-ambar-bg); border-color: var(--semaforo-ambar-line); color: var(--semaforo-ambar); }
.mfilter__dot { width: 8px; height: 8px; border-radius: var(--r-full); background: var(--tint); }
.mfilter-sep { flex: 0 0 auto; width: 1px; height: 20px; background: var(--line-2); margin: 0 2px; }
.mfilter--mes { font-weight: var(--fw-bold); }

.mov-list { display: flex; flex-direction: column; gap: var(--sp-5); }
/* Encabezado de mes: separa Julio de Agosto al scrollear el historial. */
.mov-month {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3);
  margin: var(--sp-4) var(--sp-1) 0;
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--line-2);
}
.mov-list > .mov-month:first-child { margin-top: 0; }
.mov-month__label {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-bold);
  letter-spacing: -0.015em;
  color: var(--text-1);
}
.mov-month__total { font-size: var(--fs-sm); color: var(--text-2); font-variant-numeric: tabular-nums; }
.mov-day__head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: var(--sp-2); padding: 0 var(--sp-1);
}
.mov-day__label { font-size: var(--fs-sm); font-weight: var(--fw-bold); color: var(--text-1); letter-spacing: -0.01em; }
.mov-day__total { font-size: var(--fs-xs); color: var(--text-3); font-variant-numeric: tabular-nums; }
.mov-day__list { display: flex; flex-direction: column; gap: 2px; }
.mov-row { display: flex; align-items: stretch; gap: var(--sp-1); }
.mov-row__main {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3);
  border-radius: var(--r-md);
  text-align: left;
}
.mov-row__icon {
  width: 42px; height: 42px; flex: 0 0 auto;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  /* Tinte MUY sutil de la categoría (--tint lo aporta .cat--*): fondo al 12%
     y glifo en un tono apagado. Un toque de color sin gritar. */
  background: color-mix(in srgb, var(--tint, var(--text-3)) 18%, transparent);
  color: color-mix(in srgb, var(--tint, var(--text-1)) 74%, var(--text-1));
}
.mov-row__icon svg { width: 21px; height: 21px; }
.mov-row__body { flex: 1 1 auto; min-width: 0; }
.mov-row__title {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-body); font-weight: var(--fw-semibold); color: var(--text-1);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mov-row__meta { font-size: var(--fs-xs); color: var(--text-3); margin-top: 1px; display: flex; align-items: center; gap: var(--sp-2); }
.mov-row__amount {
  flex: 0 0 auto;
  font-family: var(--font-num); font-variant-numeric: tabular-nums;
  font-weight: var(--fw-semibold); font-size: var(--fs-body); color: var(--text-1);
}
.mov-row__amount.is-in { color: var(--semaforo-verde); }
/* 3-dots sin contenedor: solo el ícono (visual más liviano) */
.mov-row__more { width: 40px; flex: 0 0 auto; color: var(--text-3); align-self: center; background: none; }
.mov-row__more:hover { background: none; color: var(--text-2); }
.mov-row__more:active { background: none; }
.src-badge {
  font-size: 9.5px; font-weight: var(--fw-bold); letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--text-3); background: var(--glass-2); border: 1px solid var(--line-1);
  border-radius: var(--r-full); padding: 1px 6px;
}
.hormiga-dot { width: 7px; height: 7px; border-radius: var(--r-full); background: var(--semaforo-ambar); flex: 0 0 auto; }

.mov-nores { text-align: center; padding: var(--sp-7) var(--sp-4); color: var(--text-3); display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); }
.mov-nores p { font-size: var(--fs-sm); }
.mov-error { padding: var(--sp-6); color: var(--semaforo-rojo); font-size: var(--fs-sm); text-align: center; }

/* ============================================================
   Registrar — segmented Gasto/Ingreso + modo Ingreso
   ============================================================ */
.seg {
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--seg-cols, 2), 1fr);
  gap: 3px;
  padding: 3px;
  margin: var(--sp-2) 0 var(--sp-4);
  border-radius: var(--r-full);
  background: var(--glass-2);
  border: 1px solid transparent;
}
/* La cuenta de columnas va por clase y no por style inline: la CSP prohíbe
   `style="..."` en el marcado. */
.seg--3 { --seg-cols: 3; }

/* Material HUNDIDO: el control se mete en el canvas en vez de posarse encima.
   Antes llevaba el vidrio del dock tal cual (--glass-nav opaco + borde
   --glass-nav-line + --sh-nav), y el resultado era una caja oscura con marco y
   sombra propia flotando sobre el morado: se leía como una pieza pegada, no
   como parte del fondo. El dock puede permitírselo porque flota de verdad,
   anclado al viewport y por encima del contenido; este control vive DENTRO del
   lienzo y tiene que pertenecerle.

   Los tres cambios van juntos y por eso el marco desaparece: el velo oscurece
   en el propio tono violeta (--glass-hundido), el borde baja a un hairline
   apenas insinuado y se va la sombra, que era lo que más lo despegaba. */
.seg--dock {
  background: var(--glass-hundido);
  border-color: var(--line-1);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(1.15);
  backdrop-filter: blur(var(--blur)) saturate(1.15);
  box-shadow: none;
}
/* Sobre el vidrio oscuro la pastilla NO va blanca sólida: gritaba y rompía la
   calma del resto del chrome. Aquí es translúcida —como el segmentado de iOS
   en oscuro— y el peso lo carga el texto, que pasa a blanco en vez de al
   inverso oscuro. El hairline la recorta contra el track, que si no se
   confunden. */
.seg--dock .seg__thumb {
  background: var(--glass-3);
  border-color: var(--line-3);
  box-shadow: var(--sh-sm);
}
.seg--dock .seg__opt.is-on { color: var(--text-1); }
/* Tres columnas aprietan, pero no tanto: a 14px "Mis productos" cabe de sobra
   en un móvil normal, y bajarle el punto hacía que el mismo control se leyera
   distinto en la cartera que en Hoy sin una razón que lo justificara. El
   descenso se reserva para pantallas donde la etiqueta sí se partiría. */
.seg--3 .seg__opt { padding: 0 2px; }
@media (max-width: 359px) {
  .seg--3 .seg__opt {
    font-size: var(--fs-xs);
    letter-spacing: -0.01em;
  }
}
/* Pill deslizante (posición/ancho por JS: colocarThumb). Material glossy coral
   (Gasto) que se vuelve verde glossy (Ingreso) — mismo brillo/gradiente. */
.seg__thumb {
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 0;
  width: 0;
  border-radius: var(--r-full);
  background: var(--text-1);
  border: 1px solid transparent;
  box-shadow: var(--sh-sm);
  transform: translateX(0);
  transition: transform var(--dur) var(--ease),
              background var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
  pointer-events: none;
  z-index: 0;
}
.seg--ingreso .seg__thumb {
  background: var(--verde-grad);
  border-color: var(--verde-rim);
  box-shadow: var(--sh-chip-sel-verde);
}
.seg__opt {
  position: relative;
  z-index: 1;
  min-height: 40px;
  /* flex para poder anteponer un icono; sin él centra igual que antes */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border-radius: var(--r-full);
  border: none;
  background: transparent;
  color: var(--text-2);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  transition: color var(--dur-fast) var(--ease);
}
/* El icono hereda el color del texto, así que se enciende con la opción. */
.seg__ico { display: grid; place-items: center; flex: none; }
.seg__ico svg { width: 16px; height: 16px; display: block; }
.seg__opt:active { transform: scale(0.98); }
/* seleccionado: texto blanco sobre el pill glossy (coral o verde) */
.seg__opt.is-on { color: var(--text-inverse); }
/* Seg ESTÁTICO (sin pill deslizante, p. ej. Fijo exacto / Valor variable): la
   opción activa se pinta directo con el material coral, porque no hay thumb
   detrás que dé el fondo. Sin esto, el texto text-inverse (oscuro) queda sobre
   el fondo oscuro del seg = ilegible. */
/* "Estático" = sin pastilla deslizante (solo dos opciones que se conmutan, sin
   JS que mueva un thumb), así que la opción activa lleva puesto el material DEL
   thumb en lugar de moverse uno.

   Antes se pintaba con el gradiente del FAB: una pastilla morada sólida con
   texto oscuro, que no se parecía a ningún otro segmentado de la app y además
   le daba a una elección de formulario el mismo peso visual que al botón de
   acción principal. Ahora es el mismo vidrio translúcido sobre track hundido
   que el de Hoy y el de la cartera — el peso lo carga el texto, que pasa a
   blanco. */
.seg--estatico .seg__opt.is-on {
  background: var(--glass-3);
  border: 1px solid var(--line-3);
  box-shadow: var(--sh-sm);
  color: var(--text-1);
}
@media (prefers-reduced-motion: reduce) {
  .seg__thumb { transition: none; }
}

/* monto en modo Ingreso: verde para dejar claro que SUMA */
.amt--in .amt__cur { color: var(--semaforo-verde); }
.amt--in.is-active { border-bottom-color: var(--semaforo-verde-line); }
.amt--in .amt__value { color: var(--semaforo-verde); }

/* aviso cuando no hay fuentes de negocio configuradas */
.acct-empty {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  background: var(--glass-1);
  border: 1px dashed var(--line-2);
}
.acct-empty__txt { font-size: var(--fs-sm); color: var(--text-2); line-height: 1.45; }

/* <select> con look de campo (dropdown del crédito vinculado) */
.field__select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: var(--sp-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' fill='none' stroke='%239AA0AE' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-3) center;
  background-size: 18px;
}
