/* ============================================================================
   Layout de la app real (a diferencia de styles.css, que trae los componentes
   visuales del prototipo). Acá NO hay marco de celular de mentira: la app
   ocupa toda la pantalla en el celular, y queda centrada con un ancho máximo
   prolijo en desktop/tablet.
   ============================================================================ */

html, body {
  height: 100%;
  /* Evita el "rebote" de scroll (pull-to-refresh / rubber-band) típico de
     Chrome/WebView en Android — sin esto, un toque de más arrastrando hacia
     abajo dejaba asomar por una fracción de segundo el fondo real de <body>
     (el crema de --bg) arriba de todo, incluso en pantallas como el login
     que no tienen nada para scrollear. Se ve como un recuadro blanco en las
     esquinas de arriba (bug reportado por Marcelo el 25/09). */
  overscroll-behavior-y: none;
}

/* Cualquier elemento con el atributo "hidden" tiene que quedar oculto de
   verdad, incluso cuando otra regla de más abajo (como .auth-loading o
   .app-shell) le pone display:flex a propósito. Sin este !important, esas
   reglas le ganan a [hidden] y la pantalla de carga queda trabada. */
[hidden] {
  display: none !important;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

.app-shell {
  display: flex;
  flex-direction: column;
  flex: 1;
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  min-height: 100dvh;
  background: var(--bg);
}

.app-shell .topbar {
  padding: calc(14px + env(safe-area-inset-top, 0px)) 18px 10px;
}

.app-shell .app-content {
  padding: 6px 18px 14px;
}

.app-shell .tabbar {
  padding: 8px 6px calc(8px + env(safe-area-inset-bottom, 0px));
}

.logout-btn {
  /* margin-left:auto — para que quede pegado a la derecha tanto con .greet
     visible (Inicio/Alertas) como oculto (Club/Perfil, ver cambiarTab() en
     app.js); si no, con .greet oculto el justify-content:space-between de
     .topbar lo empuja de vuelta a la izquierda. */
  margin-left: auto;
  border: none;
  background: var(--surface-2);
  color: var(--ink-soft);
  font-size: 11px;
  font-weight: 700;
  padding: 7px 11px;
  border-radius: 10px;
  cursor: pointer;
  font-family: "Poppins", sans-serif;
}

/* ---------- Pantalla de login / registro ---------- */
.auth-screen {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  padding: 32px 24px calc(32px + env(safe-area-inset-bottom, 0px));
  min-height: 100dvh;
  background: linear-gradient(160deg, var(--accent), var(--brand) 55%, var(--brand-strong));
  text-align: center;
}

/* Además del overscroll-behavior de arriba (que evita el rebote en sí),
   esto es un segundo cinturón de seguridad: mientras se ve el login o la
   pantalla de "verificá tu email" (mostrarLogin()/mostrarVerificacionEmail()
   en app.js les agregan esta clase a <body>, mostrarApp() se la saca), el
   fondo de <body> pasa a ser EL MISMO degradé de .auth-screen en vez del
   crema de --bg — así, si por lo que sea llega a asomar un pixel de <body>
   detrás (esquinas redondeadas del celular, alguna barra de estado que no
   pinta bien encima), se mimetiza en vez de verse como un recuadro blanco. */
body.pantalla-auth {
  background: linear-gradient(160deg, var(--accent), var(--brand) 55%, var(--brand-strong));
}

.auth-mark {
  width: 118px;
  filter: drop-shadow(0 14px 20px rgba(60, 40, 0, .3));
}
.auth-mark img { width: 100%; height: auto; display: block; }

.auth-title {
  font-family: "Chewy", "Poppins", cursive;
  font-size: 30px;
  color: #fff;
  text-shadow: 0 2px 10px rgba(0, 0, 0, .18);
  line-height: 1.05;
}
/* Marca ™ (trámite de registro en curso, todavía no concedido — ver charla
   con Marcelo del 03/10/26). Chica y elevada a propósito: en el tamaño real
   del texto de al lado (que suele ser una tipografía grande/redondeada como
   Chewy) un ™ sin achicar queda pesado y se come la lectura del nombre. */
.tm-mark {
  font-family: "Poppins", sans-serif;
  font-weight: 400;
  font-size: .42em;
  vertical-align: super;
  opacity: .85;
  margin-left: 2px;
}
.auth-sub {
  font-family: "Poppins", sans-serif;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #fff;
  opacity: .95;
  margin-top: -12px;
}

.auth-card {
  width: 100%;
  max-width: 340px;
  background: var(--surface);
  border-radius: 22px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  box-shadow: 0 20px 40px -20px rgba(0, 0, 0, .35);
  text-align: left;
}

.auth-toggle {
  display: flex;
  background: var(--surface-2);
  border-radius: 99px;
  padding: 3px;
  gap: 2px;
}
.auth-toggle button {
  flex: 1;
  border: none;
  background: none;
  padding: 8px 6px;
  border-radius: 99px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink-soft);
  cursor: pointer;
  font-family: "Poppins", sans-serif;
}
.auth-toggle button.active {
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 2px 8px -3px var(--shadow);
}

.auth-card .form-field input {
  width: 100%;
}

/* Pantalla de bloqueo "verificá tu email" (#verificarEmailScreen): reusa
   .auth-card, pero con un h3/p sueltos en vez del <form> de login/registro
   — sin esto, los márgenes por defecto del navegador se sumarían al gap del
   flex column y quedaría todo separado de más. */
.auth-card h3 { margin: 0; font-size: 16.5px; }
.auth-card > p { margin: 0; font-size: 12.5px; color: var(--ink-soft); line-height: 1.5; }
.auth-card > p strong { color: var(--ink); }

.auth-submit {
  border: none;
  background: linear-gradient(120deg, var(--brand), var(--violet));
  color: #fff;
  font-family: "Poppins", sans-serif;
  font-weight: 700;
  font-size: 14px;
  padding: 13px;
  border-radius: 14px;
  cursor: pointer;
  margin-top: 4px;
}
.auth-submit:disabled { opacity: .6; cursor: default; }

.auth-error {
  font-size: 12px;
  color: #B3261E;
  background: #FBE9E7;
  border-radius: 10px;
  padding: 9px 11px;
  line-height: 1.4;
}
.auth-error[hidden] { display: none; }

.auth-info {
  font-size: 12px;
  color: #11676A;
  background: #E3F2F1;
  border-radius: 10px;
  padding: 9px 11px;
  line-height: 1.4;
}
.auth-info[hidden] { display: none; }

.auth-forgot {
  align-self: flex-end;
  margin-top: -6px;
  border: none;
  background: none;
  padding: 0;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-soft);
  text-decoration: underline;
  cursor: pointer;
  font-family: "Poppins", sans-serif;
}
.auth-forgot[hidden] { display: none; }

/* Link de "Baja / Arrepentimiento" (Disposición 954/2025) — mismo look que
   .auth-forgot pero SIN su margin-top negativo (pensado para pegarse justo
   debajo del campo de contraseña), porque este va después, al final del
   formulario, y ese margen negativo lo pegaría feo contra lo de arriba. */
.auth-baja-link {
  align-self: center;
  margin-top: 4px;
  border: none;
  background: none;
  padding: 0;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-soft);
  text-decoration: underline;
  cursor: pointer;
  font-family: "Poppins", sans-serif;
}

.auth-legal-check {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-soft);
  text-align: left;
  margin-top: -2px;
  cursor: pointer;
}
.auth-legal-check input[type="checkbox"] {
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 1px;
  accent-color: var(--brand);
}
.auth-legal-check a { color: var(--teal-strong); font-weight: 600; text-decoration: none; }
.auth-legal-check a:hover { text-decoration: underline; }
.auth-legal-check[hidden] { display: none; }

.perfil-legal-links {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin-top: 14px;
  font-size: 11.5px;
  color: var(--ink-soft);
}
.perfil-legal-links a { color: var(--ink-soft); text-decoration: underline; }

.auth-loading {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100dvh;
  color: var(--ink-soft);
  font-size: 13px;
}

/* Campo de contraseña con el ojito para mostrar/ocultar lo que se escribió. */
.password-field {
  position: relative;
  width: 100%;
}
.password-field input {
  width: 100%;
  box-sizing: border-box;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  padding: 10px 38px 10px 12px; /* el padding-right deja lugar para que el ojito no tape el texto */
  /* 16px: mismo motivo que .chat-input más abajo (evita el zoom automático
     de iOS al enfocar el campo). */
  font-size: 16px;
  font-family: inherit;
  color: var(--ink);
  background: var(--surface);
  outline: none;
}
.password-field input:focus { border-color: var(--brand); }
.password-toggle {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  border: none;
  background: none;
  font-size: 16px;
  line-height: 1;
  padding: 6px;
  cursor: pointer;
  opacity: .65;
}
.password-toggle:hover { opacity: 1; }

/* Campo "readonly" del perfil: se ve apagado para dejar claro que hay que
   tocar "Editar" (y confirmar la contraseña) antes de poder cambiarlo. */
.field .value[readonly] {
  background: var(--surface-2);
  color: var(--ink-soft);
  cursor: default;
}

.reauth-box {
  margin-top: 14px;
  background: var(--surface-2);
  border-radius: 14px;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.reauth-box[hidden] { display: none; }
.reauth-box label {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
}
.reauth-box input {
  width: 100%;
}
.reauth-actions {
  display: flex;
  gap: 8px;
  margin-top: 2px;
}
.reauth-actions button { flex: 1; }

.geo-status {
  font-size: 11px;
  color: var(--ink-faint);
  line-height: 1.4;
}

/* ---------- Avistamientos ("👀 Lo vi") ---------- */
.avistamientos-box {
  background: var(--surface-2);
  border-radius: 14px;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.avistamientos-box[hidden] { display: none; }
.avistamientos-titulo {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink);
}
.avistamientos-lista {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.avistamiento-item {
  border-bottom: 1px solid var(--line);
  padding-bottom: 8px;
}
.avistamiento-item:last-child { border-bottom: none; padding-bottom: 0; }
.avistamiento-cabecera {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
  font-size: 11.5px;
  color: var(--ink-soft);
  line-height: 1.4;
}
.avistamiento-cabecera b { color: var(--ink); }
.avistamiento-texto { flex: 1; }
.avistamiento-avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  background: var(--surface-2);
  font-size: 13px;
}
.avistamiento-avatar img { width: 100%; height: 100%; object-fit: cover; }
.avistamiento-chevron { color: var(--ink-faint); font-size: 10px; flex-shrink: 0; }

/* flex-basis:100% — fuerza a estos dos (hijos directos de .alert-item, que
   ahora tiene flex-wrap, ver styles.css) a su propia línea de ancho
   completo, en vez de competir por el espacio angosto que deja el avatar de
   52px. El margin-top de antes ya no hace falta: el gap de .alert-item
   separa parejo la fila del avatar, el botón y el panel. */
.alert-lovi-btn {
  flex-basis: 100%;
  min-width: 0;
  width: 100%;
  font-size: 12.5px;
  padding: 8px;
}
.alert-lovi-panel {
  flex-basis: 100%;
  /* Sin esto, al ser hijo directo de .alert-item (flex), por default no se
     achica por debajo del ancho mínimo de su contenido — y el renglón del
     chat (cámara + campo + Enviar) terminaba empujado fuera de la pantalla
     en vez de acomodarse al ancho de la tarjeta (bug de Marcelo, oct 2026,
     justo después de ensancharlo). .alert-body ya tenía este mismo
     min-width:0 — se perdió al sacar el panel de adentro suyo. */
  min-width: 0;
  background: var(--surface-2);
  border-radius: 12px;
  /* Menos padding horizontal que antes (era 10px parejo): .alert-item ya
     aporta 12px propios, así que duplicarlo angostaba el chat de más — el
     motivo original de este pedido (oct 2026). */
  padding: 10px 6px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.alert-lovi-panel[hidden] { display: none; }
.alert-lovi-panel label {
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-soft);
}
.alert-lovi-nota {
  width: 100%;
  box-sizing: border-box;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  padding: 10px 12px;
  /* 16px: mismo motivo que .chat-input (evita el zoom automático de iOS). */
  font-size: 16px;
  font-family: inherit;
  color: var(--ink);
  background: var(--surface);
  outline: none;
}
.alert-lovi-nota:focus { border-color: var(--brand); }
.alert-lovi-foto-label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-soft);
}
.alert-lovi-foto-label[hidden] { display: none; }
.alert-lovi-foto { font-size: 11.5px; color: var(--ink-soft); }
.alert-lovi-confirmar { font-size: 12.5px; padding: 9px; }

/* ---------- Chat enmascarado de un avistamiento ("Encuentro Seguro") ---------- */
.chat-hilo-contenedor {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 6px;
  max-width: 100%;
  overflow-x: hidden;
}
.chat-hilo-contenedor[hidden] { display: none; }
.chat-mensajes {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 180px;
  overflow-y: auto;
  padding: 2px;
}
.chat-burbuja {
  max-width: 82%;
  padding: 7px 10px;
  border-radius: 12px;
  font-size: 12px;
  line-height: 1.35;
  word-break: break-word;
}
.chat-burbuja.mia {
  align-self: flex-end;
  /* Color fijo (no una variable de tema) a propósito: el naranja de marca
     con letras oscuras (como estaba antes) se lee mal en una burbuja chica.
     Este verde azulado oscuro + letras blancas se ve bien tanto en modo
     claro como oscuro, sin depender de qué tema tenga el celular. */
  background: #11676A;
  color: #FFFFFF;
  border-bottom-right-radius: 3px;
}
.chat-burbuja.otra {
  align-self: flex-start;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink);
  border-bottom-left-radius: 3px;
}
.chat-hora {
  display: block;
  margin-top: 2px;
  font-size: 9.5px;
  text-align: right;
}
.chat-burbuja.mia .chat-hora { color: rgba(255, 255, 255, 0.75); }
.chat-burbuja.otra .chat-hora { color: var(--ink-soft); }
.chat-foto {
  display: block;
  max-width: 100%;
  max-height: 160px;
  border-radius: 8px;
  margin-bottom: 4px;
}
.chat-escribiendo {
  font-size: 11px;
  font-style: italic;
  color: var(--ink-soft);
  padding: 0 2px;
}
.chat-escribiendo[hidden] { display: none; }
/* align-items: flex-end — así los botones de foto/enviar quedan anclados
   abajo en vez de estirarse en altura cuando .chat-input crece a 2-3 líneas
   (ver más abajo). */
.chat-input-row { display: flex; gap: 6px; max-width: 100%; align-items: flex-end; }
.chat-input {
  flex: 1 1 0%;
  /* Sin esto, en algunos navegadores (Chrome/WebView de Android) el campo de
     texto NO se achica dentro del flex: crece con lo que vas escribiendo y
     empuja el botón de foto y el de "Enviar" fuera de la pantalla, dejándolos
     inalcanzables. min-width:0 le permite reducirse hasta el ancho que
     sobra, que es lo que se espera de un flex item con flex:1. */
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 8px 10px;
  /* 16px es el mínimo que evita que iOS Safari haga zoom automático al
     tocar el campo para escribir (lo hace con cualquier letra por debajo
     de ese tamaño) — reportado por Victoria en su iPhone, sept 2026. */
  font-size: 16px;
  background: var(--surface);
  color: var(--ink);
  /* .chat-input es un <textarea> (ver renderHiloChat en app.js — el cambio
     de <input> a <textarea> es justo lo que evita que el navegador ofrezca
     autocompletar mail/contraseña acá). Antes se forzaba con
     white-space:nowrap + overflow:hidden a verse como un campo de una sola
     línea con scroll horizontal — pero un <textarea> no sigue el cursor con
     scroll horizontal de forma confiable en todos los navegadores (falla en
     Chrome/WebView de Android, reportado por Marcelo oct 2026: el texto se
     "escondía" al escribir, más notorio todavía después de subir la letra a
     16px). Ahora se deja crecer en altura con el texto, como cualquier chat
     de verdad: baja de línea normal, autoGrowChatInput() en app.js lo agranda
     hasta max-height y de ahí en más scrollea vertical (overflow-y:auto). */
  resize: none;
  overflow-y: auto;
  max-height: 100px;
  font-family: inherit;
  line-height: 1.3;
}
.chat-enviar { font-size: 12px; padding: 8px 12px; flex: none; }
.chat-foto-btn { font-size: 14px; padding: 8px 10px; flex: none; }

/* ---------- Flyer imprimible ---------- */
.flyer-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 10px;
}
.flyer-actions[hidden] { display: none; }
.flyer-actions .cta.outline {
  border: 1.5px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  text-decoration: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ⚠️ El diseño del cartel imprimible (.flyer-print-view, .flyer-photo,
   .flyer-name, .flyer-phone, .flyer-qr, etc.) vive ÚNICAMENTE en styles.css
   — acá había una copia vieja, del prototipo original (foto circular,
   textos chiquitos, y el viejo truco de "visibility:hidden en todo el body"
   que además duplicaba el cartel al imprimir). Como app.css se carga
   DESPUÉS de styles.css en index.html, esa copia vieja le ganaba en el
   cascade a todo el rediseño del cartel — es decir, lo que se imprimía en
   la práctica NO era el diseño nuevo, aunque en pantalla (y en cualquier
   vista previa que no cargara este archivo) sí se viera bien. La sacamos de
   acá para que quede un solo lugar dueño de ese diseño. Si en algún momento
   hay que tocar el cartel de nuevo, es en styles.css. */

/* ---------- Mapa real (Mapbox) ---------- */
.map-box {
  width: 100%;
  height: 170px;
  border-radius: 16px;
  overflow: hidden;
  background: var(--surface-2);
}
.map-box.tall { height: 220px; }
.map-box[hidden] { display: none; }

/* El badge "📍 Última ubicación" viene del prototipo original, donde flotaba
   con position:absolute pegado a una esquina del marco de celular de mentira
   (ver .map-badge en styles.css). Acá, al no existir ese marco, esa misma
   regla lo despegaba de #mapaInicio y lo dejaba fijo abajo de TODA la
   pantalla, tapando la barra de navegación. Lo volvemos a poner en el flujo
   normal, como una fila chica justo debajo del mapa. */
.map-badge {
  position: static;
  display: flex;
  align-items: center;
  width: auto;
  margin-top: 8px;
}
.map-badge[hidden] { display: none; }

.map-pin {
  width: 26px;
  height: 26px;
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  border: 3px solid #fff;
  box-shadow: 0 4px 10px -3px rgba(0, 0, 0, .45);
  cursor: pointer;
}

/* ---------- Pin arrastrable ("¿Dónde se perdió?") ----------
   Mismo pin de siempre (.map-pin) pero más grande — se agarra más fácil con
   el dedo en un celular — y con un cursor que deja claro que se puede
   arrastrar (ver crearMapaAjustable() en map.js). */
.map-pin-ajustable {
  width: 34px;
  height: 34px;
  cursor: grab;
}
.map-pin-ajustable:active { cursor: grabbing; }

/* ---------- Buscador de lugar (mismo modal) ---------- */
.buscar-lugar-box { position: relative; }
.buscar-lugar-input {
  border: 1.5px solid var(--line); border-radius: 12px; padding: 10px 12px;
  /* 16px: mismo motivo que .chat-input (evita el zoom automático de iOS). */
  font-size: 16px; font-family: inherit; color: var(--ink);
  background: var(--surface); outline: none;
  width: 100%; box-sizing: border-box;
}
.buscar-lugar-input:focus { border-color: var(--brand); }
.buscar-lugar-resultados {
  position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 5;
  background: var(--surface); border: 1.5px solid var(--line); border-radius: 12px;
  box-shadow: 0 10px 24px -10px var(--shadow); overflow: hidden; max-height: 220px; overflow-y: auto;
}
.buscar-lugar-resultados[hidden] { display: none; }
.buscar-lugar-item {
  display: block; width: 100%; text-align: left; border: none; background: none;
  padding: 10px 12px; font-size: 13px; color: var(--ink); font-family: inherit; cursor: pointer;
}
.buscar-lugar-item + .buscar-lugar-item { border-top: 1px solid var(--line); }
.buscar-lugar-item:hover, .buscar-lugar-item:focus { background: var(--surface-2); }

.map-popup {
  font-family: "Poppins", sans-serif;
  font-size: 12px;
  line-height: 1.4;
}
.map-popup b { display: block; font-size: 13px; margin-bottom: 2px; }

/* La atribución de Mapbox es obligatoria en el plan gratuito — solo la
   achicamos un poco para que no rompa el diseño en un mapa chico. */
.mapboxgl-ctrl-attrib { font-size: 9px; }
.mapboxgl-ctrl-logo { transform: scale(.8); transform-origin: bottom left; }

/* Aviso de "llegaste al límite de perros de tu plan" — se cierra solo a los
   pocos segundos (ver mostrarNotaLimitePerros() en app.js) o con la ✕. */
.limite-nota {
  margin-bottom: 8px;
  background: var(--alert-soft);
  border: 1px solid color-mix(in srgb, var(--alert) 35%, var(--line));
  border-radius: 12px;
  padding: 9px 10px 9px 12px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--ink);
  line-height: 1.4;
}
.limite-nota[hidden] { display: none; }
.limite-nota span { flex: 1; }
.limite-nota button {
  flex: none;
  border: none;
  background: none;
  font-size: 15px;
  line-height: 1;
  color: var(--ink-soft);
  cursor: pointer;
  padding: 2px 4px;
}

/* Aviso de "cupo de perros activos por plan" (06/10/26, pedido de Marcelo:
   el primer diseño con .limite-nota se veía "muy feo" — el texto se
   amontonaba en una columna angosta peleando con 3 botones en la misma
   fila). Reusa el mismo degradé que .member-card/.plan-badge (el carnet de
   Club) en vez del naranja de advertencia de .limite-nota: esto no es un
   error, es una invitación a volver a pagar, así que tiene más sentido con
   los colores de "plan" que con los de alerta. Texto arriba (ancho
   completo) y los accesos en su propia fila abajo, en vez de competir por
   espacio en una sola línea. */
.cupo-nota {
  position: relative;
  margin-bottom: 10px;
  background: linear-gradient(135deg, #8155E8, #FF5A46);
  color: #fff;
  border-radius: 16px;
  padding: 8px 18px 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  font-size: 13.5px;
  line-height: 1.55;
}
.cupo-nota[hidden] { display: none; }
/* El botón ✕ va primero en el flex column (order:-1 + align-self) para que
   ocupe su PROPIA fila arriba, en vez de superponerse al texto con
   position:absolute como antes (06/10/26: eso le robaba ancho a TODAS las
   líneas del texto, no solo a la primera, y era parte de por qué se veía
   amontonado). Así el texto de abajo tiene el ancho completo de la tarjeta. */
.cupo-nota-texto { display: block; letter-spacing: 0.1px; }
.cupo-nota-acciones {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.cupo-nota-acciones button {
  flex: none;
  background: rgba(255, 255, 255, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.45);
  color: #fff;
  font-size: 12.5px;
  font-weight: 700;
  padding: 7px 14px;
  border-radius: 99px;
  cursor: pointer;
}
.cupo-nota-cerrar {
  order: -1;
  align-self: flex-end;
  margin: 0 -8px -2px 0;
  border: none;
  background: none;
  color: #fff;
  opacity: 0.85;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  padding: 8px;
}

/* ---------- QR del collar ---------- */
.collar-qr-box {
  margin-top: 8px;
  background: var(--surface-2);
  border-radius: 14px;
  padding: 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  text-align: center;
}
.collar-qr-box[hidden] { display: none; }
.collar-qr-box img {
  width: 150px;
  height: 150px;
  border-radius: 10px;
  background: #fff;
}
.collar-qr-texto {
  font-size: 11.5px;
  color: var(--ink-soft);
  line-height: 1.4;
}
.collar-qr-box button { width: 100%; }

/* Insignia de la oferta de lanzamiento (5% con plan Gratis, primer mes) —
   ver btnVerCarnet en app.js. Toma los mismos colores "brand" (naranja) que
   ya usa el ícono 🎁 del perk de descuentos, para que se lea como la misma
   familia visual de "beneficio", distinta del carnet normal de socio pago. */
.carnet-badge {
  font-size: 11px;
  font-weight: 700;
  color: var(--brand-strong);
  background: var(--brand-soft);
  padding: 4px 10px;
  border-radius: 999px;
}
.carnet-badge[hidden] { display: none; }

/* Marquita 🐾 sobre los íconos "Alertas" y "Club" de la barra de abajo,
   avisando que hay algo nuevo sin ver (alerta cercana, mensaje sin leer o
   promo del Club) — ver actualizarBadgesNav() en app.js. El ícono queda
   envuelto en .tab-icon-wrap solo para poder posicionar la marquita relativa
   a ÉL (y no al botón .tab entero, que también incluye el texto de abajo). */
.tab-icon-wrap {
  position: relative;
  display: inline-flex;
}
.tab-badge {
  position: absolute;
  top: -5px;
  right: -8px;
  width: 15px;
  height: 15px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  line-height: 1;
  border-radius: 50%;
  background: var(--brand);
  border: 2px solid var(--surface);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
}
.tab-badge[hidden] { display: none; }

/* Color distintivo por perro (ver colorDePerro() en app.js) — cada chip del
   selector y la tarjeta de estado toman --dog-color, para reconocer de un
   vistazo con cuál perro estás, sobre todo al deslizar entre varios. */
.dog-chip.active {
  border-color: var(--dog-color, var(--brand));
  color: var(--dog-color, var(--brand-strong));
  background: color-mix(in srgb, var(--dog-color, var(--brand)) 16%, var(--surface));
}
.status-card {
  border-left: 4px solid var(--dog-color, transparent);
  transition: transform .18s ease, opacity .18s ease, border-color .3s ease, background .3s ease;
}
.status-card.card-fuera-izq { transform: translateX(-26px); opacity: 0; }
.status-card.card-fuera-der { transform: translateX(26px); opacity: 0; }
.status-card.card-sin-transicion { transition: none !important; }
/* Rebote al entrar la tarjeta del siguiente perro (ver cambiarPerroConSwipe()
   en app.js, 05/10/26, pedido de Marcelo) — se agrega esta clase justo al
   reactivar la transición después del "teletransporte", así que solo se usa
   para la entrada (la salida se queda con el ease rápido de siempre, para no
   demorar el gesto). Usa una curva "back-out" (pasa un poquito de 0 y vuelve)
   en vez de la de opacity/border-color/background, que siguen igual. */
.status-card.card-entrando { transition: transform .32s cubic-bezier(.34,1.56,.64,1), opacity .18s ease, border-color .3s ease, background .3s ease; }

/* Menú desplegable (⋮) junto al nombre del perro: agrupa "Editar datos" y
   "QR del collar" en vez de dos botones sueltos, para bajar el ruido visual
   de la pantalla de Inicio. */
.status-top-right {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
}
.dog-menu { position: relative; }
.dog-menu-btn {
  width: 30px;
  height: 30px;
  border-radius: 99px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.dog-menu-btn:hover, .dog-menu-btn[aria-expanded="true"] {
  background: var(--surface-2);
  color: var(--ink);
}
.dog-menu-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 5;
  min-width: 210px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: 0 14px 30px -18px rgba(0,0,0,0.35);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.dog-menu-panel[hidden] { display: none; }
.dog-menu-item {
  border: none;
  background: none;
  text-align: left;
  padding: 10px 10px;
  border-radius: 9px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}
.dog-menu-item:hover { background: var(--surface-2); }

/* Foto del perro: se cambia desde adentro del formulario "Editar datos del
   perro" (no desde el avatar de Inicio, para no mezclar acciones en la
   pantalla principal) — sube a Storage vía subirFotoPerro() y se guarda
   como photoUrl. */
.dog-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 15px;
}
.foto-editar-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
.foto-editar-row .dog-avatar { width: 56px; height: 56px; font-size: 22px; }
.foto-editar-botones {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1;
}
.foto-editar-botones .btn-outline { width: 100%; margin: 0; }
.foto-editar-row.subiendo { opacity: .6; pointer-events: none; }

/* Recortar foto del perro (ver #cropModalOverlay en index.html y las
   funciones abrirRecorte()/confirmarRecorte() en app.js). */
.crop-viewport {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  max-width: 320px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 20px;
  background: var(--surface-2);
  touch-action: none;
  cursor: grab;
}
.crop-viewport:active { cursor: grabbing; }
.crop-viewport img {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
  user-select: none;
  -webkit-user-drag: none;
}

/* Vista previa del flyer antes de compartir (ver #flyerPreviewOverlay en
   index.html y btnFlyerCompartir en app.js) — a diferencia del recorte de
   arriba, acá la imagen ya viene armada (es el PNG que generó html2canvas),
   así que solo hace falta mostrarla completa y prolija, sin recortarla. */
.flyer-preview-frame {
  width: 100%;
  max-height: 55vh;
  overflow-y: auto;
  border-radius: 16px;
  background: var(--surface-2);
  display: flex;
  justify-content: center;
  /* Sin esto, flexbox estira la imagen (que tiene height:auto) para que
     rellene todo el alto disponible del recuadro (align-items:stretch es
     el valor por defecto) — antes casi no se notaba, pero ahora que el
     cartel quedó bastante más alto (foto cuadrada + collar 480px de ancho
     fijo) la deformaba bastante, aplastándola y dándole una apariencia
     "horizontal" que no tiene el archivo real. Con flex-start, la imagen
     conserva su alto natural (según su propia proporción) y si no entra
     completa en los 55vh, el recuadro deja hacer scroll (overflow-y:auto,
     ya estaba) para verla entera.
  */
  align-items: flex-start;
}
.flyer-preview-frame img {
  width: 100%;
  height: auto;
  display: block;
  /* Respaldo: si por lo que sea el navegador igual llega a estirar la caja
     (por ejemplo mientras la imagen todavía no cargó y el aspect-ratio que
     le fijamos en JS no coincide exacto), que recorte en vez de deformar. */
  object-fit: contain;
}
#cropZoom { width: 100%; accent-color: var(--brand); }

/* Confirmación flotante chiquita (ver #toastGlobal en index.html y
   mostrarToast() en app.js) — no bloquea la pantalla, se cierra sola. */
.toast {
  position: fixed;
  left: 50%;
  bottom: calc(86px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%) translateY(8px);
  z-index: 80;
  background: var(--teal-strong);
  color: #fff;
  font-size: 12.5px;
  font-weight: 600;
  padding: 11px 18px;
  border-radius: 99px;
  box-shadow: 0 14px 30px -16px rgba(0,0,0,0.4);
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
  max-width: calc(100% - 32px);
  text-align: center;
}
.toast.open { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Variante "huella" (ver mostrarToast(mensaje, duracion, "huella") en
   app.js) — para los avisos sobre la tarjeta de socio/QR del Club: naranja
   de marca en vez del teal/verde de una confirmación genérica, con una
   huellita 🐾 al lado (oculta en el toast normal). */
.toast.huella { background: var(--brand-strong); }
.toast-huella-icon { display: none; margin-right: 6px; }
.toast.huella .toast-huella-icon { display: inline; }
