/* ═══════════════════════════════════════════════════════════════════════════
   Parking Buddy · Sistema de diseño
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  /* El tema claro es el de la marca. Desde el 2026-09-11 hay también un MODO
     NOCTURNO: un segundo juego de estos mismos tokens bajo
     `:root[data-theme="dark"]`, al final del fichero. `color-scheme` va con
     cada tema para que el navegador pinte campos, desplegables y barras de
     desplazamiento a juego. */
  color-scheme: light;

  /* ── Paleta de la marca ─────────────────────────────────────────────────
     Medida sobre los ficheros del logotipo, contando píxeles:
       azul marino  #0F2648  (la palabra «parking»)
       azul vivo    #066CEC  (el pin, la palabra «buddy», una de las personas)
       verde        #3AB72F  (la otra persona)
     El azul manda en la estructura y en las acciones; el verde es el acento que
     llama la atención. No hay naranja: la marca no lo tiene.               */
  --navy: #0F2648;
  --navy-deep: #081A33;
  --blue: #066CEC;
  --blue-dark: #0553BE;
  --blue-soft: #8CC5FF;
  /* El azul cuando es TINTA (enlaces, titulares, «Ver todo»). De día es el mismo
     azul; de noche sube medio tono para leerse sobre oscuro (--blue se queda
     para los fondos de botón). */
  --blue-ink: #066CEC;
  --teal: #4E9BF5;
  /* El acento es VERDE. El token se llama --accent y no --green para que no se
     confunda con el verde semántico de «esto ha ido bien». */
  --accent: #3AB72F;
  --accent-dark: #2A9021;
  --accent-soft: #A7E39F;

  /* Semánticos: significan cosas (éxito, peligro) y no se tocan al cambiar la
     marca. El verde de éxito coincide a propósito con el de la marca. */
  --green: #3AB72F;
  --pink: #E8447A;
  --purple: #8E5BD0;
  --red: #DC3B36;

  --bg: #F5F7FA;
  --bg-grad-1: #E4EDFB;
  --bg-grad-2: #FAFCFE;
  --surface: rgba(255, 255, 255, 0.76);
  --surface-solid: #FFFFFF;
  --card: #FFFFFF;
  --text: #0F2648;
  --text-2: #5B6B85;
  --text-3: #93A0B5;
  --border: rgba(15, 38, 72, 0.10);

  /* Canales RGB para poder componer transparencias sin repetir el color.
     Antes cada rgba() llevaba el color a mano y cambiar la marca obligaba a
     tocar cuarenta sitios. */
  --navy-rgb: 15, 38, 72;
  --blue-rgb: 6, 108, 236;
  --accent-rgb: 58, 183, 47;
  --green-rgb: 58, 183, 47;
  --red-rgb: 220, 59, 54;
  --purple-rgb: 142, 91, 208;
  /* Tintas legibles sobre fondos claros del mismo tono */
  --green-ink: #1E7F16;
  --accent-ink: #1E7F16;
  --shadow-sm: 0 1px 2px rgba(15, 38, 72, 0.07), 0 1px 3px rgba(15, 38, 72, 0.05);
  --shadow-md: 0 8px 24px rgba(15, 38, 72, 0.09), 0 2px 6px rgba(15, 38, 72, 0.06);
  --shadow-lg: 0 24px 60px rgba(15, 38, 72, 0.17), 0 8px 20px rgba(15, 38, 72, 0.09);
  --radius: 20px;
  --radius-sm: 14px;
  --radius-lg: 28px;
  --r-pill: 999px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
          "Helvetica Neue", "Inter", system-ui, sans-serif;
}
* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; }
body {
  font-family: var(--font);
  color: var(--text);
  background:
    radial-gradient(1200px 700px at 80% -10%, var(--bg-grad-1), transparent 60%),
    radial-gradient(900px 600px at -10% 110%, var(--bg-grad-1), transparent 55%),
    var(--bg);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  letter-spacing: -0.011em;
  overflow-x: hidden;
}
button { font-family: inherit; cursor: pointer; border: none; background: none; color: inherit; }
input, select, textarea { font-family: inherit; }
a { color: var(--blue-ink); text-decoration: none; }
.hidden { display: none !important; }

/* ── Iconos en línea ────────────────────────────────────────────────────────
   Tamaño POR OMISIÓN de todo icono, y hace falta de verdad: un SVG que sólo
   lleva `viewBox` mide 300×150 px si nadie le dice otra cosa. La clase `.ico`
   sólo estaba definida dentro de `.nav-item` y `.tab`, así que los nueve iconos
   que no traen `width` propio (map, spots, res, gift, user, out, repeat, admin,
   users) se pintaban gigantes en cualquier otro sitio — y dentro de un
   contenedor flex, además, se quedaban con todo el ancho y dejaban al texto una
   palabra por línea.
   El menú y la barra de pestañas los agrandan con selectores más específicos. */
.ico { width: 18px; height: 18px; flex: 0 0 auto; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: rgba(120,120,130,0.3); border-radius: 999px; border: 3px solid transparent; background-clip: content-box; }

/* ── Tipografía ─────────────────────────────────────────────────────────── */
h1 { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; }
h2 { font-size: 1.4rem; font-weight: 700; letter-spacing: -0.02em; }
h3 { font-size: 1.05rem; font-weight: 650; letter-spacing: -0.01em; }
.muted { color: var(--text-2); }
.tiny { font-size: 0.8rem; }

/* ── Botones ────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 13px 22px; border-radius: var(--r-pill); font-size: 1rem; font-weight: 600;
  transition: transform 0.18s var(--ease), box-shadow 0.18s var(--ease), background 0.18s var(--ease), opacity 0.18s;
  white-space: nowrap; line-height: 1;
}
.btn:active { transform: scale(0.96); }
.btn-primary {
  background: linear-gradient(135deg, var(--blue), var(--blue-dark));
  color: #fff; box-shadow: 0 8px 22px rgba(var(--blue-rgb), 0.35);
}
.btn-primary:hover { box-shadow: 0 12px 30px rgba(var(--blue-rgb), 0.45); }
/* Acento naranja del logo: para la acción que queremos que se vea primero */
.btn-accent {
  background: linear-gradient(135deg, var(--accent), var(--accent-dark));
  color: #fff; box-shadow: 0 8px 22px rgba(var(--accent-rgb), 0.35);
}
.btn-accent:hover { box-shadow: 0 12px 30px rgba(var(--accent-rgb), 0.45); }
.btn-ghost { background: rgba(var(--navy-rgb), 0.08); color: var(--text); }
.btn-ghost:hover { background: rgba(var(--navy-rgb), 0.14); }
.btn-danger { background: rgba(var(--red-rgb), 0.12); color: var(--red); }
.btn-danger:hover { background: rgba(var(--red-rgb), 0.2); }
.btn-block { width: 100%; }
.btn-sm { padding: 9px 16px; font-size: 0.9rem; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }

/* ── Inputs ─────────────────────────────────────────────────────────────── */
.field { margin-bottom: 16px; text-align: left; }
.field label { display: block; font-size: 0.82rem; font-weight: 600; color: var(--text-2); margin: 0 0 7px 4px; }
.input {
  width: 100%; padding: 14px 16px; font-size: 1rem; color: var(--text);
  background: var(--surface-solid); border: 1.5px solid var(--border);
  border-radius: var(--radius-sm); transition: border-color 0.18s, box-shadow 0.18s, background 0.18s;
}
.input::placeholder { color: var(--text-3); }
.input:focus { outline: none; border-color: var(--blue-ink); box-shadow: 0 0 0 4px rgba(var(--blue-rgb), 0.16); }
textarea.input { resize: vertical; min-height: 72px; }

/* ═══ PANTALLA DE ACCESO ═══════════════════════════════════════════════════
   Es el primer contacto, y en un vistazo tiene que quedar claro qué es esto y
   por qué merece la pena. La mitad izquierda hace ese trabajo: logotipo grande,
   una frase que se entiende sola, los tres pasos del relevo y lo que se gana.
   La derecha es sólo el formulario, y nunca compite con el mensaje.
   ═══════════════════════════════════════════════════════════════════════════ */
#auth-screen {
  min-height: 100dvh; display: grid; grid-template-columns: 1.08fr 0.92fr;
}

/* ── Mitad izquierda: la propuesta ──────────────────────────────────────── */
.auth-hero {
  position: relative; overflow: hidden; color: #fff;
  background: linear-gradient(145deg, var(--navy-deep) 0%, var(--navy) 38%, var(--blue-dark) 74%, var(--blue) 100%);
  display: flex; flex-direction: column; justify-content: space-between;
  padding: 46px 52px 38px; gap: 28px;
}
/* Luces suaves */
.auth-hero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(620px 420px at 82% 8%, rgba(255, 255, 255, 0.22), transparent 62%),
    radial-gradient(520px 520px at 4% 104%, rgba(0, 0, 0, 0.28), transparent 58%);
}
/* La calzada: dos líneas discontinuas que cruzan el fondo. Es la temática de la
   marca (el logo lleva una carretera) y da profundidad sin cargar la pantalla. */
.auth-hero::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0.16;
  background-image:
    repeating-linear-gradient(115deg, rgba(255,255,255,0.9) 0 34px, transparent 34px 78px),
    repeating-linear-gradient(115deg, rgba(255,255,255,0.9) 0 34px, transparent 34px 78px);
  background-size: 100% 2px, 100% 2px;
  background-position: 0 30%, 0 72%;
  background-repeat: no-repeat, no-repeat;
}
.auth-hero-top, .auth-hero-bottom, .auth-hero-mid { position: relative; z-index: 1; }

/* ── Marca: el logotipo, bien grande ─────────────────────────────────────────
   `> img` (hijo directo) y no `img`: el texto del logotipo es OTRA imagen, y
   cuelga de `.auth-brand-txt`. Con el selector de descendiente, todas estas
   reglas —y la de más abajo, `img:first-child`, que el texto también cumple
   porque es el primer hijo de SU contenedor— le imponían una caja cuadrada de
   112 px. Medido en producción: la palabra «Parking Buddy» se pintaba en
   112×112 en vez de los 240 px de ancho que su propia regla pide, o sea a menos
   de la mitad, y encima con la sombra y la flotación del emblema.            */
.auth-brand { display: flex; align-items: center; gap: 18px; }
/* Medida, forma y sombra del emblema, en UN solo sitio. Estaban repartidas
   entre esta regla y otra idéntica al final del fichero, y la de abajo —con un
   `:first-child` de más— ganaba por especificidad: las dos adaptaciones por
   ALTO de pantalla (84 px y 68 px, unas líneas más abajo) no llegaban a
   aplicarse nunca y el emblema se quedaba a 112 px en una ventana baja, donde
   justamente no cabe. `border-radius` y `box-shadow` valen cero en un PNG
   transparente: la sombra se dibuja alrededor de la caja, no del dibujo, y
   dejaba una tarjeta rectangular detrás. Va con `drop-shadow`, que sigue el
   contorno opaco. */
.auth-brand > img {
  width: 148px; height: 148px; flex-shrink: 0; border-radius: 0; box-shadow: none;
  filter: drop-shadow(0 14px 30px rgba(0, 0, 0, 0.35));
  animation: authFlota 5s var(--ease) infinite;
}
.auth-brand-txt { min-width: 0; }




@keyframes authFlota {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
}

/* ── El mensaje ─────────────────────────────────────────────────────────── */
.auth-hero-mid h1 {
  font-size: 3.1rem; line-height: 1.02; font-weight: 750; letter-spacing: -0.035em;
  max-width: 15ch;
}
.auth-hero-mid h1 i { font-style: normal; color: var(--accent-soft); }
.auth-hero-mid p {
  margin-top: 16px; font-size: 1.1rem; opacity: 0.9; max-width: 44ch; line-height: 1.5;
}

/* Los tres pasos del relevo, sobre una calzada vertical */
.auth-steps { list-style: none; margin: 28px 0 0; position: relative; }
.auth-steps::before {
  content: ""; position: absolute; left: 15px; top: 14px; bottom: 14px; width: 2px;
  background: repeating-linear-gradient(180deg,
    rgba(255, 255, 255, 0.55) 0 8px, transparent 8px 18px);
}
.auth-steps li { display: flex; align-items: flex-start; gap: 14px; padding: 7px 0; position: relative; }
.auth-steps .as-num {
  width: 32px; height: 32px; flex-shrink: 0; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.86rem; font-weight: 750; color: var(--navy);
  background: #fff; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.22);
}
.auth-steps li:nth-child(2) .as-num { color: var(--accent-dark); }
.auth-steps .as-txt { font-size: 0.9rem; opacity: 0.86; line-height: 1.4; padding-top: 5px; }
.auth-steps .as-txt b { display: block; font-size: 0.96rem; opacity: 1; font-weight: 650; }

/* Lo que se gana */
.hero-points {
  display: flex; gap: 14px; margin-top: 30px; flex-wrap: wrap;
}
.hero-points .hp {
  flex: 1 1 130px; padding: 14px 16px; border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.12);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16);
}
.hero-points .hp b { display: block; font-size: 1.7rem; font-weight: 750; letter-spacing: -0.02em; line-height: 1; }
.hero-points .hp span { display: block; margin-top: 5px; opacity: 0.85; font-size: 0.82rem; line-height: 1.3; }

/* Ventajas en una lista corta: se leen de un barrido */
.auth-perks { list-style: none; margin-top: 26px; display: grid; gap: 9px; }
.auth-perks li {
  display: flex; align-items: center; gap: 11px;
  font-size: 0.9rem; opacity: 0.88; line-height: 1.35;
}
.auth-perks .ap-i {
  width: 28px; height: 28px; flex-shrink: 0; border-radius: 9px;
  display: flex; align-items: center; justify-content: center; font-size: 0.95rem;
  background: rgba(255, 255, 255, 0.14);
}

.auth-hero-bottom { font-size: 0.8rem; opacity: 0.7; display: flex; gap: 8px; flex-wrap: wrap; }
.auth-hero-bottom .ahb-sep { opacity: 0.5; }

/* ── Mitad derecha: el formulario ───────────────────────────────────────── */
.auth-panel {
  display: flex; align-items: center; justify-content: center; padding: 40px 28px;
  background: var(--bg);
}
.auth-card { width: 100%; max-width: 410px; text-align: center; }
.auth-card .mobile-brand { display: none; }
.auth-tabs {
  display: flex; background: rgba(var(--navy-rgb), 0.07); border-radius: var(--r-pill);
  padding: 5px; margin: 0 auto 28px; width: fit-content;
}
.auth-tabs button {
  padding: 9px 26px; border-radius: var(--r-pill); font-weight: 600; font-size: 0.95rem;
  color: var(--text-2); transition: all 0.22s var(--ease);
}
.auth-tabs button.active { background: var(--surface-solid); color: var(--navy); box-shadow: var(--shadow-sm); }
.auth-card h2 { margin-bottom: 6px; }
.auth-card > form > .muted { margin-bottom: 26px; }
.auth-form { animation: fadeUp 0.5s var(--ease); }
.auth-error {
  background: rgba(var(--red-rgb), 0.12); color: var(--red); padding: 11px 14px;
  border-radius: var(--radius-sm); font-size: 0.88rem; font-weight: 500; margin-bottom: 14px; text-align: left;
}
.auth-foot { margin-top: 18px; font-size: 0.8rem; color: var(--text-2); line-height: 1.45; }
.demo-hint {
  margin-top: 22px; padding: 12px 14px; border-radius: var(--radius-sm);
  background: rgba(var(--blue-rgb), 0.08); border: 1px dashed rgba(var(--blue-rgb), 0.3);
  font-size: 0.82rem; color: var(--text-2);
}
.demo-hint b { color: var(--blue-dark); }

/* ── Adaptación ─────────────────────────────────────────────────────────── */
/* Pantalla estrecha o baja: no cabe todo el mensaje, así que se recorta por
   orden de importancia — primero las ventajas sueltas, luego los pasos. */
@media (max-height: 820px) and (min-width: 861px) {
  .auth-hero { padding: 32px 42px 26px; gap: 18px; }
  .auth-brand > img { width: 108px; height: 108px; }
  .auth-brand-txt b { font-size: 1.6rem; }
  .auth-hero-mid h1 { font-size: 2.4rem; }
  .auth-hero-mid p { font-size: 1rem; margin-top: 12px; }
  .auth-steps { margin-top: 18px; }
  .auth-perks { display: none; }
  .hero-points { margin-top: 20px; }
}
@media (max-height: 660px) and (min-width: 861px) {
  .auth-steps { display: none; }
  .auth-brand > img { width: 88px; height: 88px; }
  .auth-hero-mid h1 { font-size: 2rem; }
}

@media (max-width: 860px) {
  /* Una columna: el formulario primero, porque quien vuelve sólo quiere entrar.
     La presentación queda debajo, para quien llega nuevo y baja a leer. */
  #auth-screen { grid-template-columns: 1fr; }
  .auth-hero { order: 2; padding: 34px 24px 30px; text-align: center; }
  .auth-hero::after { opacity: 0.1; }
  .auth-brand { flex-direction: column; gap: 12px; }
  .auth-brand > img { width: 112px; height: 112px; }
  .auth-hero-mid h1 { font-size: 2rem; max-width: none; margin: 0 auto; }
  .auth-hero-mid p { margin-left: auto; margin-right: auto; }
  .auth-steps { text-align: left; max-width: 340px; margin: 24px auto 0; }
  .auth-perks { text-align: left; max-width: 340px; margin: 22px auto 0; }
  .auth-hero-bottom { justify-content: center; }
  .auth-panel { order: 1; padding: 30px 22px 34px; }
  /* En móvil la marca de arriba es la del formulario */
  .auth-card .mobile-brand { display: block; margin-bottom: 22px; }
  /* Sólo el EMBLEMA. Con `img` a secas la regla alcanzaba también al texto del
     logotipo (un PNG transparente) y le ponía 96×96, esquinas redondeadas y una
     sombra de caja: la palabra salía metida en una tarjeta blanca. */
  .auth-card .mobile-brand img:first-child {
    width: 124px; height: 124px; border-radius: 0; margin: 0 auto 10px; display: block;
    box-shadow: none;
    filter: drop-shadow(0 14px 30px rgba(var(--navy-rgb), 0.24));
  }
  .auth-card .mobile-brand b {
    display: block; font-size: 1.5rem; font-weight: 750; letter-spacing: -0.02em; color: var(--navy);
  }
  .auth-card .mobile-brand b i { font-style: normal; color: var(--accent); }
  .auth-card .mobile-brand span { display: block; margin-top: 3px; font-size: 0.86rem; color: var(--text-2); }
  /* La marca grande de la portada sobra: ya está arriba */
  .auth-hero-top { display: none; }
}
@media (max-width: 460px) {
  .auth-hero-mid h1 { font-size: 1.7rem; }
  .hero-points .hp b { font-size: 1.45rem; }
  .auth-card .mobile-brand img:first-child { width: 104px; height: 104px; }
  .auth-card .mobile-brand .wordmark { width: 176px; }
}
@media (prefers-reduced-motion: reduce) {
  .auth-brand > img { animation: none; }
}

/* ═══ SHELL DE LA APP ══════════════════════════════════════════════════════ */
#app-screen { min-height: 100dvh; display: flex; }
.sidebar {
  width: 248px; flex-shrink: 0; padding: 22px 16px; position: sticky; top: 0; height: 100dvh;
  display: flex; flex-direction: column; gap: 6px;
  background: var(--surface); backdrop-filter: saturate(180%) blur(22px); -webkit-backdrop-filter: saturate(180%) blur(22px);
  border-right: 1px solid var(--border);
}
/* ── Marca de la barra lateral ───────────────────────────────────────────────
   En escritorio el logotipo manda: grande y centrado, con el nombre debajo. El
   emblema tiene detalle (dos coches, el pin, la carretera) y a 38 px no se veía
   nada de eso. En móvil no hay barra lateral: la marca vive en la barra superior
   y ahí sí va en horizontal, porque el alto es lo que escasea.               */

/* Aquí había una regla `.sb-brand img` con `border-radius` y `box-shadow`, de
   cuando el logotipo era una sola imagen cuadrada. Ahora son dos, y la sombra se
   aplicaba también al texto: un `box-shadow` se dibuja alrededor de la CAJA del
   elemento, no de la parte opaca de la imagen, así que un PNG transparente
   quedaba con una tarjeta blanca redondeada detrás. Las reglas vigentes están en
   el apartado del logotipo y usan `img:first-child` (el icono) y `.wordmark`. */





/* Pantallas bajas: con poco alto, el logotipo grande se come el menú */

.nav-item {
  display: flex; align-items: center; gap: 13px; padding: 12px 14px; border-radius: 14px;
  font-weight: 550; color: var(--text-2); font-size: 0.97rem; transition: all 0.18s var(--ease);
  /* Son <button>: ocupan el ancho de la barra y su texto va a la izquierda, que
     es lo que un <a> hacía solo. `cursor` explícito y no heredado del reset de
     `button`, para que quede dicho aquí: esto se pincha. */
  width: 100%; text-align: left; cursor: pointer;
}
.nav-item .ico { width: 22px; height: 22px; flex-shrink: 0; }
/* El hover era gris neutro. Ahora usa el VERDE de la marca (`--accent`), que es
   justamente «el acento que llama la atención»: al pasar por encima se ve a qué
   se va a entrar. Se excluye el elemento activo, que ya va en azul sólido y con
   el verde encima quedaría sucio. */
.nav-item:hover:not(.active) { background: rgba(var(--accent-rgb), 0.13); color: var(--accent-dark); }
.nav-item:hover:not(.active) .ico { color: var(--accent-dark); }
/* Y el foco de teclado, que hasta ahora no existía porque estos elementos ni
   siquiera eran enfocables (`<a>` sin `href`). */
/* El anillo se pinta con `box-shadow` y no con `outline-color`: es lo que ya usa
   el resto del proyecto (`.input:focus`) y, medido en el navegador, `outline-color`
   no llegaba a aplicarse aquí ni con un color literal. El `outline` transparente
   se queda a propósito: en modo de alto contraste forzado el sistema lo repinta,
   y sin él quien use ese modo se quedaría sin ninguna señal de foco. */
.nav-item:focus-visible, .tab:focus-visible {
  outline: 2px solid transparent; outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.nav-item.active { background: linear-gradient(135deg, var(--blue), var(--blue-dark)); color: #fff; box-shadow: 0 8px 20px rgba(var(--blue-rgb), 0.32); }
.sb-spacer { flex: 1; }
.sb-user {
  display: flex; align-items: center; gap: 11px; padding: 12px; border-radius: 16px;
  background: rgba(120,120,130,0.08);
}
.sb-user .avatar { width: 38px; height: 38px; font-size: 0.95rem; }
.sb-user .meta { overflow: hidden; }
.sb-user .meta b { display: block; font-size: 0.9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sb-user .meta span { font-size: 0.78rem; color: var(--text-2); }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; height: 100dvh; overflow: hidden; }
#view-container { flex: 1; min-height: 0; overflow-y: auto; }
.topbar {
  position: sticky; top: 0; z-index: 20; display: flex; align-items: center; justify-content: space-between;
  /* Márgenes de seguridad a los lados: en un móvil con muesca, en horizontal,
     el logotipo caía justo debajo del recorte. La barra inferior ya cuidaba el
     borde de abajo (`env(safe-area-inset-bottom)`) y esta no cuidaba ninguno. */
  padding: 16px max(28px, env(safe-area-inset-right)) 16px max(28px, env(safe-area-inset-left));
  background: var(--surface); backdrop-filter: saturate(180%) blur(22px);
  -webkit-backdrop-filter: saturate(180%) blur(22px); border-bottom: 1px solid var(--border);
  gap: 12px;
}
/* Aquí había una regla `.topbar .mobile-brand img` que fijaba 32×32 y un
   `border-radius` de 9 px. Se escribió cuando el logotipo era UNA imagen
   cuadrada; ahora son dos —el emblema y el texto «Parking Buddy»— y esa regla
   alcanzaba también al texto: le imponía 32 px de alto, así que la palabra
   quedaba encogida y más baja que el emblema de al lado. Es el mismo error que
   ya se corrigió en la barra lateral, que aquí seguía vivo.
   Las reglas vigentes están en el apartado del LOGOTIPO, y distinguen el
   emblema (`img:first-child`) del texto (`.wordmark`). */
.topbar h2 { font-size: 1.3rem; }
.points-pill { cursor: pointer; font-family: inherit;
  display: inline-flex; align-items: center; gap: 8px; padding: 9px 16px; border-radius: var(--r-pill);
  background: linear-gradient(135deg, var(--accent), var(--accent-dark)); color: #fff; font-weight: 700; font-size: 0.95rem;
  box-shadow: 0 8px 20px rgba(var(--accent-rgb), 0.35);
}
.view { padding: 28px; max-width: 1100px; width: 100%; margin: 0 auto; animation: fadeUp 0.4s var(--ease); }

.avatar {
  width: 44px; height: 44px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 700; flex-shrink: 0; box-shadow: var(--shadow-sm);
}

/* ── Tarjetas ───────────────────────────────────────────────────────────── */
.card {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); padding: 22px;
}
.cards-grid { display: grid; gap: 16px; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-auto { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }

.section-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; gap: 12px; flex-wrap: wrap; }

/* ── Mapa ───────────────────────────────────────────────────────────────── */
/* Vista de mapa: ocupa todo el alto disponible sin scroll de página */
/* ── Vista del mapa ─────────────────────────────────────────────────────────
   El mapa es la pieza central de la aplicación y necesita cada píxel que haya.
   Dos cosas la estropeaban en escritorio:
     · `.view` limita el ancho a 1100 px. Está bien para leer texto, pero un mapa
       en una pantalla apaisada quedaba como una columna estrecha en el centro
       con dos márgenes enormes. Aquí se retira el tope.
     · La cabecera con título, subtítulo y barra de filtros se comía el alto, y
       en un portátil de 768 px de alto al mapa le quedaban cuatro dedos.
   En móvil se mantiene el apilado vertical: mapa arriba, lista debajo.        */
.view-map {
  height: 100%; display: flex; flex-direction: column;
  max-width: none;                 /* el mapa aprovecha toda la pantalla */
  padding: 16px 22px 18px;
}
.view-map .section-head { flex: 0 0 auto; margin-bottom: 12px; }
/* Cabecera compacta: el subtítulo explica, pero no a costa del mapa */
.view-map .section-head h1 { font-size: 1.5rem; }
.view-map .section-head p { font-size: 0.85rem; }

/* La lista tiene un ancho cómodo y estable; el mapa se queda con el resto. Con
   `1.6fr 1fr`, al ensanchar la pantalla crecían los dos y la lista acababa con
   una tarjeta de 500 px de ancho que no aporta nada. */
.map-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(290px, 25vw, 380px);
  gap: 16px; align-items: stretch; flex: 1 1 auto; min-height: 0;
}
#map {
  height: 100%; min-height: 320px; border-radius: var(--radius); overflow: hidden;
  box-shadow: var(--shadow-md); border: 1px solid var(--border); z-index: 1;
}
.spot-list { display: flex; flex-direction: column; gap: 12px; height: 100%; overflow-y: auto; padding-right: 4px; }

/* Pantallas apaisadas y bajas (los 1366×768 de tantos portátiles): se recorta
   todo lo prescindible para que el mapa siga siendo el protagonista. */
@media (min-width: 1001px) and (max-height: 800px) {
  .view-map { padding: 10px 18px 12px; }
  .view-map .section-head { margin-bottom: 8px; }
  .view-map .section-head p { display: none; }
  .view-map .section-head h1 { font-size: 1.3rem; }
  .view-map .filter-bar { margin-bottom: 10px; padding: 8px 10px; }
}
/* Muy apaisado (ultrapanorámicas): la lista no debe estirarse sin límite */
@media (min-width: 1600px) {
  .map-layout { grid-template-columns: minmax(0, 1fr) 360px; }
}
.spot-card {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 16px 18px; box-shadow: var(--shadow-sm); transition: transform 0.18s var(--ease), box-shadow 0.18s var(--ease);
  cursor: pointer;
}
.spot-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.spot-card.active { border-color: var(--blue-ink); box-shadow: 0 0 0 3px rgba(var(--blue-rgb), 0.18); }
.spot-card .sc-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.spot-card h3 { margin-bottom: 3px; }
.spot-card .addr { font-size: 0.85rem; color: var(--text-2); }
.time-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 12px; border-radius: var(--r-pill);
  background: rgba(var(--green-rgb), 0.14); color: var(--green-ink); font-weight: 650; font-size: 0.85rem; margin-top: 12px;
}
.spot-meta { display: flex; align-items: center; gap: 8px; margin-top: 12px; }
.spot-meta .who { font-size: 0.82rem; color: var(--text-2); }

/* ── Badges de estado ───────────────────────────────────────────────────── */
.badge { display: inline-block; padding: 5px 11px; border-radius: var(--r-pill); font-size: 0.74rem; font-weight: 700; letter-spacing: 0.01em; }
/* `free` es el valor que de verdad guarda la base; `open` se queda por
   compatibilidad. Sin la primera, la insignia de «Mis plazas» salía sin fondo
   ninguno y con el texto en crudo. */
.badge.open, .badge.free { background: rgba(var(--green-rgb), 0.16); color: var(--green-ink); }
.badge.reserved { background: rgba(var(--accent-rgb), 0.16); color: var(--accent-ink); }
.badge.occupied { background: rgba(var(--blue-rgb), 0.14); color: var(--blue-ink); }
.badge.expired { background: rgba(120,120,130,0.16); color: var(--text-2); }
.badge.active { background: rgba(var(--blue-rgb), 0.14); color: var(--blue-ink); }
.badge.cancelled { background: rgba(var(--red-rgb), 0.14); color: var(--red); }
.badge.completed { background: rgba(var(--green-rgb), 0.16); color: var(--green-ink); }

/* ── Recompensas ────────────────────────────────────────────────────────── */
.reward-card { text-align: center; display: flex; flex-direction: column; align-items: center; gap: 8px; position: relative; overflow: hidden; }
.reward-card .ricon {
  width: 70px; height: 70px; border-radius: 20px; display: flex; align-items: center; justify-content: center;
  font-size: 2rem; background: linear-gradient(135deg, rgba(var(--blue-rgb), 0.12), rgba(var(--blue-rgb), 0.12)); margin-bottom: 4px;
}
.reward-card .cost { font-weight: 700; color: var(--accent); display: inline-flex; gap: 6px; align-items: center; }
.reward-card.locked { opacity: 0.62; }
.progress { height: 8px; background: rgba(120,120,130,0.18); border-radius: 999px; overflow: hidden; margin-top: 8px; width: 100%; }
.progress > i { display: block; height: 100%; background: linear-gradient(90deg, var(--blue), var(--teal)); border-radius: 999px; transition: width 0.5s var(--ease); }

/* ── Perfil ─────────────────────────────────────────────────────────────── */
.profile-head { display: flex; align-items: center; gap: 18px; margin-bottom: 8px; }
.profile-head .avatar { width: 76px; height: 76px; font-size: 1.8rem; }
.stat-tile { text-align: center; }
.stat-tile b { display: block; font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; }
.stat-tile span { font-size: 0.85rem; color: var(--text-2); }
.color-dots { display: flex; gap: 10px; flex-wrap: wrap; }
.color-dots button { width: 34px; height: 34px; border-radius: 50%; border: 3px solid transparent; transition: transform 0.15s; }
.color-dots button:hover { transform: scale(1.12); }
.color-dots button.sel { border-color: var(--text); box-shadow: 0 0 0 3px var(--bg); }

/* ── Empty states ───────────────────────────────────────────────────────── */
.empty { text-align: center; padding: 50px 20px; color: var(--text-2); }
.empty .e-ico { font-size: 3rem; margin-bottom: 10px; }

/* ═══ MODAL / SHEET ════════════════════════════════════════════════════════ */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(10,12,18,0.45); backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px); display: flex; align-items: center; justify-content: center;
  z-index: 100; padding: 20px; animation: fade 0.25s var(--ease);
}
.modal {
  background: var(--surface-solid); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  width: 100%; max-width: 460px; max-height: 90dvh; overflow-y: auto; padding: 28px; animation: pop 0.32s var(--ease);
}
.modal h2 { margin-bottom: 4px; }
.modal .modal-sub { color: var(--text-2); margin-bottom: 20px; font-size: 0.92rem; }
.modal-actions { display: flex; gap: 10px; margin-top: 20px; }
.modal-actions .btn { flex: 1; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* ── Toast ──────────────────────────────────────────────────────────────── */
#toasts { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); z-index: 200; display: flex; flex-direction: column; gap: 10px; align-items: center; }
.toast {
  background: rgba(20,22,30,0.92); color: #fff; padding: 13px 20px; border-radius: var(--r-pill);
  font-weight: 550; font-size: 0.92rem; box-shadow: var(--shadow-lg); backdrop-filter: blur(10px);
  display: flex; align-items: center; gap: 10px; animation: toastIn 0.4s var(--ease); max-width: 90vw;
}
.toast.success { background: linear-gradient(135deg, var(--green-ink), var(--green)); }
.toast.error { background: linear-gradient(135deg, var(--accent-dark), var(--red)); }

/* ── Bottom tab bar (móvil) ─────────────────────────────────────────────── */
.tabbar { display: none; }

/* ── Animaciones ────────────────────────────────────────────────────────── */
@keyframes fadeUp { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop { from { opacity: 0; transform: translateY(20px) scale(0.96); } to { opacity: 1; transform: none; } }
@keyframes toastIn { from { opacity: 0; transform: translateY(20px) scale(0.9); } to { opacity: 1; transform: none; } }
.spin { width: 18px; height: 18px; border: 2.5px solid rgba(255,255,255,0.4); border-top-color: #fff; border-radius: 50%; animation: rot 0.7s linear infinite; }
@keyframes rot { to { transform: rotate(360deg); } }

/* ── Leaflet skin ───────────────────────────────────────────────────────── */
.leaflet-container { font-family: var(--font); background: var(--bg); }
.leaflet-popup-content-wrapper { border-radius: 16px; box-shadow: var(--shadow-md); }
.leaflet-popup-content { margin: 14px 16px; font-size: 0.9rem; }
/* Un ancho mínimo para que «Reservar» y «Llévame» quepan en una línea: Leaflet
   ajusta el globo al contenido y con un título corto los apilaba. Medido: los dos
   botones piden ~202 px con su relleno y el icono, así que 196 se quedaba a un
   pelo y se iban a dos líneas. */
.leaflet-popup-content { min-width: 222px; }
.cb-marker { display: grid; place-items: center; }
.cb-pin {
  width: 38px; height: 38px; border-radius: 50% 50% 50% 0; transform: rotate(-45deg);
  display: grid; place-items: center; box-shadow: 0 4px 12px rgba(0,0,0,0.3); border: 2.5px solid #fff;
}
.cb-pin span { transform: rotate(45deg); font-size: 1rem; }

/* ═══ CAMPANA Y PANEL DE AVISOS ════════════════════════════════════════════ */
.topbar-right { display: flex; align-items: center; gap: 12px; min-width: 0; }

/* ── Selector de idioma ─────────────────────────────────────────────────────
   Lo crea `i18n.js`. En la pantalla de acceso va fijo arriba a la derecha; una
   vez dentro se mete en `.topbar-right` y pasa a ser una celda más de la fila,
   así que deja de taparle la campana de avisos (ver el comentario de
   `selector()` en i18n.js). Los estilos, aquí y no en un atributo `style`.  */
#pb-lang { position: fixed; top: 10px; right: 12px; z-index: 1000; }
#pb-lang.en-barra { position: static; top: auto; right: auto; }
#pb-lang select {
  border: 1px solid var(--border); border-radius: 9px; padding: 6px 9px;
  font: inherit; font-size: 0.78rem; font-weight: 550;
  background: var(--card); color: var(--navy); cursor: pointer;
  box-shadow: 0 1px 4px rgba(var(--navy-rgb), 0.1);
}
#pb-lang select:focus-visible { outline: 2px solid transparent; box-shadow: 0 0 0 4px var(--accent-soft); }
/* En un móvil estrecho la fila de la derecha va justa: se queda el idioma en su
   forma más corta y la pastilla de puntos ya se recorta por su cuenta. */
@media (max-width: 480px) {
  #pb-lang.en-barra select { padding: 5px 6px; font-size: 0.72rem; max-width: 84px; }
}
.pending-chip {
  display: inline-flex; align-items: center; padding: 6px 12px; border-radius: var(--r-pill);
  background: rgba(var(--accent-rgb), 0.14); color: var(--accent-ink); font-weight: 650; font-size: 0.8rem;
  white-space: nowrap;
}

.icon-btn {
  position: relative; width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center; color: var(--text-2);
  background: rgba(120, 120, 130, 0.12); transition: all 0.2s var(--ease);
}
.icon-btn:hover { background: rgba(120, 120, 130, 0.2); color: var(--text); }
.icon-btn.has-unread { color: var(--blue-ink); background: rgba(var(--blue-rgb), 0.14); }
.icon-btn.has-unread svg { animation: ring 2.4s var(--ease) 0.4s 2; transform-origin: top center; }
@keyframes ring {
  0%, 60%, 100% { transform: rotate(0); }
  10%, 30%, 50% { transform: rotate(11deg); }
  20%, 40% { transform: rotate(-11deg); }
}
.notif-wrap { position: relative; }
.notif-badge {
  position: absolute; top: -2px; right: -2px; min-width: 19px; height: 19px; padding: 0 5px;
  border-radius: var(--r-pill); background: linear-gradient(135deg, var(--pink), var(--red));
  color: #fff; font-size: 0.68rem; font-weight: 700; display: grid; place-items: center;
  border: 2px solid var(--surface-solid); box-shadow: 0 2px 8px rgba(255, 55, 95, 0.4);
}
.notif-panel {
  position: absolute; top: calc(100% + 12px); right: 0; width: 350px; max-width: calc(100vw - 32px);
  background: var(--surface-solid); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); z-index: 60; overflow: hidden; animation: pop 0.26s var(--ease);
}
.np-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 15px 18px; border-bottom: 1px solid var(--border);
}
.np-list { max-height: min(60dvh, 440px); overflow-y: auto; }
.np-item {
  display: flex; gap: 12px; padding: 13px 18px; cursor: pointer;
  border-bottom: 1px solid var(--border); transition: background 0.16s;
}
.np-item:last-child { border-bottom: none; }
.np-item:hover { background: rgba(120, 120, 130, 0.08); }
.np-item.unread { background: rgba(var(--blue-rgb), 0.06); }
.np-item.unread .np-body b::after {
  content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--blue); margin-left: 7px; vertical-align: middle;
}
.np-ico {
  width: 34px; height: 34px; flex-shrink: 0; border-radius: 11px; display: grid; place-items: center;
  background: rgba(120, 120, 130, 0.12); font-size: 1.05rem;
}
.np-body { min-width: 0; }
.np-body b { font-size: 0.92rem; font-weight: 650; display: block; }
.np-body p { font-size: 0.82rem; color: var(--text-2); margin-top: 3px; line-height: 1.4; }
.np-time { font-size: 0.72rem; color: var(--text-3); display: block; margin-top: 5px; }
.np-empty { padding: 34px 18px; text-align: center; color: var(--text-2); font-size: 0.88rem; }
.link-btn {
  background: none; color: var(--blue-ink); font-size: 0.82rem; font-weight: 600; padding: 4px 2px;
}
.link-btn:hover { text-decoration: underline; }

/* ═══ BARRA DE FILTROS DEL MAPA ════════════════════════════════════════════ */
.filter-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 16px; flex: 0 0 auto;
}
.chip-btn {
  display: inline-flex; align-items: center; gap: 7px; padding: 10px 16px;
  border-radius: var(--r-pill); background: var(--card); border: 1.5px solid var(--border);
  font-size: 0.87rem; font-weight: 600; color: var(--text-2); white-space: nowrap;
  box-shadow: var(--shadow-sm); transition: all 0.2s var(--ease);
}
.chip-btn:hover { color: var(--text); border-color: rgba(var(--blue-rgb), 0.4); }
.chip-btn.on {
  background: linear-gradient(135deg, var(--blue), var(--blue-dark)); color: #fff;
  border-color: transparent; box-shadow: 0 6px 18px rgba(var(--blue-rgb), 0.3);
}
.chip-field {
  display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px;
  border-radius: var(--r-pill); background: var(--card); border: 1.5px solid var(--border);
  box-shadow: var(--shadow-sm); color: var(--text-2); transition: border-color 0.18s;
}
.chip-field:focus-within { border-color: var(--blue-ink); box-shadow: 0 0 0 4px rgba(var(--blue-rgb), 0.14); }
.chip-field > span { font-size: 0.78rem; font-weight: 600; white-space: nowrap; }
.chip-field select, .chip-field input {
  border: none; background: none; color: var(--text); font-size: 0.87rem; font-weight: 550;
  outline: none; min-width: 0; padding: 2px 0;
}
.chip-field.grow { flex: 1 1 190px; }
.chip-field.grow input { width: 100%; }
.chip-field.off { opacity: 0.5; }
.list-summary { padding: 2px 4px 6px; }

.dist-badge {
  display: inline-flex; align-items: center; gap: 5px; padding: 5px 11px; border-radius: var(--r-pill);
  background: rgba(var(--blue-rgb), 0.12); color: var(--blue-ink); font-size: 0.76rem; font-weight: 700;
  white-space: nowrap; flex-shrink: 0;
}

/* ═══ NOTAS INFORMATIVAS ═══════════════════════════════════════════════════ */
/* Bloque, no flex: la mayoría de las notas son texto suelto con <b> dentro, y en
   un contenedor flex cada trozo de texto se vuelve un ítem propio —el texto salía
   partido en columnas de una palabra (captura de Luiz en «Reservar plaza»,
   2026-09-12). El icono va en línea con el texto. */
.info-note {
  display: block; padding: 12px 14px; margin-top: 4px;
  border-radius: var(--radius-sm); background: rgba(var(--blue-rgb), 0.08);
  border: 1px solid rgba(var(--blue-rgb), 0.2); font-size: 0.82rem; color: var(--text-2);
  line-height: 1.45;
}
.info-note b { color: var(--text); }
.info-note svg { display: inline-block; width: 18px; height: 18px; vertical-align: -4px; margin-right: 6px; }
.info-note > span { display: inline; }
.info-note.warn { background: rgba(var(--accent-rgb), 0.1); border-color: rgba(var(--accent-rgb), 0.28); }
.ok-note {
  display: flex; align-items: center; gap: 7px; margin-top: 8px; font-size: 0.82rem;
  font-weight: 600; color: var(--green-ink);
}

.pending-pill {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 12px; padding: 6px 12px;
  border-radius: var(--r-pill); background: rgba(var(--accent-rgb), 0.14); color: var(--accent-ink);
  font-size: 0.78rem; font-weight: 650;
}
.count-pill {
  display: inline-block; margin-left: 8px; padding: 4px 11px; border-radius: var(--r-pill);
  background: rgba(var(--blue-rgb), 0.14); color: var(--blue-ink); font-size: 0.72rem; font-weight: 700;
  vertical-align: middle;
}
.card-accent { border-color: rgba(var(--blue-rgb), 0.35); box-shadow: 0 0 0 3px rgba(var(--blue-rgb), 0.08), var(--shadow-sm); }

/* ═══ RELEVO (handoff) ═════════════════════════════════════════════════════ */
.handoff {
  margin-top: 14px; padding-top: 14px; border-top: 1px dashed var(--border);
}
.handoff-row { display: flex; align-items: center; gap: 10px; }
.handoff-row b { font-size: 0.9rem; }
.steps { display: flex; gap: 8px; margin: 12px 0 4px; flex-wrap: wrap; }
.step {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: var(--r-pill);
  font-size: 0.76rem; font-weight: 650;
}
.step.todo { background: rgba(120, 120, 130, 0.14); color: var(--text-2); }
.step.done { background: rgba(var(--green-rgb), 0.16); color: var(--green-ink); }
.step svg { width: 13px; height: 13px; }

/* ═══ BUSCADOR DE DIRECCIONES ══════════════════════════════════════════════ */
.input-with-btn { display: flex; gap: 8px; align-items: stretch; }
.input-with-btn .input { flex: 1; min-width: 0; }
.input-with-btn .btn { flex-shrink: 0; }
.geo-results {
  margin-top: 8px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  overflow: hidden; max-height: 200px; overflow-y: auto; background: var(--card);
}
.geo-item {
  display: flex; align-items: flex-start; gap: 9px; width: 100%; text-align: left;
  padding: 11px 13px; font-size: 0.83rem; color: var(--text-2);
  border-bottom: 1px solid var(--border); transition: background 0.15s;
}
.geo-item:last-child { border-bottom: none; }
.geo-item:hover { background: rgba(var(--blue-rgb), 0.08); color: var(--text); }
.geo-item svg { width: 16px; height: 16px; flex: 0 0 auto; margin-top: 2px; color: var(--blue-ink); }
.geo-loading { padding: 13px; text-align: center; }

/* Botonera del globo del pin: «Reservar» y «Llévame». Leaflet da al globo un
   ancho ajustado al contenido, así que los botones van en fila y se parten solos
   si el título es largo. */
.pop-actions {
  display: flex; gap: 6px; flex-wrap: wrap; align-items: center;
  margin: 8px 0 4px;
}
/* `min-width: 0` es lo que permite que un elemento flex se encoja por debajo de
   su contenido; sin eso, `flex: 1 1 0` no sirve de nada y la fila se parte. */
.pop-actions .btn { flex: 1 1 0; min-width: 0; justify-content: center; white-space: nowrap; }

/* Fila bajo el mapa del modal de «Estoy aparcado»: el botón para repetir la
   lectura del GPS y el estado de esa lectura. En móvil el texto se va debajo,
   que si no el botón se estruja. */
.pick-geo-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 8px;
}
.pick-geo-row .btn { flex: 0 0 auto; }
#pick-geo { flex: 1; min-width: 140px; line-height: 1.35; }
/* El separador va en el CSS a propósito: así el mensaje son dos nodos de texto
   independientes y el motor de i18n traduce cada frase por su cuenta. */
.pick-geo-hint::before { content: ' · '; opacity: 0.6; }

/* ═══ LIBRO MAYOR DE PUNTOS ════════════════════════════════════════════════ */
.ledger { display: flex; flex-direction: column; }
.ledger-row {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 12px 0; border-bottom: 1px solid var(--border);
}
.ledger-row:last-child { border-bottom: none; }
.ledger-row.reverted { opacity: 0.55; }
.lr-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.lr-main b { font-size: 0.9rem; font-weight: 650; }
.lr-side { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.lr-points { font-weight: 700; font-size: 1rem; color: var(--green-ink); font-variant-numeric: tabular-nums; }
.lr-points.neg { color: var(--red); }
.ledger-row.reverted .lr-points { color: var(--text-3); text-decoration: line-through; }

.grid-4 { grid-template-columns: repeat(4, 1fr); }

/* ═══ INSIGNIA DE FIABILIDAD ═══════════════════════════════════════════════ */
.rep-badge {
  display: inline-flex; align-items: center; gap: 5px; padding: 4px 10px;
  border-radius: var(--r-pill); font-size: 0.74rem; font-weight: 700; white-space: nowrap;
}
.rep-badge svg { width: 13px; height: 13px; flex-shrink: 0; }
.rep-badge.nuevo       { background: rgba(120,120,130,0.16); color: var(--text-2); }
.rep-badge.fiable      { background: rgba(var(--blue-rgb), 0.14);  color: var(--blue-ink); }
.rep-badge.muy_fiable  { background: rgba(var(--green-rgb), 0.16);   color: var(--green-ink); }
.rep-badge.poco_fiable { background: rgba(var(--red-rgb), 0.14);   color: var(--red); }

.rep-card .rep-stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-top: 14px;
  text-align: center;
}
.rep-card .rep-stats b { display: block; font-size: 1.4rem; font-weight: 700; }
.rep-card .rep-stats span { font-size: 0.76rem; color: var(--text-2); }

.outcome-chip {
  display: inline-block; margin-top: 12px; padding: 6px 12px; border-radius: var(--r-pill);
  font-size: 0.78rem; font-weight: 650;
}
.outcome-chip.ok      { background: rgba(var(--green-rgb), 0.16);   color: var(--green-ink); }
.outcome-chip.neutral { background: rgba(120,120,130,0.14); color: var(--text-2); }
.outcome-chip.bad     { background: rgba(var(--red-rgb), 0.14);   color: var(--red); }

.tag-chip {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 10px; padding: 5px 11px;
  border-radius: var(--r-pill); background: rgba(var(--purple-rgb), 0.14); color: var(--purple);
  font-size: 0.75rem; font-weight: 650;
}
.tag-chip svg { width: 13px; height: 13px; }
.muted-card { opacity: 0.66; }
.mini-badge {
  display: inline-grid; place-items: center; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: var(--r-pill); background: var(--pink); color: #fff;
  font-size: 0.66rem; font-weight: 700;
}

/* ═══ SELECTOR DE DÍAS (plazas recurrentes) ════════════════════════════════ */
.day-picker { display: flex; gap: 7px; flex-wrap: wrap; }
.day-picker button {
  width: 40px; height: 40px; border-radius: 13px; font-weight: 700; font-size: 0.9rem;
  background: rgba(120,120,130,0.12); color: var(--text-2);
  border: 1.5px solid transparent; transition: all 0.18s var(--ease);
}
.day-picker button:hover { background: rgba(120,120,130,0.2); }
.day-picker button.sel {
  background: linear-gradient(135deg, var(--blue), var(--blue-dark)); color: #fff;
  box-shadow: 0 6px 16px rgba(var(--blue-rgb), 0.3);
}

/* ═══ CHAT DEL RELEVO ══════════════════════════════════════════════════════ */
.chat-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.chat-head h2 { margin-bottom: 2px; }
.chat-list {
  margin: 16px 0 12px; padding: 14px; border-radius: var(--radius-sm);
  background: rgba(120,120,130,0.07); height: min(46dvh, 340px); overflow-y: auto;
  display: flex; flex-direction: column; gap: 10px;
}
.msg { display: flex; flex-direction: column; max-width: 82%; }
.msg.mine { align-self: flex-end; align-items: flex-end; }
.msg.theirs { align-self: flex-start; align-items: flex-start; }
.msg-bubble {
  padding: 10px 14px; border-radius: 18px; font-size: 0.9rem; line-height: 1.4;
  word-break: break-word; box-shadow: var(--shadow-sm);
}
.msg.mine .msg-bubble {
  background: linear-gradient(135deg, var(--blue), var(--blue-dark)); color: #fff;
  border-bottom-right-radius: 6px;
}
.msg.theirs .msg-bubble {
  background: var(--surface-solid); color: var(--text); border-bottom-left-radius: 6px;
}
.msg-time { font-size: 0.68rem; color: var(--text-3); margin-top: 4px; }

.quick-replies {
  display: flex; gap: 7px; overflow-x: auto; padding-bottom: 8px; margin-bottom: 10px;
  scrollbar-width: none;
}
.quick-replies::-webkit-scrollbar { display: none; }
.quick-replies button {
  flex-shrink: 0; padding: 7px 13px; border-radius: var(--r-pill); font-size: 0.8rem;
  font-weight: 600; background: rgba(var(--blue-rgb), 0.1); color: var(--blue-ink);
  border: 1px solid rgba(var(--blue-rgb), 0.22); transition: background 0.18s;
}
.quick-replies button:hover { background: rgba(var(--blue-rgb), 0.18); }
.chat-form { display: flex; gap: 8px; align-items: stretch; }
.chat-form .input { flex: 1; min-width: 0; }
.chat-form .btn { flex-shrink: 0; padding: 13px 18px; }

.phone-box {
  margin: 10px 0 4px; padding: 20px; border-radius: var(--radius-sm); text-align: center;
  background: rgba(var(--blue-rgb), 0.08); border: 1px dashed rgba(var(--blue-rgb), 0.3);
}
.phone-box a { font-size: 1.5rem; font-weight: 700; letter-spacing: 0.02em; }

/* ═══ VALES DE CANJE ═══════════════════════════════════════════════════════ */
.voucher-live { border-color: rgba(var(--green-rgb), 0.4); box-shadow: 0 0 0 3px rgba(var(--green-rgb), 0.08), var(--shadow-sm); }
.code-box {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 14px; padding: 12px 16px; border-radius: var(--radius-sm);
  background: rgba(120,120,130,0.1); border: 1px dashed var(--border);
}
.code-box code {
  font-family: "SF Mono", ui-monospace, Menlo, Consolas, monospace;
  font-size: 1.05rem; font-weight: 700; letter-spacing: 0.08em; color: var(--text);
}
.code-box.spent code { color: var(--text-3); text-decoration: line-through; }
.code-box.big { justify-content: center; gap: 18px; padding: 22px; margin-top: 18px; }
.code-box.big code { font-size: 1.6rem; letter-spacing: 0.12em; }

/* ═══ PANEL DE ADMINISTRACIÓN ══════════════════════════════════════════════ */

.table-wrap {
  overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--card); box-shadow: var(--shadow-sm);
}
.admin-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; min-width: 620px; }
.admin-table th, .admin-table td {
  padding: 12px 14px; text-align: left; border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.admin-table th {
  font-size: 0.74rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-3); background: rgba(120,120,130,0.06); white-space: nowrap;
}
.admin-table tbody tr:last-child td { border-bottom: none; }
.admin-table tbody tr:hover { background: rgba(120,120,130,0.05); }
.admin-table code {
  font-family: "SF Mono", ui-monospace, Menlo, Consolas, monospace;
  font-weight: 700; letter-spacing: 0.04em;
}
.admin-table tr.row-warn { background: rgba(var(--red-rgb), 0.06); }
.admin-table tr.row-warn:hover { background: rgba(var(--red-rgb), 0.1); }
.stat-tile.tile-bad b { color: var(--red); }

/* ═══ CAPAS DEL MAPA ═══════════════════════════════════════════════════════ */
.map-wrap { position: relative; height: 100%; min-height: 280px; display: flex; }
.map-wrap #map { flex: 1; }
.map-fab {
  position: absolute; top: 12px; right: 12px; z-index: 400;
  width: 42px; height: 42px; border-radius: 13px; display: grid; place-items: center;
  background: var(--surface-solid); color: var(--text-2);
  border: 1px solid var(--border); box-shadow: var(--shadow-md);
  transition: all 0.18s var(--ease);
}
.map-fab:hover { color: var(--blue-ink); transform: translateY(-1px); }

.layer-panel {
  position: absolute; top: 62px; right: 12px; z-index: 401; width: 320px;
  max-width: calc(100% - 24px); max-height: calc(100% - 80px); overflow-y: auto;
  background: var(--surface-solid); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-lg); animation: pop 0.24s var(--ease);
}
.lp-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 13px 15px; border-bottom: 1px solid var(--border);
}
.lp-body { padding: 6px 0; }
.lp-group { padding: 8px 15px; }
.lp-group + .lp-group { border-top: 1px solid var(--border); }
.lp-group-title {
  display: block; font-size: 0.7rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--text-3); margin-bottom: 8px;
}
.lp-row {
  display: flex; align-items: flex-start; gap: 10px; padding: 7px 0; cursor: pointer;
}
.lp-row input { margin-top: 3px; accent-color: var(--blue-ink); width: 16px; height: 16px; flex-shrink: 0; }
.lp-dot { width: 12px; height: 12px; border-radius: 4px; flex-shrink: 0; margin-top: 4px; }
.lp-name { font-size: 0.87rem; font-weight: 600; min-width: 0; }
.lp-hint { display: block; font-size: 0.74rem; font-weight: 400; color: var(--text-2); margin-top: 2px; line-height: 1.35; }
.lp-state { display: block; font-size: 0.72rem; color: var(--blue-ink); font-weight: 600; margin-top: 3px; }
.lp-tag {
  display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: var(--r-pill);
  background: rgba(120,120,130,0.16); color: var(--text-2); font-size: 0.64rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.03em; vertical-align: middle;
}
.lp-tag.oficial { background: rgba(var(--green-rgb), 0.18); color: var(--green-ink); }
.lp-foot { padding: 10px 15px; border-top: 1px solid var(--border); line-height: 1.4; }

.map-legend {
  position: absolute; bottom: 12px; left: 12px; z-index: 400;
  display: flex; flex-direction: column; gap: 5px; padding: 10px 12px;
  background: var(--surface); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-md);
  max-width: 60%;
}
.lg-item { display: flex; align-items: center; gap: 7px; font-size: 0.74rem; font-weight: 600; color: var(--text); }
.lg-item i { width: 14px; height: 5px; border-radius: 3px; flex-shrink: 0; }

/* ═══ ALERTAS Y PRIORIDAD ══════════════════════════════════════════════════ */
.spot-card.priority { border-color: rgba(var(--accent-rgb), 0.55); box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.14), var(--shadow-sm); }
.priority-chip {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 10px; padding: 6px 12px;
  border-radius: var(--r-pill); background: linear-gradient(135deg, var(--accent), var(--accent-dark));
  color: #fff; font-size: 0.78rem; font-weight: 700;
}
.priority-chip b { font-variant-numeric: tabular-nums; }
.priority-chip.expired { background: rgba(120,120,130,0.2); color: var(--text-2); }
.tag-chip.group { background: rgba(var(--blue-rgb), 0.14); color: var(--blue-ink); }
.tag-chip.chain { background: rgba(var(--purple-rgb), 0.16); color: var(--purple); cursor: pointer; }
.code-input {
  text-transform: uppercase; letter-spacing: 0.25em; text-align: center;
  font-family: "SF Mono", ui-monospace, Menlo, Consolas, monospace; font-weight: 700; font-size: 1.2rem;
}

/* ═══ CADENA DE RELEVO ═════════════════════════════════════════════════════ */
.chain-viz {
  display: flex; align-items: center; gap: 8px; margin-top: 14px; flex-wrap: wrap;
  justify-content: center;
}
.chain-node {
  padding: 10px 14px; border-radius: var(--radius-sm); font-size: 0.8rem; font-weight: 650;
  background: rgba(120,120,130,0.12); color: var(--text-2); text-align: center;
}
.chain-node.me { background: linear-gradient(135deg, var(--purple), #6F42AE); color: #fff; }
.chain-node.done { background: rgba(var(--green-rgb), 0.16); color: var(--green-ink); }
.chain-arrow { color: var(--text-3); font-weight: 700; }

.chain-list { display: flex; flex-direction: column; gap: 8px; }
.chain-item {
  display: flex; align-items: center; gap: 12px; padding: 11px 13px;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--card);
}
.chain-item.current { border-color: var(--purple); box-shadow: 0 0 0 2px rgba(var(--purple-rgb), 0.15); }
.ci-pos {
  width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0; display: grid; place-items: center;
  background: rgba(var(--purple-rgb), 0.16); color: var(--purple); font-weight: 700; font-size: 0.85rem;
}
.ci-body { min-width: 0; flex: 1; }
.ci-body b { font-size: 0.9rem; }

/* ═══ GRUPOS ═══════════════════════════════════════════════════════════════ */
.two-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.group-stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 14px;
  text-align: center;
}
.group-stats b { display: block; font-size: 1.3rem; font-weight: 700; }
.group-stats span { font-size: 0.72rem; color: var(--text-2); }
.member-list { display: flex; flex-direction: column; gap: 8px; max-height: 260px; overflow-y: auto; }
.member {
  display: flex; align-items: center; gap: 11px; padding: 9px 11px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.m-body { min-width: 0; flex: 1; display: flex; flex-direction: column; }
.m-body b { font-size: 0.88rem; }

/* ── Plazas de un grupo, dentro de su ficha ──────────────────────────────────
   Antes se pintaban con `.member`, que es una fila de sólo lectura: se veían
   pero no se podía hacer nada con ellas. Ahora cada fila lleva sus acciones, y
   la que se puede reservar se distingue con el borde verde de «libre».        */
.gs-list { display: flex; flex-direction: column; gap: 9px; max-height: 320px; overflow-y: auto; }
.gs-item {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 11px 13px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card);
}
.gs-item.libre { border-color: rgba(var(--green-rgb), 0.45); background: rgba(var(--green-rgb), 0.045); }
.gs-body { min-width: 0; flex: 1 1 180px; display: flex; flex-direction: column; gap: 2px; }
.gs-body b { font-size: 0.9rem; }
.gs-side { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
@media (max-width: 460px) {
  .gs-side { width: 100%; justify-content: space-between; }
}

/* ═══ IMPACTO Y GAMIFICACIÓN ═══════════════════════════════════════════════ */
.impact-card { background: linear-gradient(135deg, rgba(var(--green-rgb), 0.08), rgba(var(--blue-rgb), 0.06)); }
.impact-big { font-size: 1.25rem; font-weight: 700; margin: 10px 0 8px; letter-spacing: -0.02em; }
.badge-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
.badge-item {
  display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center;
  padding: 16px 12px; border-radius: var(--radius); border: 1px solid var(--border);
  background: var(--card); opacity: 0.5; filter: grayscale(1);
  transition: all 0.22s var(--ease);
}
.badge-item.earned {
  opacity: 1; filter: none; border-color: rgba(var(--accent-rgb), 0.4);
  box-shadow: 0 6px 18px rgba(var(--accent-rgb), 0.12);
}
.badge-item .bi-icon { font-size: 1.9rem; }
.badge-item b { font-size: 0.86rem; }

.ranking { display: flex; flex-direction: column; }
.rk-row {
  display: flex; align-items: center; gap: 12px; padding: 11px 0;
  border-bottom: 1px solid var(--border);
}
.rk-row:last-child { border-bottom: none; }
.rk-row.me { background: rgba(var(--blue-rgb), 0.06); margin: 0 -22px; padding-left: 22px; padding-right: 22px; }
.rk-pos {
  width: 28px; text-align: center; font-weight: 700; color: var(--text-3); flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}
.rk-pos.podio { color: var(--accent); font-size: 1.1rem; }
.rk-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.rk-body b { font-size: 0.9rem; }
.rk-score { font-size: 1.15rem; font-variant-numeric: tabular-nums; }

/* ═══ ZONAS DE BAJAS EMISIONES Y VEHÍCULO ══════════════════════════════════ */
.lez-chip {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 10px; padding: 6px 12px;
  border-radius: var(--r-pill); font-size: 0.76rem; font-weight: 650; line-height: 1.3;
}
.lez-chip.bad { background: rgba(var(--red-rgb), 0.14); color: var(--red); }
.lez-chip.warn { background: rgba(var(--accent-rgb), 0.16); color: var(--accent-ink); }
.lez-chip.ok { background: rgba(var(--green-rgb), 0.14); color: var(--green-ink); }
.lez-chip.neutral { background: rgba(var(--navy-rgb), 0.1); color: var(--text-2); }

.label-picker { display: flex; gap: 8px; flex-wrap: wrap; }
.label-picker button {
  padding: 9px 15px; border-radius: 13px; font-weight: 700; font-size: 0.86rem;
  background: rgba(var(--navy-rgb), 0.08); color: var(--text-2);
  border: 2px solid transparent; transition: all 0.18s var(--ease);
}
.label-picker button:hover { background: rgba(var(--navy-rgb), 0.14); }
.label-picker button.sel {
  background: var(--lp-color, var(--blue)); color: #fff;
  border-color: var(--lp-color, var(--blue)); box-shadow: var(--shadow-sm);
}

.check-row {
  display: flex; align-items: flex-start; gap: 11px; padding: 12px 0; cursor: pointer;
}
.check-row input { margin-top: 3px; width: 18px; height: 18px; accent-color: var(--blue-ink); flex-shrink: 0; }
.check-row > span { font-size: 0.92rem; font-weight: 550; }
.check-row .muted { display: block; font-weight: 400; margin-top: 2px; line-height: 1.35; }

/* ═══ COSTE Y AHORRO ═══════════════════════════════════════════════════════ */
.reserve-context { display: flex; flex-direction: column; gap: 12px; margin-bottom: 18px; }
.savings-note {
  display: flex; align-items: center; gap: 14px; padding: 14px 16px;
  border-radius: var(--radius-sm);
  background: linear-gradient(135deg, rgba(var(--green-rgb), 0.12), rgba(var(--blue-rgb), 0.08));
  border: 1px solid rgba(var(--green-rgb), 0.25);
}
.sn-amount {
  font-size: 1.7rem; font-weight: 700; color: var(--green-ink); letter-spacing: -0.02em;
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.sn-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.savings-card { background: linear-gradient(135deg, rgba(var(--green-rgb), 0.08), rgba(var(--accent-rgb), 0.06)); }
.stat-tile.tile-accent b { color: var(--accent); }

/* ═══ «VOY DE CAMINO» ══════════════════════════════════════════════════════ */
.eta-note {
  display: flex; align-items: center; gap: 7px; margin-top: 10px; padding: 8px 12px;
  border-radius: var(--radius-sm); background: rgba(var(--blue-rgb), 0.1);
  font-size: 0.82rem; color: var(--text);
}
.eta-note .live { color: var(--accent); font-weight: 700; }
.eta-note .live::before {
  content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent); margin-right: 5px; animation: latido 1.4s ease-in-out infinite;
}
@keyframes latido { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
.nav-links { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }

/* ═══ RESPONSIVE ═══════════════════════════════════════════════════════════ */
@media (max-width: 1000px) {
  /* Móvil y tablet: se apila en vertical — mapa arriba, lista debajo — y la
     página vuelve a tener desplazamiento normal, que es lo que se espera al
     recorrerla con el pulgar. */
  .view-map { height: auto; display: block; padding: 16px; max-width: 760px; }
  .view-map .section-head p { display: block; }
  .map-layout { grid-template-columns: 1fr; flex: none; min-height: 0; }
  /* Sin la rejilla de escritorio, el envoltorio del mapa se ajusta al contenido */
  .map-wrap { height: auto; }
  #map { height: 48dvh; min-height: 300px; }
  .spot-list { height: auto; max-height: none; margin-top: 16px; }
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
}

/* Móvil girado en horizontal: el alto es minúsculo (unos 400 px). Si el mapa se
   quedara con el 48% no cabría nada, y con la lista debajo tampoco se vería el
   mapa. Se pone lado a lado, que es justo lo que pide una pantalla apaisada. */
@media (max-width: 1000px) and (orientation: landscape) and (max-height: 560px) {
  .view-map { height: 100%; display: flex; flex-direction: column; padding: 10px 14px; max-width: none; }
  .view-map .section-head { margin-bottom: 6px; }
  .view-map .section-head p { display: none; }
  .view-map .section-head h1 { font-size: 1.15rem; }
  .map-layout {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(240px, 34%);
    gap: 12px; flex: 1 1 auto; min-height: 0;
  }
  .map-wrap { height: 100%; }
  #map { height: 100%; min-height: 0; }
  .spot-list { height: 100%; margin-top: 0; overflow-y: auto; }
}
@media (max-width: 860px) {
  #auth-screen { grid-template-columns: 1fr; }
  .auth-hero { display: none; }
  .auth-card .mobile-brand { display: flex; flex-direction: column; align-items: center; gap: 10px; margin-bottom: 24px; }
  /* `img:first-child` y no `img`: la segunda imagen es el TEXTO del logotipo, un
     PNG con transparencia. Con la regla alcanzándolo también, recibía 64×64 y un
     `box-shadow`, que se dibuja alrededor de la CAJA del elemento y no de la
     parte opaca: la palabra «Parking Buddy» aparecía dentro de una tarjeta
     blanca redondeada con sombra. Se veía en cualquier móvil, en la pantalla de
     acceso, que es lo primero que ve quien llega. */
  .auth-card .mobile-brand img:first-child {
    width: 124px; height: 124px; border-radius: 0; box-shadow: none;
    filter: drop-shadow(0 12px 26px rgba(var(--navy-rgb), 0.22));
  }
  .auth-card .mobile-brand b { font-size: 1.4rem; font-weight: 700; }
}
@media (max-width: 768px) {
  .sidebar { display: none; }
  .topbar { padding: 14px max(16px, env(safe-area-inset-right)) 14px max(16px, env(safe-area-inset-left)); }
  /* La visibilidad de `.topbar .mobile-brand` se decide en el apartado del
     LOGOTIPO, al final del fichero. Ponerla también aquí es lo que escondía la
     marca en el móvil: allí hay un `display` que gana por ir después. */
  .topbar h2.view-title { display: none; }
  .view { padding: 18px 16px 100px; }
  .tabbar {
    display: flex; position: fixed; bottom: 0; left: 0; right: 0; z-index: 50;
    background: var(--surface); backdrop-filter: saturate(180%) blur(22px); -webkit-backdrop-filter: saturate(180%) blur(22px);
    border-top: 1px solid var(--border); padding: 8px 6px calc(8px + env(safe-area-inset-bottom)); justify-content: space-around;
  }
  .tab {
    flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 6px 4px;
    color: var(--text-3); font-size: 0.66rem; font-weight: 600; border-radius: 12px; transition: color 0.18s;
    cursor: pointer;
  }
  /* 🔴 La etiqueta, en UNA línea y recortada si no cabe.
     Sin esto, una traducción larga rompe la barra entera: «Mis plazas» estaba
     traducido al portugués como «Minhas vagas de estacionamento» —correcto y
     larguísimo— y en un móvil de 375 px se partía en tres renglones, empujaba
     el resto de las pestañas y dejaba la barra descuadrada. Se vio en una
     captura de la aplicación viva.
     La traducción se ha acortado (i18n-dict-11.js), pero el arreglo de verdad
     es este: la barra no puede depender de que nadie escriba una palabra larga
     en ninguno de los cuatro idiomas. Y `title` guarda el texto completo, que el
     motor de i18n también traduce. */
  .tab span {
    max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    line-height: 1.2;
  }
  .tab .ico { width: 24px; height: 24px; }
  .tab.active { color: var(--blue-ink); }
  .grid-3, .grid-2 { grid-template-columns: 1fr; }
  .field-row { grid-template-columns: 1fr; }
  h1 { font-size: 1.6rem; }
}
@media (max-width: 460px) {
  .grid-auto { grid-template-columns: 1fr; }
  .modal { padding: 22px 18px; }
}

/* ── Responsive de los componentes nuevos ────────────────────────────────── */
@media (max-width: 1000px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 768px) {
  /* La barra de filtros se desliza en horizontal en vez de crecer a lo alto */
  .filter-bar {
    flex-wrap: nowrap; overflow-x: auto; padding-bottom: 6px;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .filter-bar::-webkit-scrollbar { display: none; }
  .chip-btn, .chip-field { flex-shrink: 0; }
  .chip-field.grow { flex: 0 0 190px; }

  /* El panel de avisos ocupa el ancho útil, anclado bajo la barra superior */
  .notif-panel {
    position: fixed; top: 66px; left: 12px; right: 12px; width: auto; max-width: none;
  }
  .np-list { max-height: min(70dvh, 460px); }

  .topbar-right { gap: 8px; flex: none; }
  .pending-chip { display: none; } /* el dato se ve en Perfil y Recompensas */
  /* Con la luna ya no cabían cinco cosas y la campana se salía por la derecha
     (Luiz, 2026-09-11). En el móvil la barra se queda con logotipo · luna ·
     campana: los puntos viven bajo los botones de la portada (y en Perfil y
     Recompensas), y el idioma se elige en Perfil. */
  .topbar .points-pill { display: none; }
  #pb-lang.en-barra { display: none; }
  .icon-btn { width: 38px; height: 38px; }
  .handoff .btn { flex: 1 1 auto; }

  /* Con seis pestañas hay que apretar el texto para que no se corte */
  .tab { font-size: 0.6rem; padding: 6px 2px; }
  .tab .ico { width: 22px; height: 22px; }

  /* El panel de capas ocupa el ancho del mapa en móvil */
  .layer-panel { width: auto; left: 12px; right: 12px; top: 58px; }
  .map-legend { max-width: calc(100% - 24px); }
  .badge-grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }
}
@media (max-width: 380px) {
  .tab span { font-size: 0.55rem; }
  .tab .ico { width: 20px; height: 20px; }
}
@media (max-width: 460px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .stat-tile b { font-size: 1.6rem; }
  .input-with-btn { flex-direction: column; }
  .input-with-btn .btn { width: 100%; }
  .ledger-row { flex-direction: column; align-items: flex-start; gap: 6px; }
  .lr-side { width: 100%; justify-content: space-between; }
  .group-stats b { font-size: 1.1rem; }
  .chain-viz { flex-direction: column; }
  .chain-arrow { transform: rotate(90deg); }
  .rk-row.me { margin: 0 -18px; padding-left: 18px; padding-right: 18px; }
  .impact-big { font-size: 1.05rem; }
  /* En el chat el formulario de envío no debe apilarse: teclado y pulgar */
  .chat-form { flex-direction: row; }
  .chat-list { height: 40dvh; }
  .msg { max-width: 90%; }
  .day-picker button { width: 38px; height: 38px; }
  .code-box.big code { font-size: 1.25rem; }
  .rep-card .rep-stats b { font-size: 1.2rem; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   SISTEMA DE MAQUETACIÓN
   ───────────────────────────────────────────────────────────────────────────
   Un vocabulario común para todas las vistas. Antes cada pantalla se maquetaba
   por su cuenta: la de Comunidad usaba las pestañas del panel de administración
   y repartía atributos de estilo en línea, y el resumen de administración era
   una cuadrícula de tarjetas todas iguales donde nada destacaba sobre nada.

   Las reglas de este bloque:
     · Jerarquía antes que uniformidad. Lo importante, grande; el detalle, en
       una fila. Diez tarjetas idénticas no informan: cansan.
     · Un dato numérico no necesita una tarjeta para él. `.metrics` pone varios
       en una sola superficie, separados por una línea.
     · Todo bloque de datos puede explicarse. `.explain` es para eso, y se ve
       igual en toda la aplicación.
     · Nada de estilos en línea en el HTML generado: si hace falta una variante,
       es una clase.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Página y cabecera ──────────────────────────────────────────────────── */
.page-head { margin-bottom: 22px; }
.page-head h1 { margin-bottom: 4px; }
.page-head .sub { color: var(--text-2); font-size: 0.95rem; max-width: 62ch; line-height: 1.45; }
.page-head .actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 14px; }

/* ── Pestañas (control segmentado) ──────────────────────────────────────── */
.tabs {
  display: flex; gap: 4px; padding: 4px; margin-bottom: 22px;
  background: rgba(var(--navy-rgb), 0.05); border-radius: var(--r-pill);
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs button {
  flex: 1 1 auto; white-space: nowrap; padding: 9px 16px; border-radius: var(--r-pill);
  font-size: 0.9rem; font-weight: 600; color: var(--text-2);
  transition: background 0.18s var(--ease), color 0.18s var(--ease);
}
.tabs button:hover { color: var(--text); }
.tabs button.active { background: var(--surface-solid); color: var(--navy); box-shadow: var(--shadow-sm); }

/* ── Panel: una sección con título propio ───────────────────────────────── */
.panel {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); overflow: hidden; margin-bottom: 18px;
}
.panel-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  padding: 18px 20px 14px; flex-wrap: wrap;
}
.panel-head h2, .panel-head h3 { font-size: 1.05rem; font-weight: 650; }
.panel-head .hint { color: var(--text-2); font-size: 0.84rem; margin-top: 3px; line-height: 1.4; max-width: 58ch; }
.panel-head + .panel-body { padding-top: 0; }
.panel-body { padding: 0 20px 20px; }
.panel-body > * + * { margin-top: 14px; }
.panel.flush .panel-body { padding: 0 0 4px; }

/* ── Cifra protagonista ─────────────────────────────────────────────────── */
.hero {
  display: flex; align-items: center; gap: 22px; flex-wrap: wrap;
  padding: 24px; border-radius: var(--radius); margin-bottom: 18px;
  background: linear-gradient(135deg, rgba(var(--blue-rgb), 0.10), rgba(var(--accent-rgb), 0.07));
  border: 1px solid rgba(var(--blue-rgb), 0.16);
}
.hero-main { flex: 1 1 220px; min-width: 0; }
.hero-num {
  display: block; font-size: 3rem; line-height: 1; font-weight: 750;
  letter-spacing: -0.03em; color: var(--navy);
}
.hero-num small { font-size: 0.9rem; font-weight: 600; color: var(--text-2); letter-spacing: 0; }
.hero-label { display: block; margin-top: 6px; color: var(--text-2); font-size: 0.92rem; line-height: 1.45; }
.hero-side { flex: 0 1 auto; }
.hero.accent { background: linear-gradient(135deg, rgba(var(--accent-rgb), 0.13), rgba(var(--blue-rgb), 0.07)); border-color: rgba(var(--accent-rgb), 0.22); }
.hero.accent .hero-num { color: var(--accent-dark); }

/* ── Métricas en fila: varios números, UNA superficie ───────────────────── */
.metrics {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden; margin-bottom: 18px;
}
.metrics > div { padding: 16px 18px; border-right: 1px solid var(--border); }
.metrics > div:last-child { border-right: none; }
.metrics b {
  display: block; font-size: 1.6rem; font-weight: 700; letter-spacing: -0.02em;
  color: var(--navy); line-height: 1.15;
}
.metrics span { display: block; margin-top: 2px; font-size: 0.82rem; color: var(--text-2); line-height: 1.35; }
.metrics .m-hint { display: block; margin-top: 5px; font-size: 0.76rem; color: var(--text-3); line-height: 1.35; }
.metrics > div.good b { color: var(--green-ink); }
.metrics > div.warn b { color: var(--accent-ink); }
.metrics > div.bad b { color: var(--red); }

/* ── Lista de datos: etiqueta, valor y explicación ──────────────────────── */
.rows { display: flex; flex-direction: column; }
.rows > div {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: 13px 20px; border-top: 1px solid var(--border);
}
.rows > div:first-child { border-top: none; }
.rows .r-key { font-size: 0.9rem; font-weight: 550; }
.rows .r-key small { display: block; font-weight: 400; color: var(--text-2); font-size: 0.79rem; margin-top: 2px; line-height: 1.4; max-width: 54ch; }
.rows .r-val { font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }
.rows > div.bad .r-val { color: var(--red); }
.rows > div.good .r-val { color: var(--green-ink); }

/* ── Explicación en lenguaje llano ──────────────────────────────────────── */
.explain {
  display: flex; gap: 12px; padding: 14px 16px; border-radius: var(--radius-sm);
  background: rgba(var(--blue-rgb), 0.06); border: 1px solid rgba(var(--blue-rgb), 0.15);
  font-size: 0.88rem; line-height: 1.5; color: var(--text);
}
.explain svg { width: 18px; height: 18px; flex: 0 0 auto; margin-top: 1px; color: var(--blue-ink); }
.explain > div { flex: 1 1 auto; min-width: 0; }
.explain b { font-weight: 650; }
.explain.calm { background: rgba(var(--navy-rgb), 0.04); border-color: var(--border); color: var(--text-2); }
.explain > div { min-width: 0; }
.explain dl { display: grid; grid-template-columns: auto 1fr; gap: 5px 12px; margin-top: 9px; }
.explain dt { font-weight: 650; white-space: nowrap; }
.explain dd { color: var(--text-2); }

/* ── Estado vacío ───────────────────────────────────────────────────────── */
.empty { text-align: center; padding: 44px 24px; }
.empty .e-icon {
  width: 62px; height: 62px; margin: 0 auto 14px; border-radius: 20px;
  display: flex; align-items: center; justify-content: center; font-size: 1.7rem;
  background: rgba(var(--blue-rgb), 0.09); color: var(--blue-dark);
}
.empty h3 { margin-bottom: 6px; }
.empty p { color: var(--text-2); font-size: 0.9rem; max-width: 46ch; margin: 0 auto 18px; line-height: 1.5; }

/* ── Rejillas ───────────────────────────────────────────────────────────── */
.grid { display: grid; gap: 16px; }
.grid.auto { grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); }
.grid.auto-wide { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
.grid.two { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

/* ── Utilidades mínimas, para no volver a los estilos en línea ──────────── */
.stack { display: flex; flex-direction: column; gap: 12px; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.row-wrap { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.push { margin-left: auto; }
.center { text-align: center; }
.loading { padding: 40px; text-align: center; color: var(--text-2); font-size: 0.9rem; }
.mb0 { margin-bottom: 0; }

@media (max-width: 560px) {
  .hero { padding: 20px; gap: 16px; }
  .hero-num { font-size: 2.4rem; }
  .hero-side { width: 100%; }
  .metrics { grid-template-columns: repeat(2, 1fr); }
  .metrics > div:nth-child(2n) { border-right: none; }
  .metrics > div:nth-child(n + 3) { border-top: 1px solid var(--border); }
  .rows > div { flex-direction: column; align-items: flex-start; gap: 4px; padding-left: 16px; padding-right: 16px; }
  .panel-head, .panel-body { padding-left: 16px; padding-right: 16px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   NIVELES E INSIGNIAS
   El nivel va por los puntos GANADOS en total, nunca por el saldo: si bajara al
   canjear, el sistema castigaría justo lo que quiere fomentar. Eso se dice en la
   propia pantalla, porque si no la gente teme gastar.
   ═══════════════════════════════════════════════════════════════════════════ */
.tier-hero {
  position: relative; overflow: hidden; padding: 26px;
  border-radius: var(--radius-lg); margin-bottom: 18px; color: #fff;
  background: linear-gradient(140deg, var(--navy) 0%, var(--blue-dark) 60%, var(--blue) 100%);
  box-shadow: var(--shadow-md);
}
.tier-hero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(420px 260px at 88% 8%, rgba(255,255,255,0.22), transparent 62%),
              radial-gradient(340px 340px at 4% 108%, rgba(0,0,0,0.20), transparent 58%);
}
.tier-hero > * { position: relative; z-index: 1; }
.tier-top { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.tier-medal {
  width: 74px; height: 74px; flex-shrink: 0; border-radius: 24px;
  display: flex; align-items: center; justify-content: center; font-size: 2.3rem;
  background: rgba(255,255,255,0.16); border: 1px solid rgba(255,255,255,0.28);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.35);
}
.tier-id { flex: 1 1 200px; min-width: 0; }
.tier-name { font-size: 1.6rem; font-weight: 750; letter-spacing: -0.02em; line-height: 1.15; }
.tier-level { font-size: 0.82rem; opacity: 0.82; margin-top: 3px; }
.tier-balance { text-align: right; flex: 0 0 auto; }
.tier-balance b { display: block; font-size: 2rem; font-weight: 750; letter-spacing: -0.02em; line-height: 1; }
.tier-balance span { font-size: 0.78rem; opacity: 0.85; }

.tier-progress { margin-top: 20px; }
.tier-progress .tp-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  font-size: 0.86rem; margin-bottom: 8px; flex-wrap: wrap;
}
.tier-progress .tp-head b { font-weight: 650; }
.tier-progress .tp-head .tp-goal { opacity: 0.85; }
.tier-bar { height: 10px; border-radius: 999px; background: rgba(255,255,255,0.22); overflow: hidden; }
.tier-bar > i {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--accent-soft), var(--accent));
  transition: width 0.7s var(--ease);
}
.tier-note { margin-top: 12px; font-size: 0.8rem; opacity: 0.8; line-height: 1.45; }

/* ── Escalera de niveles ────────────────────────────────────────────────── */
.tier-ladder {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 10px;
}
.tier-step {
  text-align: center; padding: 14px 8px; border-radius: var(--radius-sm);
  background: rgba(var(--navy-rgb), 0.04); border: 1px solid var(--border);
  transition: transform 0.18s var(--ease);
}
.tier-step .ts-icon { font-size: 1.5rem; line-height: 1; filter: grayscale(1); opacity: 0.45; }
.tier-step .ts-name { display: block; margin-top: 6px; font-size: 0.8rem; font-weight: 600; color: var(--text-2); }
.tier-step .ts-min { display: block; margin-top: 2px; font-size: 0.72rem; color: var(--text-3); }
.tier-step.reached { background: rgba(var(--blue-rgb), 0.08); border-color: rgba(var(--blue-rgb), 0.22); }
.tier-step.reached .ts-icon { filter: none; opacity: 1; }
.tier-step.reached .ts-name { color: var(--text); }
.tier-step.current {
  background: linear-gradient(140deg, rgba(var(--accent-rgb), 0.16), rgba(var(--blue-rgb), 0.10));
  border-color: rgba(var(--accent-rgb), 0.4); transform: translateY(-3px);
  box-shadow: var(--shadow-sm);
}
.tier-step.current .ts-name { color: var(--accent-dark); font-weight: 700; }

/* Insignia compacta, para el perfil y las cabeceras */
.tier-chip {
  display: inline-flex; align-items: center; gap: 7px; padding: 6px 13px 6px 9px;
  border-radius: var(--r-pill); font-size: 0.84rem; font-weight: 650;
  background: rgba(var(--blue-rgb), 0.10); color: var(--navy);
  border: 1px solid rgba(var(--blue-rgb), 0.2);
}
.tier-chip .tc-icon { font-size: 1rem; line-height: 1; }

/* ═══════════════════════════════════════════════════════════════════════════
   PREMIOS
   ═══════════════════════════════════════════════════════════════════════════ */
.reward-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(228px, 1fr)); gap: 16px; }
.rw {
  position: relative; display: flex; flex-direction: column; gap: 10px;
  padding: 22px 18px 18px; text-align: center; overflow: hidden;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease), border-color 0.2s;
}
.rw:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
.rw-icon {
  width: 68px; height: 68px; margin: 0 auto; border-radius: 21px;
  display: flex; align-items: center; justify-content: center; font-size: 2rem;
  background: linear-gradient(140deg, rgba(var(--blue-rgb), 0.14), rgba(var(--accent-rgb), 0.10));
}
.rw h3 { font-size: 1rem; }
.rw .rw-desc { font-size: 0.82rem; color: var(--text-2); line-height: 1.45; flex: 1 1 auto; }
.rw .rw-cost {
  display: inline-flex; align-items: center; gap: 6px; justify-content: center;
  font-weight: 750; font-size: 1.05rem; color: var(--accent-dark);
}
.rw .rw-gap { font-size: 0.78rem; color: var(--text-2); }
.rw .rw-bar { height: 6px; border-radius: 999px; background: rgba(var(--navy-rgb), 0.08); overflow: hidden; }
.rw .rw-bar > i { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--blue), var(--accent)); transition: width 0.6s var(--ease); }
.rw.ready { border-color: rgba(var(--green-rgb), 0.35); box-shadow: 0 0 0 3px rgba(var(--green-rgb), 0.09), var(--shadow-sm); }
.rw.locked .rw-icon { filter: grayscale(0.75); opacity: 0.7; }
.rw-flag {
  position: absolute; top: 12px; right: 12px; padding: 3px 9px; border-radius: var(--r-pill);
  font-size: 0.7rem; font-weight: 700; letter-spacing: 0.02em; text-transform: uppercase;
  background: rgba(var(--green-rgb), 0.14); color: var(--green-ink);
}

/* ═══════════════════════════════════════════════════════════════════════════
   VALES
   Un vale es un código que se dicta en voz alta en un comercio, así que lo
   primero que se ve tiene que ser el código, grande y legible.
   ═══════════════════════════════════════════════════════════════════════════ */
.voucher {
  display: flex; gap: 0; overflow: hidden; margin-bottom: 14px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
.voucher-stub {
  flex: 0 0 92px; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 4px; padding: 18px 10px; text-align: center;
  background: linear-gradient(150deg, rgba(var(--blue-rgb), 0.12), rgba(var(--accent-rgb), 0.10));
  border-right: 2px dashed var(--border);
}
.voucher-stub .vs-icon { font-size: 1.9rem; line-height: 1; }
.voucher-stub .vs-cost { font-size: 0.74rem; font-weight: 700; color: var(--accent-dark); }
.voucher-main { flex: 1 1 auto; min-width: 0; padding: 16px 18px; }
.voucher-main h3 { font-size: 1rem; margin-bottom: 2px; }
.voucher-code {
  display: flex; align-items: center; gap: 10px; margin: 10px 0 8px; flex-wrap: wrap;
}
.voucher-code code {
  font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 1.3rem;
  font-weight: 700; letter-spacing: 0.08em; color: var(--navy);
  padding: 8px 14px; border-radius: var(--radius-sm);
  background: rgba(var(--navy-rgb), 0.05); border: 1px dashed rgba(var(--navy-rgb), 0.22);
}
.voucher.spent .voucher-code code { color: var(--text-3); text-decoration: line-through; border-style: solid; }
.voucher.spent .voucher-stub { filter: grayscale(0.9); opacity: 0.75; }
.voucher-meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 0.8rem; color: var(--text-2); }
.voucher-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }

.v-state { display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px; border-radius: var(--r-pill); font-size: 0.76rem; font-weight: 650; }
.v-state.ok { background: rgba(var(--green-rgb), 0.13); color: var(--green-ink); }
.v-state.neutral { background: rgba(var(--navy-rgb), 0.08); color: var(--text-2); }
.v-state.bad { background: rgba(var(--red-rgb), 0.12); color: var(--red); }

/* Los tres pasos de «cómo se usa un vale» */
.howto { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 14px; }
.howto > div { display: flex; gap: 11px; align-items: flex-start; }
.howto .h-num {
  flex: 0 0 26px; height: 26px; border-radius: 999px; display: flex;
  align-items: center; justify-content: center; font-size: 0.8rem; font-weight: 700;
  background: rgba(var(--blue-rgb), 0.13); color: var(--blue-dark);
}
.howto .h-txt { font-size: 0.85rem; line-height: 1.45; }
.howto .h-txt b { display: block; font-weight: 650; margin-bottom: 1px; }
.howto .h-txt span { color: var(--text-2); }

@media (max-width: 560px) {
  .tier-hero { padding: 20px; }
  .tier-medal { width: 60px; height: 60px; font-size: 1.9rem; border-radius: 19px; }
  .tier-name { font-size: 1.3rem; }
  .tier-balance { text-align: left; width: 100%; }
  .voucher { flex-direction: column; }
  .voucher-stub { flex: 0 0 auto; flex-direction: row; gap: 10px; border-right: none; border-bottom: 2px dashed var(--border); padding: 12px; }
  .voucher-code code { font-size: 1.15rem; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PANTALLA DE CARGA
   Se pinta antes de que corra nada de JavaScript (está en el HTML, no la genera
   la aplicación) y se retira cuando lo esencial ya está en memoria: la sesión,
   los avisos y los datos de la primera vista.

   Dos cosas la gobiernan:
     · Nunca puede quedarse colgada. Tiene un plazo máximo, y si algo falla se
       retira igual. Una pantalla de carga eterna es peor que ninguna.
     · No parpadea. Si todo estaba en caché y termina en 80 ms, se mantiene un
       instante mínimo: un destello es más molesto que una espera corta.
   ═══════════════════════════════════════════════════════════════════════════ */
#splash {
  position: fixed; inset: 0; z-index: 9999;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 22px;
  background:
    radial-gradient(900px 600px at 78% -8%, #E4EDFB, transparent 62%),
    radial-gradient(700px 500px at -8% 108%, #E4EDFB, transparent 58%),
    #F5F7FA;
  transition: opacity 0.45s var(--ease), visibility 0.45s;
}
#splash.gone { opacity: 0; visibility: hidden; pointer-events: none; }

.splash-logo {
  width: 128px; height: 128px; border-radius: 32px;
  box-shadow: 0 24px 60px rgba(27, 58, 105, 0.22), 0 8px 20px rgba(27, 58, 105, 0.12);
  animation: splashIn 0.7s var(--ease) both, splashFloat 3.2s var(--ease) 0.7s infinite;
}


.splash-step {
  font-size: 0.86rem; color: var(--text-2); min-height: 1.2em;
  animation: splashIn 0.7s var(--ease) 0.2s both;
}
.splash-track { width: 172px; height: 5px; border-radius: 999px; background: rgba(27, 58, 105, 0.10); overflow: hidden; }
.splash-track > i {
  display: block; height: 100%; width: 0; border-radius: 999px;
  background: linear-gradient(90deg, var(--blue), var(--accent));
  transition: width 0.4s var(--ease);
}

@keyframes splashIn {
  from { opacity: 0; transform: translateY(14px) scale(0.96); }
  to { opacity: 1; transform: none; }
}
@keyframes splashFloat {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-9px); }
}
/* Quien pide menos animación no debe recibir un logotipo flotando */
@media (prefers-reduced-motion: reduce) {
  .splash-logo, .splash-word, .splash-step { animation: none; }
  #splash { transition: none; }
}
@media (max-width: 460px) {
  .splash-logo { width: 100px; height: 100px; border-radius: 26px; }
  .splash-word { width: 168px; }
}

/* ── Perfil ─────────────────────────────────────────────────────────────── */
.pf-hero {
  display: flex; align-items: center; gap: 20px; flex-wrap: wrap;
  padding: 24px; margin-bottom: 18px; border-radius: var(--radius);
  background: linear-gradient(135deg, rgba(var(--blue-rgb), 0.09), rgba(var(--accent-rgb), 0.06));
  border: 1px solid rgba(var(--blue-rgb), 0.15);
}
.pf-avatar { width: 78px; height: 78px; font-size: 1.85rem; flex-shrink: 0; }
.pf-id { flex: 1 1 220px; min-width: 0; }
.pf-id h1 { font-size: 1.75rem; margin-bottom: 2px; }
.pf-badges { margin-top: 12px; }
.pf-label-hint { margin-top: 6px; }
.pf-rep-rows { margin: 0 -20px; }

/* ── Ranking ────────────────────────────────────────────────────────────── */
.rk-avatar { width: 32px; height: 32px; font-size: 0.78rem; flex-shrink: 0; }

@media (max-width: 560px) {
  .pf-hero { padding: 20px; gap: 14px; }
  .pf-avatar { width: 62px; height: 62px; font-size: 1.4rem; }
  .pf-id h1 { font-size: 1.4rem; }
  .pf-rep-rows { margin: 0 -16px; }
}

/* ── Piezas que estaban escritas a mano en el HTML generado ─────────────── */
/* Tamaños de avatar: el tamaño es maquetación, no un dato de la persona. */
.avatar-xs { width: 28px; height: 28px; font-size: 0.72rem; flex-shrink: 0; }
.avatar-sm { width: 32px; height: 32px; font-size: 0.78rem; flex-shrink: 0; }

/* Globo del marcador del mapa */
.pop-free { color: var(--green-ink); font-weight: 600; }
.pop-dist { color: var(--text-2); }

/* Cuenta atrás de la ventana de prioridad, dentro de la tarjeta de la plaza */
.pr-count { font-variant-numeric: tabular-nums; letter-spacing: 0.02em; }

/* ── Utilidades de espaciado y ajuste ───────────────────────────────────────
   Sustituyen a los 66 atributos de estilo que estaban escritos a mano dentro
   del HTML generado. La escala es fija a propósito (4-6-10-14 px): con valores
   libres, cada pantalla acababa con su propio ritmo vertical y el conjunto se
   veía descosido.                                                            */
.mt-1 { margin-top: 3px; }
.mt-2 { margin-top: 7px; }
.mt-3 { margin-top: 11px; }
.mt-4 { margin-top: 15px; }
.mb-4 { margin-bottom: 16px; }
.pad-3 { padding: 12px 14px; }
.pad-4 { padding: 16px; }
.pad-5 { padding: 20px; }
.pad-6 { padding: 24px; }
.gap-sm { gap: 8px; margin-top: 14px; }
.grow-1 { flex: 1; }
.faded { opacity: 0.75; }
.narrow { max-width: 420px; }
.ink-green { color: var(--green-ink); }
.ink-accent { color: var(--accent-ink); }

/* Título de sección dentro de una vista o un modal */
.sec-title { margin: 26px 0 14px; }
.sec-title.sm { margin: 18px 0 10px; font-size: 1.05rem; }

/* Mini-mapa de los modales (elegir el pin, ver una plaza) */
.mini-map {
  height: 180px; border-radius: var(--radius-sm); overflow: hidden;
  border: 1px solid var(--border); position: relative; z-index: 0;
}
.mini-map.tall { height: 200px; }
/* Pin de avistamiento (capa separada, sin garantía): distinto del relevo. */
.sight-pin { font-size: 24px; text-align: center; filter: drop-shadow(0 2px 3px rgba(0,0,0,.4));
  background: #FFF4E0; border: 2px dashed #F09000; border-radius: 50% 50% 50% 0;
  width: 30px; height: 30px; line-height: 28px; transform: rotate(-45deg); }
.sight-pin { }
.sight-pin > * { display: inline-block; transform: rotate(45deg); }
/* Chincheta central fija: el mapa se mueve debajo y el pin marca SIEMPRE el centro
   (= la ubicación que se guardará). Antes no había marca visible y no se veía dónde
   caía la plaza. pointer-events:none para no bloquear el arrastre del mapa. */
.mini-map.pickable::after {
  content: '📍'; position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -100%); font-size: 30px; line-height: 1;
  z-index: 500; pointer-events: none; filter: drop-shadow(0 2px 3px rgba(0,0,0,.35));
}
.mini-map.pickable::before {
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: 50%;
  background: rgba(10,132,255,.9); box-shadow: 0 0 0 3px rgba(10,132,255,.25);
  z-index: 500; pointer-events: none;
}

/* Punto de la leyenda que representa los ámbitos especiales del SER (naranja y
   rojo a la vez). Los colores son los oficiales del Geoportal, no de la marca. */
.lp-dot.especial { background: linear-gradient(135deg, #FF9F0A, #FF453A); }

/* ── Aviso de que no hay conexión con el servidor ────────────────────────────
   Es una barra fija, no un toast: un toast se va a los tres segundos y el
   problema sigue ahí. Antes, cuando el servidor no respondía, cada panel de la
   aplicación pintaba el texto crudo del navegador («Failed to fetch»), en inglés
   y sin decir qué hacer. Esto lo sustituye por un aviso que se explica, reintenta
   solo cada cinco segundos y se retira en cuanto el servidor vuelve.          */
#offline-bar {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
  z-index: 9998; display: flex; align-items: center; gap: 12px;
  padding: 12px 16px 12px 18px; border-radius: var(--r-pill);
  background: var(--navy); color: #fff; font-size: 0.88rem; font-weight: 550;
  box-shadow: 0 16px 40px rgba(var(--navy-rgb), 0.35), 0 4px 12px rgba(0, 0, 0, 0.18);
  animation: obEntra 0.35s var(--ease) both;
  max-width: calc(100vw - 32px);
}
#offline-bar .ob-dot {
  width: 9px; height: 9px; border-radius: 50%; background: var(--accent);
  flex-shrink: 0; animation: obLatido 1.4s ease-in-out infinite;
}
#offline-bar .ob-btn {
  padding: 6px 13px; border-radius: var(--r-pill); font-size: 0.82rem; font-weight: 650;
  background: rgba(255, 255, 255, 0.18); color: #fff; white-space: nowrap;
  transition: background 0.18s var(--ease);
}
#offline-bar .ob-btn:hover { background: rgba(255, 255, 255, 0.3); }

@keyframes obEntra {
  from { opacity: 0; transform: translateX(-50%) translateY(14px); }
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
@keyframes obLatido {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}

@media (max-width: 768px) {
  /* Por encima de la barra de pestañas, no debajo */
  #offline-bar { bottom: calc(76px + env(safe-area-inset-bottom, 0px)); font-size: 0.83rem; }
}
@media (prefers-reduced-motion: reduce) {
  #offline-bar { animation: none; }
  #offline-bar .ob-dot { animation: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PANTALLA DE INICIO
   Es lo primero que se ve al entrar, y también donde lleva el logotipo. Tiene
   dos trabajos a la vez, y por eso no es un folleto:
     · A quien llega nuevo le explica qué es esto y por qué merece la pena.
     · A quien ya lo usa le da lo suyo primero (nivel, lo que tiene abierto) y
       los accesos directos. Una presentación que sólo presenta se convierte en
       un obstáculo a partir de la segunda vez.
   Las cifras de comunidad son las REALES de la base de datos. Un número
   inventado en una pantalla de bienvenida es la peor manera de empezar.
   ═══════════════════════════════════════════════════════════════════════════ */
.view-home { max-width: 1080px; }

/* ── Portada ────────────────────────────────────────────────────────────── */
.hm-hero {
  position: relative; overflow: hidden; color: #fff;
  padding: 44px 44px 40px; border-radius: var(--radius-lg); margin-bottom: 22px;
  background: linear-gradient(135deg, var(--navy) 0%, var(--blue-dark) 52%, var(--blue) 100%);
  box-shadow: 0 24px 60px rgba(var(--navy-rgb), 0.28), 0 6px 16px rgba(var(--navy-rgb), 0.14);
}
/* Una sola luz, y suave. Eran dos degradados radiales —uno blanco arriba a la
   derecha y una sombra abajo a la izquierda— que junto a la calzada de puntos
   llenaban la portada de adorno y le daban ese aire de plantilla generada. */
.hm-hero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(560px 320px at 92% -18%, rgba(255, 255, 255, 0.16), transparent 66%);
}

/* Aquí había un `::after` que dibujaba una LÍNEA DISCONTINUA DE CALZADA de 62 px
   cruzando el pie de la portada, justo por debajo de las pastillas de nivel y
   puntos. En la pantalla no se leía como una carretera: se leía como unos trazos
   sueltos y descuadrados debajo de «215 para Plata», que es exactamente cómo lo
   describió Luiz. Quitado. La marca ya está en el color, el logotipo y el
   emblema; no necesita que le pintemos el asfalto detrás.                     */

.hm-hero > * { position: relative; z-index: 1; }

.hm-top { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.hm-logo {
  width: 118px; height: 118px; border-radius: 26px; flex-shrink: 0;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.3);
  animation: hmFlota 4.5s var(--ease) infinite;
}
.hm-titles { flex: 1 1 300px; min-width: 0; }
.hm-titles h1 {
  font-size: 2.5rem; line-height: 1.06; font-weight: 750; letter-spacing: -0.03em;
}
.hm-titles h1 i { font-style: normal; color: var(--accent-soft); }
.hm-titles p {
  margin-top: 12px; font-size: 1.12rem; line-height: 1.5; opacity: 0.93; max-width: 46ch;
}
/* ── Las dos acciones principales ────────────────────────────────────────────
   «Buscar plaza» y «Estoy aparcado» son la aplicación entera. Antes eran dos
   botones del tamaño de cualquier otro, uno de ellos casi transparente sobre el
   azul, y competían con el resto de la portada. Ahora ocupan lo que les
   corresponde: dos tarjetas grandes, en blanco y en el verde de la marca —los
   dos colores que más resaltan sobre el azul marino—, cada una con una segunda
   línea que dice qué hace.                                                   */
.hm-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin-top: 26px; }
/* Dos líneas centradas: [icono Título] arriba y el subtítulo debajo. Es lo que
   hace que el botón no pueda verse descentrado a ningún ancho — el icono viaja
   pegado al título en vez de flotar a un lado del bloque de texto. */
.btn-cta {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 5px; width: 100%;
  padding: 14px 18px; border-radius: var(--radius); text-align: center;
  font-weight: 700; letter-spacing: -0.01em;
  transition: transform 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.btn-cta .cta-head { display: flex; align-items: center; gap: 11px; min-width: 0; }
.btn-cta .cta-ico {
  width: 38px; height: 38px; border-radius: 12px; flex: none;
  display: flex; align-items: center; justify-content: center;
}
.btn-cta .cta-ico svg { width: 20px; height: 20px; }
.btn-cta b { font-size: 1.06rem; font-weight: 750; }
/* `.btn` impone `white-space: nowrap` a todo el botón, así que sin esto un
   subtítulo largo se saldría en vez de partirse: el francés («Dites quand vous
   libérez la vôtre») no cabe en un móvil de 360 px. */
.btn-cta i {
  font-style: normal; font-weight: 500; font-size: 0.82rem; opacity: 0.78;
  line-height: 1.3; white-space: normal;
}
.btn-cta:hover { transform: translateY(-2px); }

.cta-buscar {
  background: #fff; color: var(--navy);
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.24);
}
.cta-buscar .cta-ico { background: rgba(var(--blue-rgb), 0.12); color: var(--blue-dark); }
.cta-buscar:hover { box-shadow: 0 18px 40px rgba(0, 0, 0, 0.3); }

.cta-aparcado {
  background: linear-gradient(135deg, var(--accent), var(--accent-dark)); color: #fff;
  box-shadow: 0 12px 30px rgba(var(--accent-rgb), 0.4);
}
.cta-aparcado .cta-ico { background: rgba(255, 255, 255, 0.22); color: #fff; }
.cta-aparcado:hover { box-shadow: 0 18px 40px rgba(var(--accent-rgb), 0.48); }

/* Chips de bienvenida: nivel y saldo, para quien ya viene de antes */
.hm-you { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 22px; }
.hm-chip {
  display: inline-flex; align-items: center; gap: 8px; padding: 7px 14px;
  border-radius: var(--r-pill); font-size: 0.86rem; font-weight: 650;
  background: rgba(255, 255, 255, 0.15);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.22);
}
.hm-chip .hc-icon { font-size: 1.05rem; line-height: 1; }

@keyframes hmFlota {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-7px); }
}

/* ── Los tres pasos del relevo, sobre una carretera ─────────────────────── */
.hm-road { position: relative; padding: 8px 0 4px; }
.hm-steps {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
  position: relative; z-index: 1;
}
/* La calzada que une los tres pasos */
.hm-road::before {
  content: ""; position: absolute; z-index: 0;
  left: 12%; right: 12%; top: 46px; height: 4px; border-radius: 2px;
  background: repeating-linear-gradient(90deg,
    rgba(var(--navy-rgb), 0.28) 0 14px, transparent 14px 30px);
}
.hm-step { text-align: center; }
.hm-step .hs-num {
  width: 62px; height: 62px; margin: 0 auto 14px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.6rem; font-weight: 750;
  background: #fff; color: var(--navy);
  box-shadow: 0 8px 22px rgba(var(--navy-rgb), 0.18), inset 0 0 0 2px rgba(var(--blue-rgb), 0.25);
}
.hm-step:nth-child(2) .hs-num { color: var(--accent-dark); box-shadow: 0 8px 22px rgba(var(--accent-rgb), 0.22), inset 0 0 0 2px rgba(var(--accent-rgb), 0.3); }
.hm-step h3 { font-size: 1.02rem; margin-bottom: 5px; }
.hm-step p { font-size: 0.88rem; color: var(--text-2); line-height: 1.5; max-width: 30ch; margin: 0 auto; }

/* ── Tarjetas de ventaja ────────────────────────────────────────────────── */
.hm-perks { display: grid; grid-template-columns: repeat(auto-fill, minmax(258px, 1fr)); gap: 16px; }
.hm-perk {
  padding: 20px; border-radius: var(--radius);
  background: var(--card); border: 1px solid var(--border); box-shadow: var(--shadow-sm);
  transition: transform 0.22s var(--ease), box-shadow 0.22s var(--ease), border-color 0.22s;
}
.hm-perk:hover {
  transform: translateY(-4px); box-shadow: var(--shadow-md);
  border-color: rgba(var(--blue-rgb), 0.28);
}
.hm-perk .hp-icon {
  width: 46px; height: 46px; border-radius: 14px; margin-bottom: 13px;
  display: flex; align-items: center; justify-content: center; font-size: 1.45rem;
  background: linear-gradient(140deg, rgba(var(--blue-rgb), 0.14), rgba(var(--accent-rgb), 0.10));
}
.hm-perk h3 { font-size: 1rem; margin-bottom: 5px; }
.hm-perk p { font-size: 0.87rem; color: var(--text-2); line-height: 1.5; }
.hm-perk .hp-tag {
  display: inline-block; margin-top: 11px; padding: 3px 10px; border-radius: var(--r-pill);
  font-size: 0.74rem; font-weight: 700; letter-spacing: 0.01em;
  background: rgba(var(--accent-rgb), 0.12); color: var(--accent-ink);
}

/* ── Cifras reales de la comunidad ──────────────────────────────────────── */
.hm-numbers {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 4px; padding: 26px 22px; border-radius: var(--radius);
  background: linear-gradient(135deg, rgba(var(--blue-rgb), 0.09), rgba(var(--accent-rgb), 0.06));
  border: 1px solid rgba(var(--blue-rgb), 0.15);
}
.hm-numbers > div { text-align: center; padding: 8px 12px; }
.hm-numbers b {
  display: block; font-size: 2.1rem; font-weight: 750; letter-spacing: -0.03em;
  color: var(--navy); line-height: 1.05;
}
.hm-numbers span { display: block; margin-top: 4px; font-size: 0.83rem; color: var(--text-2); line-height: 1.35; }

/* ── Lo que tienes abierto ahora ────────────────────────────────────────── */
.hm-now { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
.hm-now a, .hm-now button {
  display: flex; align-items: center; gap: 13px; text-align: left; width: 100%;
  padding: 15px 17px; border-radius: var(--radius-sm);
  background: var(--card); border: 1px solid var(--border); box-shadow: var(--shadow-sm);
  transition: transform 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.hm-now button:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.hm-now .hn-num {
  font-size: 1.5rem; font-weight: 750; color: var(--navy); line-height: 1;
  min-width: 1.6em; text-align: center;
}
.hm-now .hn-txt { font-size: 0.87rem; line-height: 1.35; }
.hm-now .hn-txt b { display: block; font-weight: 650; }
.hm-now .hn-txt span { color: var(--text-2); font-size: 0.8rem; }
.hm-now .urge .hn-num { color: var(--accent-dark); }

/* ── Accesos directos ───────────────────────────────────────────────────────
   Lo que ocupa el sitio que dejaron libres las dos secciones plegadas y el
   bloque de cierre. Son funcionalidades, no explicaciones.                   */
.hm-quick { display: grid; grid-template-columns: repeat(auto-fill, minmax(178px, 1fr)); gap: 11px; }
.hm-quick button {
  display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
  width: 100%; text-align: left; padding: 15px 16px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card); cursor: pointer;
  transition: border-color 0.18s var(--ease), transform 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.hm-quick button svg { width: 22px; height: 22px; color: var(--blue-ink); margin-bottom: 5px; }
.hm-quick button b { font-size: 0.92rem; font-weight: 650; }
.hm-quick button span { font-size: 0.78rem; color: var(--text-2); line-height: 1.35; }
.hm-quick button:hover {
  transform: translateY(-2px); box-shadow: var(--shadow-md);
  border-color: rgba(var(--blue-rgb), 0.32);
}
.hm-quick button:focus-visible { outline: 2px solid transparent; box-shadow: 0 0 0 4px var(--accent-soft); }

/* ── Secciones plegables ────────────────────────────────────────────────────
   `<details>` nativo y no un botón con JavaScript: funciona sin scripts, se
   puede abrir con el teclado sin que nosotros lo programemos y el navegador ya
   sabe que su contenido está oculto, así que el buscador de la página (Ctrl+F)
   lo encuentra igual. Lo único que hay que hacer es esconder el triángulo del
   sistema, que cada navegador dibuja a su manera.                            */
.panel-fold { padding: 0; }
.panel-fold > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 18px 20px; cursor: pointer; list-style: none;
  border-radius: var(--radius);
  transition: background 0.18s var(--ease);
}
.panel-fold > summary::-webkit-details-marker { display: none; }
.panel-fold > summary::marker { content: ""; }
.panel-fold > summary:hover { background: rgba(var(--blue-rgb), 0.045); }
.panel-fold > summary:focus-visible { outline: 2px solid transparent; box-shadow: 0 0 0 4px var(--accent-soft); }
.panel-fold .fold-txt { min-width: 0; }
.panel-fold .fold-txt h3 { font-size: 1.06rem; margin: 0; }
.panel-fold .fold-txt .hint { margin-top: 3px; }
.panel-fold .fold-mark {
  flex: none; display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 50%; color: var(--text-2);
  background: rgba(var(--navy-rgb), 0.06);
  transition: transform 0.24s var(--ease), background 0.18s;
}
.panel-fold[open] > summary .fold-mark { transform: rotate(180deg); background: rgba(var(--blue-rgb), 0.12); color: var(--blue-ink); }
.panel-fold[open] > summary { border-bottom: 1px solid var(--border); border-radius: var(--radius) var(--radius) 0 0; }
.panel-fold > .panel-body { padding: 18px 20px 20px; }

/* ── Invitar: era un bloque con estilos escritos a mano en el HTML ──────────
   Tenía un `border: 2px solid #0A84FF` y un degradado con dos colores en
   hexadecimal puestos en el atributo `style`, más una pastilla de código de
   22 px también en línea. Nada de eso respetaba los tokens del proyecto —el
   mismo azul existe como `--blue`— y bastaba para que la portada pareciera
   montada a pedazos. Ahora es una clase, y usa los colores de la marca.      */
.panel-ref { border: 1px solid rgba(var(--blue-rgb), 0.3); }
.ref-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.ref-code {
  font-family: "SF Mono", ui-monospace, Menlo, Consolas, monospace;
  font-size: 1.3rem; font-weight: 800; letter-spacing: 0.08em;
  padding: 9px 18px; border-radius: var(--radius-sm);
  background: linear-gradient(135deg, var(--blue), var(--blue-dark)); color: #fff;
}
.ref-stat {
  display: inline-flex; align-items: center; padding: 6px 13px; border-radius: var(--r-pill);
  font-size: 0.82rem; font-weight: 600;
  background: rgba(var(--blue-rgb), 0.09); color: var(--blue-dark);
}

/* La marca de la barra lateral y la de móvil llevan a Inicio: se nota */
.sb-brand, .topbar .mobile-brand { cursor: pointer; }

/* ── Adaptación ─────────────────────────────────────────────────────────── */
@media (max-width: 860px) {
  .hm-hero { padding: 30px 24px 32px; }
  .hm-titles h1 { font-size: 1.95rem; }
  .hm-titles p { font-size: 1rem; }
  .hm-logo { width: 94px; height: 94px; border-radius: 22px; }
}
@media (max-width: 640px) {
  .hm-hero { padding: 26px 20px 28px; border-radius: var(--radius); }
  .hm-top { gap: 16px; }
  .hm-logo { width: 82px; height: 82px; border-radius: 19px; }
  .hm-titles h1 { font-size: 1.65rem; }
  /* Las dos acciones, una debajo de otra y a todo el ancho: en el móvil es
     donde más importa que se vean, y en dos columnas el subtítulo no cabe. */
  .hm-actions { margin-top: 20px; grid-template-columns: 1fr; gap: 11px; }
  /* El centrado de los dos botones ya no depende del ancho: está en la propia
     estructura (icono junto al título, subtítulo debajo, todo en columna
     centrada). Aquí sólo se aprieta un poco, que en el móvil ocupan el ancho
     entero y las dos tarjetas van una encima de otra. */
  .btn-cta { padding: 13px 16px; }
  .panel-fold > summary { padding: 15px 16px; }
  .panel-fold > .panel-body { padding: 15px 16px 17px; }
  .hm-quick { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px; }
  .hm-quick button { padding: 13px 12px; }
  .ref-code { font-size: 1.1rem; padding: 8px 14px; }
  /* Los pasos en vertical: la carretera horizontal ya no tiene sentido */
  .hm-steps { grid-template-columns: 1fr; gap: 22px; }
  .hm-road::before {
    left: 50%; right: auto; top: 20px; bottom: 20px; width: 4px; height: auto;
    transform: translateX(-50%);
    background: repeating-linear-gradient(180deg,
      rgba(var(--navy-rgb), 0.28) 0 14px, transparent 14px 30px);
  }
  .hm-step .hs-num { width: 52px; height: 52px; font-size: 1.35rem; margin-bottom: 10px; }
  .hm-numbers b { font-size: 1.7rem; }
}
@media (prefers-reduced-motion: reduce) {
  .hm-logo { animation: none; }
  .hm-perk:hover, .hm-now button:hover, .hm-quick button:hover, .btn-cta:hover { transform: none; }
  .panel-fold .fold-mark { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   LOGOTIPO
   Son dos piezas: el icono (un pin, en PNG con transparencia) y el texto
   «Parking Buddy», que es una imagen con su propia tipografía. El texto NO se
   reescribe con la fuente del sistema: un logotipo tiene la letra que tiene.
   Hay dos versiones del texto — la original para fondos claros y una aclarada
   para los oscuros, porque el azul marino sobre azul marino no se lee.
   ═══════════════════════════════════════════════════════════════════════════ */
/* `object-fit: contain` es la red de seguridad: si algún día alguien fija las dos
   medidas, la imagen se ajusta dentro en vez de estirarse. */
.wordmark { display: block; height: auto; max-width: 100%; object-fit: contain; }

/* ── Barra lateral: icono arriba, texto debajo ───────────────────────────── */
.sb-brand {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 12px 10px 20px; text-align: center;
}
.sb-brand img:first-child {
  width: 104px; height: 104px; border-radius: 0;
  filter: drop-shadow(0 8px 18px rgba(var(--navy-rgb), 0.22));
  transition: transform 0.25s var(--ease);
  box-shadow: none;
}
.sb-brand:hover img:first-child { transform: translateY(-3px) scale(1.03); }
.sb-brand .wordmark { width: 152px; margin-top: 2px; }

/* Pantallas bajas: en horizontal y compacto, si no el logotipo se come el menú */
@media (max-height: 760px) {
  .sb-brand { flex-direction: row; gap: 10px; padding: 8px 8px 14px; text-align: left; }
  .sb-brand img:first-child { width: 52px; height: 52px; }
  .sb-brand .wordmark { width: 98px; margin-top: 0; }
}

/* ── Barra superior en móvil ─────────────────────────────────────────────────
   El emblema y el texto tienen que quedar alineados por su base óptica y no
   por la caja: el PNG del texto trae aire arriba y abajo, así que centrarlo
   sin más lo dejaba flotando alto. Se le da su alto real y `flex: none` a los
   dos, para que la marca no se estruje cuando el título de la vista y las
   pastillas de puntos aprietan desde la derecha.                            */
/* 🔴 Aquí estaba el motivo de que en el móvil NO se viera el logotipo en
   ninguna parte. Esta regla decía `display: none`, y la que lo enciende en
   pantalla pequeña —`@media (max-width: 768px) { … display: flex }`— está unas
   mil líneas MÁS ARRIBA. Una media query no añade especificidad: entre dos
   reglas que valen lo mismo gana la última del fichero, así que el `none` de
   aquí pisaba al `flex` de allí **siempre**. Comprobado en producción: en un
   móvil de 375 px la barra superior sale con los puntos, la campana y el
   selector de idioma, y sin marca ninguna. Es el mismo tipo de error que el de
   las cabeceras de `firebase.json` del 2026-09-05: no lo decide el orden en que
   uno lo piensa, lo decide el orden en que está escrito.

   Se invierte el planteamiento: la marca de la barra superior está VISIBLE por
   omisión y se esconde en escritorio, donde su sitio es la barra lateral. Así
   la regla que la enciende no depende de dónde caiga en el fichero.          */
.topbar .mobile-brand { display: flex; align-items: center; gap: 6px; flex: none; min-width: 0; }
@media (min-width: 769px) {
  .topbar .mobile-brand { display: none; }
}
.topbar .mobile-brand img:first-child {
  width: 56px; height: 56px; border-radius: 0; box-shadow: none; flex: none;
}
/* Más grande desde el 2026-09-11, a petición de Luiz (dos veces): 56 px el emblema.
   El texto va en SU proporción real: el PNG (texto-240) mide 240×125, dos líneas
   («parking» / «buddy»), 1,92:1. La caja anterior de 124×41 (3:1) lo dejaba
   flotando en el centro con 22 px de aire a cada lado por el object-fit, y
   parecía lejos del emblema (captura de Luiz, misma noche). 96×50 es 1,92:1 y
   casa con los atributos del <img>. */
.topbar .mobile-brand .wordmark { width: 96px; height: 50px; flex: none; }
/* Muy estrecho: se queda sólo el emblema. Con el texto al lado, la marca y las
   pastillas de la derecha se pisaban por debajo de unos 380 px. */
@media (max-width: 330px) {
  .topbar .mobile-brand .wordmark { display: none; }
}

/* ── Pantalla de carga ──────────────────────────────────────────────────── */
.splash-word {
  width: 190px; height: auto; display: block; object-fit: contain;
  animation: splashIn 0.7s var(--ease) 0.12s both;
}

/* ── Pantalla de acceso ─────────────────────────────────────────────────────
   El emblema se define arriba, junto a `.auth-brand`, para que las
   adaptaciones por alto de pantalla puedan pisarlo. Aquí sólo el texto.      */
/* `min(240px, 100%)`: el ancho fijo desbordaba el hueco en la franja estrecha
   entre 861 y 1000 px, donde la columna de la portada se queda justa. */
.auth-brand-txt .wordmark { width: min(240px, 100%); }
.auth-brand-txt span { display: block; margin-top: 8px; font-size: 0.9rem; opacity: 0.82; }

.auth-card .mobile-brand .wordmark { width: 210px; margin: 0 auto 4px; }

/* ═══════════════════════════════════════════════════════════════════════════
   DIÁLOGOS DE CONFIRMACIÓN
   Sustituyen al `confirm()` del navegador, que abre el cuadro del sistema
   operativo: gris, cuadrado, con el nombre del navegador y en el idioma del
   sistema. Y sobre todo, no puede explicar nada — no admite formato, ni un aviso
   destacado, ni distinguir una acción destructiva de una normal.
   ═══════════════════════════════════════════════════════════════════════════ */
.dlg-backdrop {
  position: fixed; inset: 0; z-index: 10000;
  display: flex; align-items: center; justify-content: center; padding: 22px;
  background: rgba(var(--navy-rgb), 0.42);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  animation: dlgFondo 0.22s var(--ease) both;
}
.dlg {
  width: 100%; max-width: 400px; text-align: center;
  padding: 28px 26px 24px; border-radius: var(--radius-lg);
  background: var(--card); box-shadow: var(--shadow-lg);
  animation: dlgEntra 0.3s var(--ease) both;
}
.dlg-icon {
  width: 58px; height: 58px; margin: 0 auto 16px; border-radius: 18px;
  display: flex; align-items: center; justify-content: center; font-size: 1.7rem;
  background: linear-gradient(140deg, rgba(var(--blue-rgb), 0.13), rgba(var(--accent-rgb), 0.10));
}
.dlg.peligro .dlg-icon {
  background: linear-gradient(140deg, rgba(var(--red-rgb), 0.14), rgba(var(--red-rgb), 0.06));
}
.dlg h3 { font-size: 1.2rem; font-weight: 700; letter-spacing: -0.02em; margin-bottom: 8px; }
.dlg p { color: var(--text-2); font-size: 0.93rem; line-height: 1.5; }
/* El detalle es la letra pequeña que el diálogo del sistema no podía dar: qué
   pasa con los puntos, qué es irreversible, qué alternativa hay. */
.dlg-detalle {
  margin-top: 14px; padding: 12px 14px; border-radius: var(--radius-sm);
  background: rgba(var(--navy-rgb), 0.045); border: 1px solid var(--border);
  font-size: 0.83rem; color: var(--text-2); line-height: 1.5; text-align: left;
}
.dlg-actions { display: flex; gap: 10px; margin-top: 22px; }
.dlg-actions .btn { flex: 1; }
.dlg-actions .btn:focus-visible { outline: 3px solid rgba(var(--blue-rgb), 0.4); outline-offset: 2px; }

@keyframes dlgFondo { from { opacity: 0; } to { opacity: 1; } }
@keyframes dlgEntra {
  from { opacity: 0; transform: translateY(18px) scale(0.96); }
  to { opacity: 1; transform: none; }
}

@media (max-width: 460px) {
  .dlg { padding: 24px 20px 20px; }
  .dlg-actions { flex-direction: column-reverse; }
}
@media (prefers-reduced-motion: reduce) {
  .dlg-backdrop, .dlg { animation: none; }
}

/* ═══ MAPA A PANTALLA COMPLETA (2) ═══════════════════════════════════════════
   El mapa es la pantalla principal del producto y en el móvil se quedaba con
   media pantalla. Se resuelve con una clase y no con la Fullscreen API del
   navegador a propósito: Safari en iPhone no la admite para nada que no sea un
   vídeo, y el móvil es justo donde más falta hace. Así funciona igual en los
   cuatro sitios: móvil, tablet, portátil y escritorio.                       */

/* Segundo botón flotante, debajo del de capas. */
.map-fab-full { top: 62px; }
.map-fab-full .mff-in,
.map-fab-full .mff-out { display: grid; place-items: center; }
.map-fab-full .mff-out { display: none; }
.map-wrap.map-full .map-fab-full .mff-in { display: none; }
.map-wrap.map-full .map-fab-full .mff-out { display: grid; }

/* `dvh` y no `vh`: en el móvil la barra del navegador aparece y desaparece, y
   con `vh` el mapa queda cortado por debajo justo cuando está a pantalla
   completa, que es cuando más se nota. */
.map-wrap.map-full {
  position: fixed; inset: 0; z-index: 900;
  height: 100dvh; width: 100vw; max-width: none; margin: 0;
  border-radius: 0; background: var(--card);
}
.map-wrap.map-full #map {
  height: 100dvh; min-height: 0;
  border-radius: 0; border: none; box-shadow: none;
}
/* Los mandos se apartan de la muesca y de la barra de gestos del móvil. */
.map-wrap.map-full .map-fab      { top: calc(12px + env(safe-area-inset-top)); }
.map-wrap.map-full .map-fab-full { top: calc(62px + env(safe-area-inset-top)); }
.map-wrap.map-full .layer-panel  { top: calc(12px + env(safe-area-inset-top)); max-height: calc(100dvh - 96px); }
.map-wrap.map-full .map-legend   { bottom: calc(14px + env(safe-area-inset-bottom)); }

/* Mientras el mapa lo ocupa todo, la página de detrás no se arrastra ni asoma
   la barra de pestañas del móvil por encima. */
body.con-mapa-full { overflow: hidden; }
body.con-mapa-full .tabbar { display: none; }

/* Capa sin datos en esta zona: la SER y la ZBE son de Madrid, y fuera de Madrid
   no hay nada que encender. */
.lp-row-off { opacity: 0.5; }
.lp-row-off input { cursor: not-allowed; }

/* ═══ TABLETS Y PANTALLAS TÁCTILES (2) ═══════════════════════════════════════
   Entre el móvil y el escritorio había una franja que no atendía ninguna regla:
   una tablet en vertical caía en las de móvil y se quedaba con un mapa de 48dvh
   en una pantalla de diez pulgadas, desaprovechada.                          */
@media (min-width: 700px) and (max-width: 1000px) {
  #map { height: 60dvh; }
  .grid-3 { grid-template-columns: repeat(3, 1fr); }
  .grid-4 { grid-template-columns: repeat(4, 1fr); }
  /* Con este ancho caben dos plazas por fila y se ve el doble sin desplazar. */
  .spot-list {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    align-content: start; gap: 12px;
  }
}

/* Tablet apaisada: ya cabe la rejilla de escritorio, con la lista más estrecha
   para que el mapa se quede con el sitio que merece. */
@media (min-width: 1001px) and (max-width: 1180px) {
  .map-layout { grid-template-columns: minmax(0, 1fr) clamp(260px, 28vw, 320px); }
}

/* Dedos, no ratón: ningún blanco de pulsación baja de 44 px, que es el mínimo
   que recomiendan tanto Apple como Google. */
@media (pointer: coarse) {
  .icon-btn, .map-fab, .chip-btn { min-width: 44px; min-height: 44px; }
  .link-btn { padding: 6px 2px; }
}

/* ── Aviso de correo sin confirmar (1) ────────────────────────────────────── */
.verify-banner {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 0; padding: 11px 18px;
  background: #FFF6E5; border-bottom: 1px solid #F3D9A4; color: #6B4E10;
  font-size: 0.9rem; line-height: 1.4;
}
.verify-banner.hidden { display: none; }
.verify-banner .vb-ico { font-size: 1.05rem; flex: none; }
.verify-banner .vb-txt { flex: 1 1 240px; min-width: 0; }
.verify-banner .btn { flex: none; }
@media (max-width: 460px) {
  .verify-banner { padding: 10px 14px; font-size: 0.85rem; }
}

/* ── Motivos de denuncia (7) ──────────────────────────────────────────────── */
.motivos { display: flex; flex-direction: column; gap: 8px; }
.motivo {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  cursor: pointer; transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
}
.motivo:hover { border-color: var(--blue-ink); }
.motivo input { margin-top: 2px; flex: none; }
.motivo span { display: flex; flex-direction: column; gap: 2px; font-size: 0.92rem; }
.motivo small { color: var(--text-2); font-size: 0.8rem; line-height: 1.35; }
.motivo:has(input:checked) { border-color: var(--blue-ink); background: rgba(var(--blue-rgb), 0.05); }

/* ── Administración · cola de denuncias (7) ───────────────────────────────── */
.report-list { display: flex; flex-direction: column; gap: 12px; }
.report-card { padding: 16px 18px; }
.rep-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.rep-linea { margin: 0 0 6px; font-size: 0.94rem; line-height: 1.45; }
.rep-nota {
  margin: 0 0 8px; padding: 9px 12px; font-size: 0.9rem; line-height: 1.45;
  background: var(--surface); border-left: 3px solid var(--border); border-radius: 0 8px 8px 0;
  color: var(--text-2);
}
/* La señal más útil de la cola: si la llegada se verificó por GPS o no. */
.rep-gps.ok { color: var(--green-ink, #1B7A4B); font-weight: 600; }
.rep-gps.warn { color: #B26A00; font-weight: 600; }
.rep-acciones { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
@media (max-width: 460px) {
  .rep-acciones .btn { flex: 1 1 auto; }
}

/* ── Menú de tres puntos (⋮) ───────────────────────────────────────────────
   Va en cada tarjeta que tiene más de dos acciones. Antes se apilaban todos los
   botones en fila y la tarjeta acababa siendo una botonera; con las acciones de
   limpieza (renovar, eliminar) eso ya no cabía. */
.kebab-wrap { position: relative; }
.kebab-btn {
  display: grid; place-items: center; width: 34px; height: 34px; border-radius: 10px;
  color: var(--text-3); cursor: pointer; transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.kebab-btn:hover { background: rgba(var(--accent-rgb), 0.13); color: var(--accent-dark); }
.kebab-btn:focus-visible { outline: 2px solid transparent; box-shadow: 0 0 0 4px var(--accent-soft); }
.kebab-menu {
  position: absolute; right: 0; top: 38px; z-index: 40; min-width: 208px;
  background: var(--card); border: 1px solid var(--border); border-radius: 14px;
  box-shadow: var(--shadow-md); padding: 6px; animation: pop 0.16s var(--ease);
}
.kebab-menu button {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 10px 12px; border-radius: 10px; font-size: 0.9rem; font-weight: 550;
  color: var(--text); cursor: pointer;
}
.kebab-menu button:hover { background: rgba(var(--accent-rgb), 0.13); color: var(--accent-dark); }
.kebab-menu button.danger { color: var(--danger, #c0392b); }
.kebab-menu button.danger:hover { background: rgba(192, 57, 43, 0.10); color: var(--danger, #c0392b); }
.kebab-sep { height: 1px; background: var(--border); margin: 5px 8px; }
/* Aviso de plaza vencida: se lee antes de leer la fecha. */
.badge.expired { background: rgba(120,120,130,0.16); color: var(--text-3); }

/* ══ PORTADA (rediseño del 2026-09-11, docs/diseno/portada) ══════════════════
   La portada ES el mapa: enseña plazas antes de pedir nada. Encima flota UNA
   tarjeta con lo que hay en marcha, sólo si hay algo; desde abajo sube una hoja
   con la pregunta y las dos acciones apiladas a todo el ancho. Sin degradado,
   sin adorno: dos colores planos —marino y verde— sobre blanco. */
.view-portada { position: relative; z-index: 0; isolation: isolate; height: 100%; min-height: 560px; overflow: hidden; background: #E6ECF4; }
/* Un contexto de apilamiento propio: los paneles y controles de Leaflet llevan
   z-index de 400 a 1000 y, sin esto, salían al contexto raíz y obligaban a subir
   la hoja por encima de la barra fija del móvil (z 50), que quedaba TAPADA. Se
   vio en el móvil de Luiz: «no queda nada debajo de los botones». */
.portada-map { position: absolute; top: 0; left: 0; right: 0; bottom: 0; cursor: pointer; background: #E6ECF4; }
/* `bottom` lo ajusta mountHomeMap a la altura de la hoja: así el mapa sólo
   ocupa lo que se ve, la atribución de OpenStreetMap queda a la vista justo
   encima de la hoja, y el encuadre de los pines no cuenta con la mitad tapada. */
.portada-map .leaflet-control-attribution { font-size: 10px; background: rgba(255, 255, 255, 0.72); }
.portada-pin {
  display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 50%;
  background: var(--accent-dark); color: #fff; font-weight: 800; font-size: 13px; line-height: 1;
  box-shadow: 0 0 0 6px rgba(var(--accent-rgb), 0.22);
}
.portada-pin b { font-weight: 800; }
.portada-now {
  position: absolute; top: 14px; left: 18px; right: 18px; z-index: 1100;
  display: flex; align-items: center; gap: 12px; height: 62px; padding: 0 16px; width: auto;
  border-radius: 18px; background: var(--card); color: var(--text); text-align: left;
  box-shadow: 0 10px 30px rgba(var(--navy-rgb), 0.14);
}
.portada-now .pn-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; box-shadow: 0 0 0 4px rgba(var(--blue-rgb), 0.18); }
.portada-now .pn-txt { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.portada-now .pn-txt b { font-size: 0.93rem; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.portada-now .pn-txt span { font-size: 0.8rem; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.portada-now .pn-more { font-size: 0.78rem; font-weight: 700; color: var(--text-2); }
.portada-now .pc-chev svg { width: 20px; height: 20px; opacity: 0.45; }
.portada-sheet {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 1200;
  display: flex; flex-direction: column; background: var(--card); color: var(--text);
  border-radius: 30px 30px 0 0; padding: 8px 20px 14px;
  box-shadow: 0 -18px 50px rgba(var(--navy-rgb), 0.16);
}
/* La hoja mide lo justo (2026-09-11, Luiz: «el mapa más cerca del 50 %»): los
   márgenes se estrechan y los botones bajan a escala 0,85 —92 → 78 px, icono
   48 → 42— sin cambiar sus proporciones. En un móvil de 812 px el mapa pasa de
   un tercio a algo más del 40 % de la pantalla. */
.portada-handle { width: 44px; height: 5px; border-radius: 3px; background: rgba(var(--navy-rgb), 0.16); margin: 0 auto 12px; }
.portada-hola { font-size: 0.88rem; font-weight: 500; color: var(--text-2); letter-spacing: 0.01em; }
/* El titular en el azul del logotipo (--blue), como el botón: Luiz pidió que la
   portada fuera armónica con la marca. 4,6:1 sobre blanco; es texto grande. */
/* Peso 700 y no 800: a Luiz le parecía «demasiado relleno». Y el espaciado un poco
   menos apretado, que con el trazo más fino respira mejor. */
.portada-h1 { margin: 4px 0 0; font-size: 1.9rem; line-height: 1; font-weight: 700; letter-spacing: -0.025em; color: var(--blue-ink); }
.portada-h1 i { font-style: normal; color: var(--accent-dark); }
.portada-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }
.portada-cta {
  display: flex; align-items: center; gap: 12px; width: 100%; height: 78px; padding: 0 16px 0 14px;
  border-radius: 22px; text-align: left; transition: transform 0.18s var(--ease);
}
.portada-cta:hover { transform: translateY(-2px); }
.portada-cta .pc-ico { width: 42px; height: 42px; border-radius: 14px; display: flex; align-items: center; justify-content: center; flex: none; }
.portada-cta .pc-ico svg { width: 21px; height: 21px; }
.portada-cta .pc-txt { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; }
.portada-cta .pc-txt b { font-size: 1.1rem; font-weight: 700; letter-spacing: -0.02em; }
.portada-cta .pc-txt i { font-style: normal; font-size: 0.78rem; font-weight: 500; line-height: 1.3; }
.portada-cta .pc-chev svg { width: 20px; height: 20px; opacity: 0.6; }
/* El azul del logotipo (--blue), no el marino: Luiz pidió que los botones fueran
   armónicos con la marca. Blanco sobre #066CEC da 4,6:1; el subtítulo va casi
   opaco para no bajar de 4,5:1 en texto pequeño. */
.portada-cta.cta-buscar { background: var(--blue); color: #fff; box-shadow: none; }
.portada-cta.cta-buscar .pc-ico { background: rgba(255, 255, 255, 0.16); color: #fff; }
.portada-cta.cta-buscar .pc-txt i { color: rgba(255, 255, 255, 0.92); }
.portada-cta.cta-aparcado { background: var(--accent-dark); color: #fff; box-shadow: none; }
.portada-cta.cta-aparcado .pc-ico { background: rgba(255, 255, 255, 0.18); color: #fff; }
.portada-cta.cta-aparcado .pc-txt i { color: rgba(255, 255, 255, 0.94); }
/* Es un botón: lleva a Recompensas. En el móvil es donde viven los puntos desde
   que la pastilla salió de la barra (2026-09-11). */
.portada-chips { display: flex; align-items: center; gap: 8px; margin-top: 12px; padding: 0 4px; min-height: 32px; width: 100%; text-align: left; font: inherit; font-size: 0.82rem; font-weight: 600; color: var(--text-2); }
.portada-chips .pch-pts { color: var(--text); font-weight: 700; }
.portada-chips .pch-chev { margin-left: auto; display: flex; }
.portada-chips .pch-chev svg { width: 16px; height: 16px; opacity: 0.45; }
.portada-chips .dot { width: 3px; height: 3px; border-radius: 50%; background: rgba(var(--navy-rgb), 0.3); }
/* En el móvil la barra inferior es fija y va por encima: la hoja le deja sitio. */
@media (max-width: 860px) {
  .view-portada .portada-sheet { padding-bottom: calc(84px + env(safe-area-inset-bottom)); }
}
/* En pantalla ancha la hoja no se estira a todo el ancho: se queda como una
   tarjeta centrada sobre el mapa. */
@media (min-width: 861px) {
  .portada-sheet { left: 50%; right: auto; width: min(560px, calc(100% - 48px)); transform: translateX(-50%); }
  .portada-now { left: 50%; right: auto; width: min(560px, calc(100% - 48px)); transform: translateX(-50%); }
}

/* ══ ACTIVIDAD: las dos listas de siempre, una debajo de otra ═════════════════ */
.view-actividad > div > .view { padding: 0; max-width: none; animation: none; }
.view-actividad > div + div { margin-top: 32px; }

/* ══ EL RELEVO ACTIVO (2026-09-11, docs/diseno/portada/RelevoActivo.dc.html) ═══
   Se mira conduciendo: una acción grande y clara, y lo justo para reconocer al
   otro coche. Colores planos, sin degradados. */
.view-relevo { max-width: 560px; }
.rv-head { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.rv-back {
  width: 44px; height: 44px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  color: var(--text); flex: none; margin-left: -8px;
}
.rv-back svg { width: 24px; height: 24px; }
.rv-back:hover { background: rgba(var(--navy-rgb), 0.06); }
.rv-title { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.rv-kicker { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-2); }
.rv-title b { font-size: 1.25rem; font-weight: 800; letter-spacing: -0.025em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rv-pill {
  display: flex; align-items: center; gap: 6px; height: 32px; padding: 0 12px; border-radius: 999px; flex: none;
  background: rgba(var(--blue-rgb), 0.10); color: var(--blue-dark); font-size: 0.8rem; font-weight: 700;
}
.rv-pill i { width: 8px; height: 8px; border-radius: 50%; background: var(--blue); }
.rv-card { background: var(--card); border-radius: 22px; border: 1.5px solid rgba(var(--navy-rgb), 0.08); margin-bottom: 14px; }
.rv-row { display: flex; align-items: center; gap: 14px; padding: 16px 18px; }
.rv-row .avatar { width: 48px; height: 48px; font-size: 1rem; flex: none; }
.rv-who { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.rv-who b { font-size: 1rem; font-weight: 700; letter-spacing: -0.01em; }
.rv-who .rv-real { font-weight: 500; color: var(--text-2); }
.rv-sep { height: 1px; background: rgba(var(--navy-rgb), 0.08); margin: 0 18px; }
/* La matrícula con tipografía de placa: se lee de un vistazo desde el coche. */
.rv-plate {
  display: flex; align-items: center; height: 40px; border: 2px solid var(--navy); border-radius: 8px; overflow: hidden; flex: none;
  background: #fff;
}
.rv-plate i { display: block; width: 12px; height: 100%; background: var(--blue-dark); }
.rv-plate b { padding: 0 12px; font-size: 1.1rem; font-weight: 800; letter-spacing: 0.08em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.rv-steps { padding: 18px; display: flex; flex-direction: column; gap: 14px; }
.rv-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.rv-step { display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 8px 14px; border-radius: 14px; }
.rv-step > svg, .rv-step .rv-num { flex: none; }
.rv-step svg { width: 20px; height: 20px; }
.rv-step .rv-num {
  width: 22px; height: 22px; border-radius: 50%; border: 2px solid currentColor;
  display: flex; align-items: center; justify-content: center; font-size: 0.75rem; font-weight: 800;
}
.rv-step div { display: flex; flex-direction: column; min-width: 0; }
.rv-step b { font-size: 0.86rem; font-weight: 700; }
.rv-step span { font-size: 0.76rem; opacity: 0.85; }
.rv-step.done { background: rgba(var(--accent-rgb), 0.12); color: var(--green-ink); }
.rv-step.todo { background: rgba(var(--blue-rgb), 0.10); color: var(--blue-dark); }
.rv-eta { display: flex; align-items: center; gap: 8px; font-size: 0.86rem; color: var(--text-2); flex-wrap: wrap; }
.rv-eta svg { width: 18px; height: 18px; color: var(--blue-ink); flex: none; }
.rv-eta .live { color: var(--blue-dark); font-weight: 600; }
.rv-main {
  display: flex; align-items: center; justify-content: center; gap: 12px; width: 100%; height: 72px; border-radius: 22px;
  background: var(--accent-dark); color: #fff; font-size: 1.25rem; font-weight: 800; letter-spacing: -0.02em;
  box-shadow: 0 12px 30px rgba(var(--accent-rgb), 0.28); margin-bottom: 14px; transition: transform 0.18s var(--ease);
}
.rv-main:hover { transform: translateY(-2px); }
.rv-main svg { width: 24px; height: 24px; }
.rv-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.rv-actions button {
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  height: 68px; border-radius: 18px; background: var(--card); border: 1.5px solid rgba(var(--navy-rgb), 0.10); color: var(--text);
  font-size: 0.76rem; font-weight: 700;
}
.rv-actions button svg { width: 22px; height: 22px; }
.rv-actions button.on { background: var(--navy); border-color: var(--navy); color: #fff; }
.rv-actions button .mini-badge { position: absolute; top: 8px; right: 10px; }
.rv-foot { display: flex; justify-content: center; margin-top: 8px; }
.rv-foot .link-btn { min-height: 44px; padding: 0 12px; color: var(--text-2); font-weight: 600; }

/* ══ ENTRAR CON HUELLA: lo primero del formulario de acceso (2026-09-12) ═══════
   Cuando este dispositivo tiene passkey, la huella es la puerta principal y la
   contraseña la alternativa. Botón alto, con el nombre de la persona debajo. */
.bio-login { margin: 0 0 14px; }
.bio-login-btn {
  display: flex; align-items: center; gap: 14px; width: 100%; min-height: 62px; padding: 10px 18px;
  border-radius: 14px; background: var(--navy); color: #fff; text-align: left; cursor: pointer;
  box-shadow: 0 8px 22px rgba(15, 38, 72, 0.22); transition: transform 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.bio-login-btn:hover { transform: translateY(-1px); box-shadow: 0 12px 28px rgba(15, 38, 72, 0.28); }
.bio-login-btn svg { width: 30px; height: 30px; flex: none; color: var(--accent-soft, #7FE07A); }
.bio-login-btn span { display: flex; flex-direction: column; line-height: 1.2; }
.bio-login-btn b { font-size: 1.02rem; font-weight: 700; }
.bio-login-btn small { font-size: 0.8rem; opacity: 0.8; font-weight: 500; }
.bio-login-o { display: flex; align-items: center; gap: 10px; margin: 14px 0 4px; color: var(--text-3, var(--text-2)); font-size: 0.8rem; }
.bio-login-o::before, .bio-login-o::after { content: ''; flex: 1; height: 1px; background: var(--border); }
[data-theme="dark"] .bio-login-btn { background: var(--blue); }

/* ══ EL ICONO DE AYUDA (i) junto a las etiquetas (2026-09-12) ══════════════════
   Un botón —en el móvil no hay hover— que abre una burbuja con la explicación. */
.field label, .chip-field { position: relative; }
.chip-field .ayuda { margin-left: 0; }
/* Las pestañas del perfil: misma pastilla que las demás pestañas de la app. */
.pf-tabs { position: sticky; top: 0; z-index: 5; }
.pf-tab > .panel, .pf-tab > .grid, .pf-tab > details { margin-bottom: 16px; }
.ayuda {
  display: inline-flex; align-items: center; justify-content: center; width: 17px; height: 17px; margin-left: 4px;
  border-radius: 50%; border: 1.5px solid var(--text-3); color: var(--text-3); background: transparent;
  font: 700 0.68rem/1 Georgia, 'Times New Roman', serif; font-style: italic; vertical-align: text-bottom; cursor: pointer; flex: none;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.ayuda:hover, .ayuda.on { color: #fff; background: var(--blue); border-color: var(--blue); }
.ayuda-pop {
  position: absolute; left: 0; top: calc(100% + 8px); z-index: 60; display: block; width: min(320px, calc(100vw - 32px));
  padding: 10px 12px; border-radius: 12px; background: var(--navy); color: #fff; font-size: 0.8rem; font-weight: 500; line-height: 1.45;
  text-transform: none; letter-spacing: 0; box-shadow: 0 12px 30px rgba(15, 38, 72, 0.28); white-space: normal;
  animation: fadeUp 0.18s var(--ease);
}
.ayuda-pop::before { content: ''; position: absolute; left: 14px; top: -6px; width: 12px; height: 12px; background: var(--navy); transform: rotate(45deg); border-radius: 2px; }
[data-theme="dark"] .ayuda-pop, [data-theme="dark"] .ayuda-pop::before { background: #1E3A6B; }

/* ══ PAÍS → CIUDAD, sin texto libre (§019, 2026-09-12) ═════════════════════════ */
.lugar-busca { display: flex; gap: 8px; }
.lugar-busca .input { flex: 1; min-width: 0; }
.lugar-busca .btn { flex: none; padding: 0 16px; }
.lugar-elegida { display: flex; align-items: center; gap: 10px; min-height: 46px; }
.lugar-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 10px 14px; border-radius: 12px;
  background: rgba(var(--blue-rgb), 0.08); border: 1px solid rgba(var(--blue-rgb), 0.2); color: var(--text); font-size: 0.92rem;
}
.lugar-res { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.lugar-res:empty { display: none; }
.lugar-opt {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; padding: 10px 14px; border-radius: 12px;
  background: var(--card); border: 1.5px solid var(--border); color: var(--text); text-align: left; cursor: pointer; transition: border-color 0.15s;
}
.lugar-opt:hover { border-color: var(--blue-ink); }
.lugar-opt b { font-size: 0.95rem; }
.lugar-opt span { font-size: 0.8rem; color: var(--text-2); }
select.input { appearance: auto; -webkit-appearance: auto; }

/* ══ LOS COCHES DE LA CUENTA (§019) ════════════════════════════════════════════ */
.coche-opts { display: flex; flex-wrap: wrap; gap: 8px; }
.coche-lista { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.coche-fila { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 12px; border: 1.5px solid var(--border); background: var(--card); }
.coche-fila.en-uso { border-color: rgba(var(--blue-rgb), 0.45); background: rgba(var(--blue-rgb), 0.05); }
.coche-fila .rv-plate { height: 34px; }
.coche-fila .rv-plate b { font-size: 0.95rem; padding: 0 10px; }
.coche-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.coche-txt b { font-size: 0.92rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ok-txt { color: var(--green-ink); font-weight: 600; }
.coche-add { display: block; padding-top: 6px; border-top: 1px dashed var(--border); }
.coche .field-row { margin-bottom: 0; }

/* ══ AVISO DE BIOMETRÍA: una línea fina encima de la barra (2026-09-11) ════════
   Antes era una tarjeta flotante que, con la portada nueva, caía sobre «Estoy
   aparcado». Por debajo de los modales (100) y por encima del contenido. */
.bio-bar {
  /* 66 px: la barra mide 63 y así el aviso queda 3 px por encima de ella y por
     debajo del botón verde, sin pisarlo (medido: antes solapaba 7 px). */
  position: fixed; left: 12px; right: 12px; bottom: calc(66px + env(safe-area-inset-bottom)); z-index: 45;
  display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 4px 4px 4px 14px;
  border-radius: 14px; background: var(--navy); color: #fff; font-family: inherit;
  box-shadow: 0 10px 30px rgba(var(--navy-rgb), 0.28);
}
.bio-bar-ico { width: 22px; height: 22px; flex: none; color: var(--accent-soft); }
.bio-bar-txt { flex: 1; min-width: 0; font-size: 0.86rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bio-bar-on {
  flex: none; height: 34px; padding: 0 14px; border-radius: 10px; background: var(--accent); color: #0F2648;
  font-size: 0.86rem; font-weight: 800; cursor: pointer;
}
.bio-bar-x { flex: none; width: 36px; height: 34px; border-radius: 10px; display: flex; align-items: center; justify-content: center; color: rgba(255, 255, 255, 0.75); cursor: pointer; }
.bio-bar-x svg { width: 18px; height: 18px; }
.bio-bar-x:hover { background: rgba(255, 255, 255, 0.10); color: #fff; }
/* En pantalla ancha no hay barra inferior: el aviso baja al borde. */
@media (min-width: 861px) {
  .bio-bar { left: auto; right: 24px; bottom: 24px; max-width: 460px; }
}

/* ══ ACTIVIDAD (2026-09-11, docs/diseno/portada/Actividad.dc.html) ═══════════
   Plazas y turnos en una pantalla, por bloques; la hora manda en cada fila. */
.view-actividad { max-width: 640px; }
.act-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; margin-bottom: 18px; }
.act-head h1 { margin: 0; font-size: 2rem; line-height: 1; font-weight: 800; letter-spacing: -0.03em; }
.act-head .link-btn { min-height: 44px; font-weight: 700; }
.act-sec { margin-bottom: 22px; }
.act-sec-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 0 4px 10px 4px; }
.act-sec-head h2 { margin: 0; font-size: 0.75rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-2); }
.act-sec-head .link-btn { min-height: 44px; font-size: 0.82rem; font-weight: 700; }
.act-list { display: flex; flex-direction: column; background: var(--card); border-radius: 20px; border: 1.5px solid rgba(var(--navy-rgb), 0.08); overflow: visible; }
.act-row {
  display: flex; align-items: flex-start; gap: 14px; padding: 14px 12px 14px 16px; width: 100%; text-align: left; color: var(--text);
  border-top: 1px solid rgba(var(--navy-rgb), 0.08);
}
.act-row:first-child { border-top: 0; }
button.act-row { cursor: pointer; }
button.act-row:hover { background: rgba(var(--navy-rgb), 0.03); }
.act-row.apagada .act-txt, .act-row.apagada .act-hora { opacity: 0.6; }
.act-hora {
  display: flex; flex-direction: column; align-items: center; justify-content: center; width: 56px; height: 56px; border-radius: 16px; flex: none;
  background: rgba(var(--navy-rgb), 0.08); color: var(--text);
}
.act-hora b { font-size: 1rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1; }
.act-hora span { font-size: 0.6rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.8; margin-top: 3px; white-space: nowrap; }
.act-hora.navy { background: var(--navy); color: #fff; }
.act-hora.verde { background: rgba(var(--accent-rgb), 0.14); color: var(--green-ink); }
.act-ico { width: 56px; height: 56px; flex: none; display: flex; align-items: center; justify-content: center; }
.act-ico svg { width: 22px; height: 22px; }
.act-ico.done, .act-ico.completed { color: var(--green-ink); }
.act-ico.cancelled { color: var(--text-3); }
.act-txt { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; padding-top: 6px; }
.act-txt b { font-size: 0.97rem; font-weight: 700; letter-spacing: -0.01em; }
.act-txt > span { font-size: 0.82rem; color: var(--text-2); }
.act-acts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.act-pill {
  display: flex; align-items: center; gap: 6px; height: 30px; padding: 0 10px; border-radius: 999px; flex: none; margin-top: 13px;
  background: rgba(var(--blue-rgb), 0.10); color: var(--blue-dark); font-size: 0.76rem; font-weight: 700;
}
.act-pill i { width: 7px; height: 7px; border-radius: 50%; background: var(--blue); }
.act-row .kebab-wrap { margin-top: 6px; }
/* Los bloques de siempre debajo: sin el padding duplicado de la vista antigua */
.view-actividad #received-block, .view-actividad #schedules-block { margin-top: 8px; }

/* ══ DETALLE DE PLAZA (2026-09-11, docs/diseno/portada/DetallePlaza.dc.html) ═══
   Hoja sobre el mapa al tocar un pin. El mapa crea su propio contexto de
   apilamiento (misma lección que la portada): Leaflet lleva z-index 400–1000 y,
   sin esto, la hoja tendría que subir por encima de la barra y de los modales. */
.map-wrap { z-index: 0; isolation: isolate; }
.spot-sheet {
  position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 1100;
  display: flex; flex-direction: column; gap: 10px; padding: 8px 20px 18px;
  background: var(--card); color: var(--text); border-radius: 26px;
  box-shadow: 0 18px 50px rgba(var(--navy-rgb), 0.18); animation: fadeUp 0.3s var(--ease);
}
.ss-handle { width: 44px; height: 5px; border-radius: 3px; background: rgba(var(--navy-rgb), 0.16); margin: 2px auto 4px; }
.ss-close { position: absolute; top: 10px; right: 10px; width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: var(--text-2); }
.ss-close:hover { background: rgba(var(--navy-rgb), 0.06); color: var(--text); }
.ss-close svg { width: 18px; height: 18px; }
.ss-prio { display: flex; align-items: center; gap: 10px; margin: 0; min-height: 44px; padding: 0 14px; border-radius: 14px; font-size: 0.86rem; font-weight: 700; }
.ss-prio svg { width: 18px; height: 18px; flex: none; }
.ss-prio.mine { background: rgba(var(--accent-rgb), 0.12); color: var(--green-ink); }
.ss-prio.theirs { background: rgba(var(--navy-rgb), 0.06); color: var(--text-2); }
.ss-prio.expired { display: none; }
.ss-prio .pr-count { font-variant-numeric: tabular-nums; }
.ss-title { margin: 0; font-size: 1.5rem; line-height: 1.05; font-weight: 800; letter-spacing: -0.03em; padding-right: 40px; }
.ss-sub { margin: -4px 0 0; font-size: 0.9rem; color: var(--text-2); }
.ss-tags { display: flex; gap: 6px; flex-wrap: wrap; }
.ss-when { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.ss-when > div { display: flex; flex-direction: column; gap: 2px; padding: 12px 14px; border-radius: 16px; background: var(--bg); }
.ss-when span { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-2); }
.ss-when b { font-size: 1.25rem; font-weight: 800; letter-spacing: -0.02em; }
.ss-owner { display: flex; align-items: center; gap: 12px; }
.ss-owner .avatar { flex: none; }
.ss-owner > div { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.ss-owner b { font-size: 0.95rem; font-weight: 700; }
.ss-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 4px; }
.ss-main {
  height: 64px; border-radius: 20px; background: var(--accent-dark); color: #fff;
  font-size: 1.15rem; font-weight: 800; letter-spacing: -0.02em; box-shadow: 0 12px 30px rgba(var(--accent-rgb), 0.28);
  transition: transform 0.18s var(--ease);
}
.ss-main:hover { transform: translateY(-2px); }
.ss-main.ss-main-mia { background: var(--navy); box-shadow: none; }
.ss-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.ss-row button {
  display: flex; align-items: center; justify-content: center; gap: 8px; height: 50px; border-radius: 16px;
  background: var(--card); border: 1.5px solid rgba(var(--navy-rgb), 0.12); color: var(--text); font-size: 0.9rem; font-weight: 700;
}
.ss-row button svg { width: 18px; height: 18px; }
/* En pantalla ancha, una tarjeta abajo a la derecha del mapa, sin tapar la lista */
@media (min-width: 861px) { .spot-sheet { left: auto; right: 16px; bottom: 16px; width: 380px; } }


/* ══ MODO NOCTURNO (2026-09-11, docs/diseno/portada/Noche.dc.html) ═══════════
   Un segundo juego de tokens bajo `:root[data-theme="dark"]`. El atributo lo
   pone un script temprano en index.html (antes de pintar, sin parpadeo) a partir
   de `pb_tema` en localStorage: «claro», «oscuro» o «sistema» (por omisión).
   La idea de la paleta: el azul marino de la marca deja de ser tinta y pasa a
   ser el FONDO; las tarjetas, un tono más claras y con borde; la tinta, blanco
   hueso. El azul y el verde suben medio tono cuando son TINTA (--blue-ink,
   --green-ink) y se quedan como están cuando son FONDO de botón, que ya eran
   colores de noche. Sin sombras: de noche mandan los bordes.               */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0B1730;
  --bg-grad-1: #10244A;
  --bg-grad-2: #0B1730;
  --surface: rgba(17, 35, 72, 0.84);
  --surface-solid: #142A4F;
  --card: #142A4F;
  --text: #EEF3FA;
  --text-2: #A9B8CF;
  --text-3: #6F809B;
  --border: rgba(255, 255, 255, 0.10);
  /* El «marino» como color sólido (cuadro de la hora, botones encendidos) pasa a
     azul vivo: marino sobre marino desaparecería. Como TINTE (rgba con
     --navy-rgb) pasa a blanco: los tintes son «un poco más claro que el fondo». */
  --navy: #066CEC;
  --navy-rgb: 238, 243, 250;
  --blue-ink: #5EA4FF;
  --green-ink: #7EE072;
  --accent-ink: #7EE072;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.35);
  --shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.5);
}
/* Logotipo: dos versiones en el HTML, se enseña la que toca. */
:root:not([data-theme="dark"]) .solo-oscuro { display: none !important; }
:root[data-theme="dark"] .solo-claro { display: none !important; }

[data-theme="dark"] .view-portada, [data-theme="dark"] .portada-map { background: #0B1730; }
[data-theme="dark"] .portada-now { border: 1px solid var(--border); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35); }
[data-theme="dark"] .portada-sheet { background: #112348; border-top: 1px solid var(--border); box-shadow: 0 -18px 50px rgba(0, 0, 0, 0.45); }
[data-theme="dark"] .portada-h1 { color: var(--blue-ink); }
[data-theme="dark"] .portada-h1 i { color: #5FD653; }
[data-theme="dark"] .portada-map .leaflet-control-attribution { background: rgba(11, 23, 48, 0.72); color: var(--text-2); }
/* El mapa se oscurece sin cambiar de proveedor: las teselas de OSM invertidas y
   desaturadas dan un plano azul noche que casa con la paleta. Los pines van en
   otra capa y no se tocan. */
[data-theme="dark"] .leaflet-tile-pane { filter: invert(1) hue-rotate(195deg) brightness(0.72) contrast(1.05) saturate(0.5); }
[data-theme="dark"] .leaflet-control-attribution { background: rgba(11, 23, 48, 0.72) !important; color: var(--text-2) !important; }
[data-theme="dark"] .leaflet-control-attribution a { color: var(--blue-ink) !important; }
[data-theme="dark"] .leaflet-popup-content-wrapper, [data-theme="dark"] .leaflet-popup-tip { background: var(--card); color: var(--text); }
[data-theme="dark"] .leaflet-bar a { background: var(--card); color: var(--text); border-color: var(--border); }
[data-theme="dark"] #splash { background: var(--bg); }
[data-theme="dark"] .verify-banner { background: rgba(255, 159, 10, 0.14); border-color: rgba(255, 159, 10, 0.3); color: #FFC96B; }
[data-theme="dark"] .bio-bar { background: var(--card); border: 1px solid var(--border); box-shadow: 0 12px 30px rgba(0, 0, 0, 0.4); }
[data-theme="dark"] .spot-sheet { border: 1px solid var(--border); box-shadow: 0 18px 50px rgba(0, 0, 0, 0.5); }
[data-theme="dark"] .ss-main { box-shadow: none; }
[data-theme="dark"] .ss-prio.theirs { background: rgba(255, 255, 255, 0.08); }
[data-theme="dark"] #offline-bar { background: var(--card); border: 1px solid var(--border); box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5); }
/* La matrícula de noche: la placa sigue blanca (es una matrícula), pero la tinta
   heredaba el blanco hueso del tema y el texto desaparecía sobre la placa (Luiz,
   2026-09-12: «no es tan visible en el modo noche»). Tinta marino fija y borde
   claro para que la placa se recorte del fondo oscuro. */
[data-theme="dark"] .rv-plate { background: #FFFFFF; border-color: #DDE3EE; }
[data-theme="dark"] .rv-plate b { color: #0B1730; }
[data-theme="dark"] .toast { background: rgba(20, 42, 79, 0.96); border: 1px solid var(--border); }

/* El ajuste, en Perfil (Aspecto.dc.html): tres opciones en fila. */
.aspecto { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.aspecto-opt {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; height: 82px;
  border-radius: 16px; background: var(--bg); border: 1.5px solid var(--border); color: var(--text);
  font-size: 0.84rem; font-weight: 700; transition: transform 0.18s var(--ease), background 0.18s, border-color 0.18s;
}
.aspecto-opt svg { width: 22px; height: 22px; }
.aspecto-opt:hover { transform: translateY(-1px); }
.aspecto-opt.on { background: var(--navy); border-color: var(--navy); color: #fff; }
/* El interruptor de la barra: en móvil, junto a la campana. */
.tema-btn svg { display: block; }
[data-theme="dark"] .tema-btn { color: #FFD166; }


/* ══ GRUPOS (2026-09-11, docs/diseno/portada/Grupos.dc.html) ══════════════════
   Reutiliza las barras de la portada (.portada-cta) y las filas de Actividad
   (.act-row); aquí sólo lo propio. */
.grp-ctas { display: flex; flex-direction: column; gap: 10px; margin-bottom: 22px; }
.grp-row { align-items: flex-start; }
.grp-row .act-hora { cursor: pointer; }
.grp-row .act-hora:hover { transform: translateY(-1px); }
.grp-name {
  display: flex; align-items: center; gap: 6px; padding: 0; text-align: left; color: inherit; font: inherit; min-height: 0;
}
.grp-name b { font-size: 0.97rem; font-weight: 700; letter-spacing: -0.01em; }
.grp-name svg { width: 16px; height: 16px; opacity: 0.45; flex: none; }
.grp-name:hover svg { opacity: 0.9; }
.grp-vacio .act-ico { color: var(--text-3); }
.grp-vacio .act-txt span { line-height: 1.4; }
.grp-nota { margin: 12px 4px 0; font-size: 0.8rem; line-height: 1.45; color: var(--text-2); }
@media (min-width: 861px) { .grp-ctas { flex-direction: row; } .grp-ctas .portada-cta { flex: 1; } }
