/* =============================================================================
   MISSIONS · catalog page styles
   ----------------------------------------------------------------------------
   Estructura: hero · priority · filter-bar · catalog (grid/map) · testimonials
   · final-cta. Tokens y componentes del DS (common.css). Sólo lo específico de
   esta página vive aquí.
   ============================================================================= */


/* =============================================================================
   1 · HERO · foto cinematográfica de fondo + scrim. Padding Statement (lg)
   del DS — banda con más peso visual que un editorial normal.
   ========================================================================== */
.mis-hero {
  background: var(--gradient-strong);   /* fallback bajo la foto */
  padding: var(--section-pad-y-lg) var(--gutter);
}
.mis-hero__inner {
  max-width: var(--max-wide);
  margin: 0 auto;
}
.mis-hero__title {
  font-family: var(--font-sans);
  /* Token compartido de hero (mismo que Premium/App) · en móvil baja a
     --text-hero-title-sm para no quedar más grande que el resto de heroes. */
  font-size: var(--text-hero-title);
  font-weight: 600;
  line-height: var(--lh-display, 1.08);
  letter-spacing: -0.01em;
  color: var(--content-text-default);
  margin: 0 0 clamp(20px, 2.4vw, 32px);
}


/* =============================================================================
   2 · FORM · inputs + form layout · reutilizado en las cards de priority list
   (heros D/E) y en el final-cta.
   ========================================================================== */
.mis-form {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}
@media (min-width: 720px) {
  /* Name | Email en una fila (cada uno media card → email cómodo para correos
     largos); el botón baja a su PROPIA fila full-width. Antes iban los tres en
     una fila (`1fr 1fr auto`) y el email quedaba estrecho. */
  .mis-form { grid-template-columns: 1fr 1fr; align-items: stretch; }
  /* El botón ocupa su propia fila, CENTRADO en la card, con ancho fijo de 310px. */
  .mis-form button[type="submit"] { grid-column: 1 / -1; justify-self: center; width: 310px; max-width: 100%; }
  .mis-form .input { min-height: 56px; }
  .mis-form .btn { white-space: nowrap; }
  .mis-form__rating { grid-column: 1 / -1; }
}
.mis-form--stacked,
.mis-form--stacked.mis-form {
  grid-template-columns: 1fr;
  gap: 12px;
}

/* Los inputs del formulario son el `.input` del DS (cuadrado · radius-s). El
   min-height de desktop (56) se mantiene arriba en `.mis-form .input`. */

.mis-form__rating { margin-top: 0.25rem; }


/* =============================================================================
   4 · FILTER BAR · sticky al top dentro de la banda Catalog. Bg TRANSPARENTE
   en estado inicial (se ve el gradient-strong continuo de la sección). Cuando
   el bar queda pegado al top y empieza a montarse sobre las cards, JS añade
   la clase `.is-stuck` (vía IntersectionObserver sobre `.mis-filter-bar__sentinel`)
   → activa el bg glass (negro 72% + backdrop blur) y la sombra inferior sutil.
   Mismo lenguaje que los `.mis-badge--pastel`. Transición con `--dur-instant`.
   ========================================================================== */
.mis-filter-bar__sentinel {
  height: 1px;
  width: 100%;
  pointer-events: none;
  /* `scroll-margin-top` · al hacer `scrollIntoView` sobre el sentinel
     (e.g. al cambiar entre Grid y Map view), descontar la altura de
     la nav fija para que el filter bar aparezca JUSTO debajo de la
     nav, no escondido detrás. El sentinel está antes del filter bar
     en el flujo natural (no sticky), por eso es el target correcto:
     hacer scrollIntoView sobre el filter bar directamente FALLA
     cuando éste ya está en estado sticky pegado al top. */
  scroll-margin-top: calc(var(--nav-height) + env(safe-area-inset-top, 0px) + 8px);
}

/* Modo "cambio de vista" · activo solo durante la animación de scroll
   programático al pulsar los tabs Grid/Map. Deshabilita TODAS las
   transiciones de la nav y el filter bar para que ninguna animación
   secundaria (translateY, opacity, bg) compita con el scroll. El JS
   añade `.is-switching-view` al `<body>` antes de la animación y la
   retira tras el `performViewChange`. `overflow-anchor: none` impide
   que el browser haga auto-ajustes de scroll cuando el grid se oculta
   y el layout colapsa (scroll anchoring CSS spec). */
body.is-switching-view {
  overflow-anchor: none;
}
body.is-switching-view .nav,
body.is-switching-view .mis-filter-bar {
  transition: none !important;
}
.mis-filter-bar {
  position: sticky;
  /* `top` fijo: el bar se pega JUSTO debajo de la nav fija. Cuando la
     nav se oculta al scroll, NO cambiamos `top` (eso animaba layout y
     se desfasaba con el `transform` de la nav, dejando un hueco visible
     durante el scroll-up). En su lugar movemos el bar con `transform:
     translateY(...)` — misma propiedad, misma curva y misma duración
     que la nav (`--dur-soft`/`--ease-out`) → sincronización pixel-perfect,
     sin separación entre nav y bar durante la transición. */
  top: calc(var(--nav-height) + env(safe-area-inset-top, 0px));
  z-index: 50;
  background: transparent;
  /* Full viewport width: el bar escapa del padding lateral 24px del
     `.mis-catalog` con margin negativo. El `.mis-filter-bar__inner`
     mantiene `max-width: var(--max-wide)` para que el contenido
     siga centrado y alineado con el resto de la sección.
     `margin-bottom` reducido (antes 28-48px) para ganar espacio
     vertical para el siguiente bloque (grid o mapa) y poder dejar
     más respiración debajo. */
  margin: 0 calc(-1 * var(--gutter)) clamp(14px, 1.8vw, 24px);
  padding: clamp(12px, 1.4vw, 18px) clamp(16px, 2vw, 24px);
  transform: translateY(0);
  transition: transform var(--dur-soft) var(--ease-out),
              background-color var(--dur-instant) var(--ease-out),
              backdrop-filter var(--dur-instant) var(--ease-out),
              box-shadow var(--dur-instant) var(--ease-out);
}
/* Cuando la nav se oculta (clase `.hidden` por mockup/script.js),
   subimos el bar la altura del nav para que ocupe ese hueco. Vuelve a
   translateY(0) en cuanto la nav reaparece — misma animación que la nav. */
body:has(.nav.hidden) .mis-filter-bar {
  transform: translateY(calc(-1 * (var(--nav-height) + env(safe-area-inset-top, 0px))));
}
.mis-filter-bar.is-stuck {
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: var(--glass-filter-strong);
  -webkit-backdrop-filter: var(--glass-filter-strong);
  box-shadow: 0 1px 0 var(--border-neutral-soft);
  /* En estado stuck reducimos el padding vertical y colapsamos el
     `Filter by` — la fila de triggers + chips + counter se queda como
     info esencial mientras la usuaria scrollea. */
  padding-top: clamp(8px, 1vw, 12px);
  padding-bottom: clamp(8px, 1vw, 12px);
}
/* Title `Filter by` colapsable cuando el bar está stuck — transición
   suave con max-height + opacity + margins a 0. El counter `N missions
   available` se mantiene visible siempre (info útil bajo los chips). */
.mis-filter-bar__title {
  overflow: hidden;
  max-height: 60px;
  transition: max-height var(--dur-instant) var(--ease-out),
              margin var(--dur-instant) var(--ease-out),
              opacity var(--dur-instant) var(--ease-out);
}
.mis-filter-bar.is-stuck .mis-filter-bar__title {
  max-height: 0;
  margin-top: 0;
  margin-bottom: 0;
  opacity: 0;
  pointer-events: none;
}
.mis-filter-bar__inner {
  max-width: var(--max-wide);
  margin: 0 auto;
  position: relative;
}
/* Field title encima de la fila de controles. Mono uppercase weak, mismo
   tono que un label de form. */
.mis-filter-bar__title {
  margin: 0 0 clamp(10px, 1.2vw, 14px);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--content-text-default-weak);
}
/* Fila única: triggers a la izquierda con gap pequeño entre ellos,
   tablist (Grid/Map) al borde derecho con margin-left: auto. */
.mis-filter-bar__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(12px, 1.5vw, 20px);
}
.mis-filter-bar__row .mis-view-toggle {
  margin-left: auto;
}
.mis-filter-bar__triggers {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
/* Filter triggers · usan `.btn .btn-outline .btn-s` del DS. Aquí sólo lo
   específico: caret + estados aria-expanded/has-active. */
.mis-filter-trigger[aria-expanded="true"],
.mis-filter-trigger.has-active {
  box-shadow: inset 0 0 0 1.5px var(--border-secondary-accent);
}
.mis-filter-trigger__caret {
  width: 10px;
  height: 10px;
  flex-shrink: 0;
  color: currentColor;
  transition: transform var(--dur-instant) var(--ease-out);
}
.mis-filter-trigger[aria-expanded="true"] .mis-filter-trigger__caret { transform: rotate(180deg); }
.mis-filter-count-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--radius-full);
  background: var(--yellow-5);
  color: var(--gray-9);
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  font-weight: 600;
}

/* Botón de ajustes (móvil) · colapsa/expande la fila de filtros. Oculto en
   desktop; se activa en el bloque responsive de abajo. Usa `.icon-btn` del
   DS (glass). El badge amarillo (arriba-derecha) muestra el total activo. */
.mis-filter-toggle {
  display: none;
  position: relative;
  flex-shrink: 0;
}
.mis-filter-bar.is-filters-open .mis-filter-toggle {
  box-shadow: inset 0 0 0 1.5px var(--border-secondary-accent);
}
.mis-filter-toggle__badge {
  display: none;
  position: absolute;
  top: -5px;
  right: -5px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-full);
  background: var(--yellow-5);
  color: var(--gray-9);
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  font-weight: 600;
  border: 2px solid var(--bg-bold);   /* separa el badge del icono */
}
.mis-filter-toggle__badge.is-visible { display: inline-flex; }

.mis-filter-clear {
  background: transparent;
  border: 0;
  padding: 8px 12px;
  color: var(--content-text-default-weak);
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.mis-filter-clear:hover { color: var(--content-text-default); }

/* Fila de acciones · en desktop es transparente al layout (`display:contents`)
   → Clear all sigue inline entre los triggers, Done no existe. En móvil (abajo)
   se convierte en la barra inferior del panel de filtros. */
.mis-filter-actions { display: contents; }
.mis-filter-done { display: none; }

/* Chips de filtros activos · sin margin propio, el wrapper `__results`
   se encarga del espaciado vertical y horizontal con el counter. */
.mis-filter-bar__selected {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
  min-height: 0;
}
.mis-filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px 6px 12px;
  border-radius: var(--radius-full);
  background: rgba(255, 255, 255, 0.08);
  color: var(--content-text-default);
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 400;
}
.mis-filter-chip button {
  width: 22px;
  height: 22px;
  border-radius: var(--radius-circle);
  background: transparent;
  border: 0;
  color: var(--content-text-default-weak);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.mis-filter-chip button:hover { color: var(--content-text-default); background: rgba(255, 255, 255, 0.08); }

/* Counter · sin margin propio, controlado por el wrapper `__results`. */
.mis-filter-bar__count {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  color: var(--content-text-default-weak);
  white-space: nowrap;
}
/* Wrapper de resultados · counter + chips en una sola línea (flex con
   gap 14px entre ellos y flex-wrap para mobile). Vive debajo de la fila
   de filtros. Visible por defecto. En estado stuck SIN chips se colapsa
   por completo (counter no aporta). Si hay al menos una chip activa
   (detección con `:has()`), reaparece — entonces el conteo es info
   crítica para saber cuántos resultados quedan tras filtrar. */
.mis-filter-bar__results {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin-top: clamp(14px, 1.6vw, 20px);
  overflow: hidden;
  max-height: 60px;
  opacity: 1;
  transition: max-height var(--dur-instant) var(--ease-out),
              margin var(--dur-instant) var(--ease-out),
              opacity var(--dur-instant) var(--ease-out);
}
.mis-filter-bar.is-stuck .mis-filter-bar__results {
  max-height: 0;
  margin-top: 0;
  opacity: 0;
  pointer-events: none;
}
.mis-filter-bar.is-stuck:has(.mis-filter-chip) .mis-filter-bar__results {
  max-height: 60px;
  margin-top: clamp(14px, 1.6vw, 20px);
  opacity: 1;
  pointer-events: auto;
}
.mis-filter-bar__count-n {
  color: var(--content-text-default);
  font-weight: 600;
}
/* View toggle Grid/Map · usa el `.tablist` canónico del DS (ver common.css).
   Aquí solo añadimos el gap del icono con el label en cada item. */
.mis-view-toggle .tablist__item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* Wrapper del trigger + popover · contexto de posicionamiento para que el
   popover se ancle SOLO a su botón (no al filter bar completo). */
.mis-filter-field {
  position: relative;
  display: inline-block;
}

/* Popovers de filtros · tratados como cards del DS (gradient-subtle +
   shadow-soft + filete canónico). Anclados al trigger, NO full-width:
   `width: max-content` para que se ajusten al contenido, con un cap. */
.mis-popover {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 8px;
  padding: clamp(14px, 1.6vw, 20px);
  border-radius: var(--radius-l);
  background: var(--gradient-subtle);
  border: 1px solid var(--border-neutral-soft);
  box-shadow: var(--shadow-soft);
  width: max-content;
  max-width: min(520px, calc(100vw - 48px));
  z-index: 60;
}
/* Popover del último trigger (Month) · alineado a la derecha del wrapper
   para evitar overflow en viewports estrechos. */
.mis-popover[data-popover="month"] {
  left: auto;
  right: 0;
}

/* Grid de opciones · 1 col móvil · 2 col desktop. El popover crece a
   `max-content`, así que los items con label corto (Format: 2 items)
   quedan en 1 columna estrecha; los largos (Moment/Destination/Month:
   12-14 items) ocupan 2 columnas. */
.mis-popover__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px;
  min-width: 200px;
}
@media (min-width: 720px) {
  .mis-popover[data-popover="moment"] .mis-popover__grid,
  .mis-popover[data-popover="destination"] .mis-popover__grid,
  .mis-popover[data-popover="month"] .mis-popover__grid {
    grid-template-columns: repeat(2, minmax(140px, 1fr));
  }
}

/* Cada opción es una fila sutil; sólo el hover/active la destaca. */
.mis-popover-option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border-radius: var(--radius-m);
  border: 0;
  background: transparent;
  color: var(--content-text-default);
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 400;
  text-align: left;
  cursor: pointer;
  transition:
    background var(--dur-instant) var(--ease-out),
    color var(--dur-instant) var(--ease-out);
}
.mis-popover-option:hover { background: rgba(255, 255, 255, 0.04); }
.mis-popover-option.is-selected { color: var(--content-text-highlight); }

/* Checkbox · cuadrado claramente visible (no se confunde con radiobutton).
   Borde más fuerte que el filete soft estándar para asegurar que se lee
   como una casilla; al marcar se rellena de amarillo y muestra el tick. */
.mis-popover-check {
  width: 18px;
  height: 18px;
  border-radius: 4px;
  border: 1.5px solid rgba(255, 255, 255, 0.42);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--gray-9);
  background: transparent;
  transition:
    background var(--dur-instant) var(--ease-out),
    border-color var(--dur-instant) var(--ease-out);
}
.mis-popover-check svg { opacity: 0; transition: opacity var(--dur-instant) var(--ease-out); }
.mis-popover-option.is-selected .mis-popover-check {
  background: var(--yellow-5);
  border-color: var(--yellow-5);
}
.mis-popover-option.is-selected .mis-popover-check svg { opacity: 1; }


/* =============================================================================
   5 · CATALOG · header + filter bar + grid en una sola banda gradient-strong
   sin divisores. Padding editorial md arriba/abajo del DS.
   ========================================================================== */
.mis-catalog {
  background: var(--gradient-strong);
  padding: var(--section-pad-y-md) var(--gutter);
}
.mis-catalog__header {
  margin-bottom: clamp(20px, 2.4vw, 36px);
}
/* Título de sección un punto menor que el `.section-title` canónico
   (clamp heading-lg → display-lg). Aquí cap heading-md → heading-xl
   (32 → 56px) para que no compita con el H1 del hero. */
.mis-catalog__header .section-title {
  font-size: clamp(var(--text-heading-md), 4.5vw, var(--text-heading-xl));
}
.mis-catalog__inner {
  max-width: var(--max-wide);
  margin: 0 auto;
}
.mis-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  /* Filtrado fluido (Irene, ago 2026) · crossfade: el JS añade
     `.is-swapping` (opacidad 0), intercambia el contenido invisible y la
     quita → la parrilla se funde en vez de pestañear. */
  transition: opacity var(--dur-instant) var(--ease-out);
}
.mis-grid.is-swapping {
  opacity: 0;
}
@media (prefers-reduced-motion: reduce) {
  .mis-grid { transition: none; }
}
@media (min-width: 720px) { .mis-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .mis-grid { grid-template-columns: repeat(3, 1fr); } }


/* =============================================================================
   6 · CARD · mission card · media + body (header + facts + footer).
   ========================================================================== */
.mis-card {
  display: flex;
  flex-direction: column;
  background: var(--gradient-soft);
  border: 1px solid var(--border-neutral-soft);
  border-radius: var(--radius-l);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition:
    transform var(--dur-soft) var(--ease-out),
    border-color var(--dur-soft) var(--ease-out),
    box-shadow var(--dur-soft) var(--ease-out);
}
.mis-card:hover {
  transform: translateY(-2px);
  border-color: rgba(255, 255, 255, 0.18);
  box-shadow: var(--shadow-soft);
}
.mis-card__media {
  position: relative;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: var(--gradient-subtle);
}
.mis-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--dur-glide) var(--ease-soft);
}
.mis-card:hover .mis-card__media img { transform: scale(1.04); }

/* Badges anclados a la esquina superior derecha del media (canonical). */
.mis-card__badges {
  position: absolute;
  top: 12px;
  right: 12px;
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
/* Status badge (`.mis-badge` + `--pastel-*` + `__dot`) PROMOVIDO al DS
   compartido → vive en `common.css` (2026-07). Se añadió allí la variante
   neutra `--pastel-available` (bg-bold 82% + punto blanco) para el CTA de
   plazas de Expeditions. Aquí solo quedan los tratamientos específicos de
   card (wrapper `.mis-card__badges` y la "memoria editorial" sold-out). */

/* ─────────────────────────────────────────────────────────────────────
   Tratamiento SOLD-OUT · "memoria editorial" sin cambiar el bg de la card
   - Textos del body (title, num, dt, dd) bajan a `--content-text-default-weak`
     → jerarquía tipográfica apagada, la card se lee como "ya pasada"
     sin tocar el bg ni romper la coherencia del grid.
   - Overlay `--gradient-soft` sobre la foto (`::after` z-index 1, debajo
     del badge z-index 2) → tinte cinematográfico que refuerza el "ya no".
   - `[Sold out]` inline en el num (clase .mis-card__num-status) en
     `--red-5` (paso ★ canónico del rol alert) → etiqueta de estado
     embebida en el eyebrow técnico.
   - CTAs del footer mantienen su color (primary yellow, ghost gray) →
     la acción sigue siendo accesible. La card sold-out NO se desactiva,
     solo se "apaga" visualmente; el usuario puede entrar al detalle y
     pedir lista de espera.
   ───────────────────────────────────────────────────────────────────── */
.mis-card__media:has(.mis-badge--pastel-soldout)::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--gradient-soft);
  opacity: 0.45;
  pointer-events: none;
  z-index: 1;
}
.mis-card__badges {
  z-index: 2;
}
.mis-card:has(.mis-badge--pastel-soldout) .mis-card__title,
.mis-card:has(.mis-badge--pastel-soldout) .mis-card__num,
.mis-card:has(.mis-badge--pastel-soldout) .mis-card__facts dt,
.mis-card:has(.mis-badge--pastel-soldout) .mis-card__facts dd {
  color: var(--content-text-default-weak);
}
.mis-card__num-status {
  color: var(--red-5);
}

.mis-card__body {
  display: flex;
  flex-direction: column;
  gap: clamp(14px, 1.5vw, 18px);
  padding: clamp(20px, 2vw, 28px);
}
.mis-card__header {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.mis-card__loc {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--content-text-highlight);
}
.mis-card__title {
  font-family: var(--font-sans);
  font-size: var(--text-heading-sm);
  font-weight: 600;
  line-height: 1.2;
  color: var(--content-text-default);
  margin: 0;
}
/* Mission nº · ocupa el slot del eyebrow (encima del título). Mono uppercase
   gris débil. Ver render del card en script.js: va primero en el header. */
.mis-card__num {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--content-text-default-weak);
}

.mis-card__facts {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: clamp(14px, 1.6vw, 20px);
  row-gap: 6px;
  margin: 0;
}
.mis-card__facts dt {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);     /* mono-sm 12px · legible */
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--content-text-default-weak);
  align-self: center;
}
.mis-card__facts dd {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 400;
  color: var(--content-text-default);
}

/* Footer · sin línea divisora interna; el gap natural del body separa
   las facts del footer sin necesidad de border.
   Modelo 50/50 fill: los dos slots (`.mis-card__avail` o `.btn-ghost.btn-s`
   a la izquierda · `.btn-primary.btn-s` a la derecha) ocupan la mitad
   del ancho disponible cada uno, con gap fijo de 12px entre ellos.
   `align-items: center` centra verticalmente el avail text respecto a
   la altura natural del btn — NO usar flex en el `.mis-card__avail`
   porque colapsa el espacio entre `<strong>` y el text node siguiente. */
.mis-card__foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}
.mis-card__foot > * {
  flex: 1 1 0;
  min-width: 0;
}
.mis-card__avail {
  font-family: var(--font-sans);
  font-size: var(--text-body-xs);     /* body-xs 14px · más sutil delante del CTA */
  color: var(--content-text-default-weak);
}
.mis-card__avail strong { color: var(--content-text-default); font-weight: 600; }
/* CTA del card · primary siempre `.btn .btn-primary .btn-s` (View Mission).
   Secundario (estados coming-soon / sold-out) → `.btn .btn-ghost .btn-s`.
   Los `.btn` heredan el `flex: 1 1 0` y se estiran al 50% — su texto
   se mantiene centrado dentro del pill estirado. */


/* =============================================================================
   7 · MAP · view alternativa (Leaflet). Tema oscuro.
   ========================================================================== */
.mis-map {
  /* Altura calculada para que tras el scroll de "click Map", filter bar
     + mapa quepan COMPLETOS en un solo viewport sin recortar el mapa
     por abajo. Descuento conservador de ~260px:
       · nav fija         48
       · filter bar      ~110 (clamp 76-120 según breakpoint)
       · gap superior    ~48
       · padding/legend  ~50
     Total: 256 → round up a 260 para garantizar margen.
     - Floor 400px · pantallas cortas (laptops 13" con docks) siguen
       viendo un mapa usable, scroll natural si no cabe.
     - Cap 680px · evita que el mapa parezca desmesurado en pantallas
       grandes — la atribución y los zoom controls quedan a distancia
       cómoda del eje vertical. */
  height: clamp(360px, calc(100svh - 300px), 600px);
  width: 100%;
  background: var(--gradient-subtle);
}
/* Tuning editorial de los tiles satélite (Esri WorldImagery) · saturación
   reducida + brillo bajado + contraste +5% para que la imagen se sienta
   cinematográfica/PhotoPills, no Google Maps colorido. Patrón validado
   en productos premium como Strava Heatmap, Komoot, Apple Maps Dark. */
.mis-map .leaflet-tile {
  filter: saturate(0.7) brightness(0.85) contrast(1.05);
}

/* Refuerzo CSS · cuando el tab `Map` está activo, ocultamos cards,
   empty fallback y bridge CTA. El JS también lo hace vía `[hidden]`,
   pero esta capa CSS asegura el comportamiento si la caché del
   navegador no recargara el JS actualizado. Detección con `:has()`
   sobre el botón activo de la tablist. */
.mis-catalog:has(.mis-view-btn[data-view="map"].is-active) .mis-grid[data-view="grid"],
.mis-catalog:has(.mis-view-btn[data-view="map"].is-active) .mis-empty,
.mis-catalog:has(.mis-view-btn[data-view="map"].is-active) .mis-bridge {
  display: none !important;
}
/* Atribución de Leaflet · franja full-width sin bg, mono uppercase weak
   con text-shadow para legibilidad sobre cualquier zona del satélite.
   Cumple TOS Esri sin distraer del mapa. */
.mis-map .leaflet-bottom.leaflet-right {
  left: 0;
  right: 0;
}
.mis-map .leaflet-control-attribution {
  width: 100%;
  background: transparent;
  color: rgba(255, 255, 255, 0.7);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.04em;
  padding: 6px 16px;
  border-radius: 0;
  margin: 0;
  text-align: right;
}
.mis-map .leaflet-control-attribution a {
  color: rgba(255, 255, 255, 0.9);
  text-decoration: none;
}
.mis-map .leaflet-control-attribution a:hover {
  color: var(--content-text-highlight);
}

/* Controles de zoom (+/−) · viven en `common.css` como patrón compartido
   del DS (tab capsule estilo `.btn-dark`). Misma estética en TODOS los
   mapas de la web — no se redefinen por página. */
/* MAP DETAIL · floating card en la esquina superior derecha del mapa
   (sobre el mapa, no parte el viewport en dos columnas). Aloja la
   `.mis-card` canónica. El mapa sigue completamente interactivo debajo.
   Patrón validado en Apple Maps app cuando se selecciona un POI. */
.mis-map-wrap {
  /* `position: relative` + `z-index: 0` crea un stacking context propio
     para todo el mapa de Leaflet (sus panes internos tienen z-index
     200, 400, 700 — sin este wrapper aislado escapaban y se montaban
     sobre el filter bar sticky y la nav fija al hacer scroll). */
  position: relative;
  z-index: 0;
  isolation: isolate;
  margin: 0;
  border-radius: var(--radius-l);
  overflow: hidden;
  border: 1px solid var(--border-neutral-soft);
}
.mis-map-detail {
  position: absolute;
  top: clamp(16px, 2vw, 24px);
  right: clamp(16px, 2vw, 24px);
  bottom: clamp(16px, 2vw, 24px);
  width: clamp(320px, 26vw, 400px);
  z-index: 1000;  /* sobre los panes de Leaflet (z-index < 700) */
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-strong);
  overflow: hidden;  /* el scroll vive dentro del card body si hace falta */
  animation: misMapDetailIn var(--dur-soft) var(--ease-out);
}
@keyframes misMapDetailIn {
  from { transform: scale(0.96) translateY(8px); opacity: 0; }
  to   { transform: scale(1) translateY(0); opacity: 1; }
}
/* Close button · esquina top-right del card, sobre la foto. */
.mis-map-detail__close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-circle);
  border: 0;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: var(--glass-filter-strong);
  -webkit-backdrop-filter: var(--glass-filter-strong);
  color: var(--gray-white);
  cursor: pointer;
  z-index: 3;
  transition: background var(--dur-instant) var(--ease-out);
}
.mis-map-detail__close:hover {
  background: rgba(0, 0, 0, 0.8);
}
/* La card dentro del floating panel ocupa el alto completo · estructura
   flex column: media arriba (proporción fija), body flex-grow con la
   descripción incluida, footer al fondo. El body es scrollable si el
   contenido excede el alto disponible. */
.mis-map-detail__body {
  height: 100%;
}
.mis-map-detail__body .mis-card {
  height: 100%;
  display: flex;
  flex-direction: column;
  pointer-events: auto;
}
.mis-map-detail__body .mis-card:hover {
  transform: none;
}
.mis-map-detail__body .mis-card__media {
  flex-shrink: 0;
}
.mis-map-detail__body .mis-card__body {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
}
/* Description y footer · description se estira (flex: 1) para empujar el
   footer al fondo de la card. Si el texto es corto, queda arriba con
   espacio en blanco entre el final del texto y el footer · si el texto
   es largo, ocupa hasta donde puede. */
.mis-map-detail__body .mis-card__description {
  flex: 1;
}
/* Badge top-LEFT solo cuando la card vive en el floating panel del mapa.
   En el grid normal el badge sigue top-right (convención local). Aquí
   movemos para no chocar con el botón close (×) que UX universal vive
   siempre en top-right. */
.mis-map-detail__body .mis-card__badges {
  left: 12px;
  right: auto;
}
/* Párrafo descriptivo · entre las facts y el footer. Solo aparece cuando
   `cardHTML(m, { withDescription: true })` se invoca (floating panel del
   mapa). Body-sm peso 300 con line-height generoso para 2-3 líneas. */
.mis-card__description {
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 300;
  line-height: 1.45;
  color: var(--content-text-default-weak);
  margin: 0;
}
/* Mobile: floating card pasa a bottom sheet (más cómodo en mobile). */
@media (max-width: 720px) {
  .mis-map-detail {
    top: auto;
    left: clamp(12px, 3vw, 20px);
    right: clamp(12px, 3vw, 20px);
    bottom: clamp(12px, 3vw, 20px);
    width: auto;
    max-height: 70%;
    animation: misMapDetailInMobile var(--dur-soft) var(--ease-out);
  }
  @keyframes misMapDetailInMobile {
    from { transform: translateY(20px); opacity: 0; }
    to   { transform: translateY(0); opacity: 1; }
  }
}

/* Markers (divIcon). */
.mis-marker {
  display: block;
  width: 14px;
  height: 14px;
  border-radius: var(--radius-circle);
  background: var(--yellow-5);
  border: 2px solid var(--gray-9);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--yellow-5) 32%, transparent);
  transition: transform var(--dur-instant) var(--ease-out),
              box-shadow var(--dur-instant) var(--ease-out);
}
.mis-marker--sold {
  background: color-mix(in srgb, var(--red-5) 92%, transparent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--red-5) 25%, transparent);
}
/* Marker seleccionado · escala 1.5x + anillo doble exterior amarillo
   para que se vea claramente cuál es el pin que corresponde a la card
   floating. El `transform: scale` no afecta el anchor del icon (Leaflet
   lo ancla por su iconAnchor), solo visualmente. */
.mis-marker--selected {
  transform: scale(1.5);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--yellow-5) 50%, transparent),
              0 4px 14px rgba(0, 0, 0, 0.55);
  z-index: 1000;
}
.mis-marker--selected.mis-marker--sold {
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--red-5) 50%, transparent),
              0 4px 14px rgba(0, 0, 0, 0.55);
}

/* Mensaje de éxito al enviar el form de priority list. */
.mis-form__success {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-body-md);
  font-weight: 500;
  color: var(--content-text-highlight);
  grid-column: 1 / -1;
}


/* =============================================================================
   8 · EMPTY STATE · cuando ningún filtro coincide.
   ========================================================================== */
.mis-empty {
  padding: clamp(40px, 5vw, 64px) 0;
  text-align: center;
}
.mis-empty__title {
  font-family: var(--font-sans);
  font-size: var(--text-heading-sm);
  font-weight: 500;
  color: var(--content-text-default);
  margin: 0 0 0.5rem;
}
.mis-empty__hint {
  font-family: var(--font-sans);
  font-size: var(--text-body-md);
  font-weight: 300;
  color: var(--content-text-default-weak);
  margin: 0 0 clamp(24px, 3vw, 40px);
}


/* =============================================================================
   9 · BRIDGE CTA · debajo de las cards, hacia Private Missions.
   ========================================================================== */
.mis-bridge {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 1.25rem;
  margin-top: clamp(48px, 6vw, 80px);
  padding: clamp(28px, 3vw, 40px) 24px;
  border-top: 1px solid var(--border-neutral-soft);
}
.mis-bridge__copy {
  max-width: 60ch;
  font-family: var(--font-sans);
  font-size: var(--text-body-md);
  font-weight: 300;
  line-height: 1.4;
  color: var(--content-text-default-weak);
  margin: 0;
}


/* =============================================================================
   10 · TESTIMONIALS · "Field notes" · gradient-soft, quote SVG canónico
   centrado en el track, pager DS abajo.
   ========================================================================== */
.mis-testimonials {
  background: var(--gradient-soft);
  padding: var(--section-pad-y-md) var(--gutter);
}
.mis-testimonials__inner {
  max-width: 880px;
  margin: 0 auto;
  text-align: center;
}
.mis-testimonials__inner .eyebrow-line { margin: 0 auto 2rem; }

/* Quote mark · vive DENTRO de cada testimonio para que se centre
   verticalmente JUNTO con la quote y el meta (el grid del track
   centra cada article como bloque). Hereda tamaño 28×19.4 y color
   yellow-5 del componente canónico en common.css. Solo añadimos
   centrado horizontal y margin-bottom respecto a la quote. */
.mis-testimonial__quote-mark {
  margin: 0 auto clamp(20px, 2.4vw, 32px);
}

/* Track · grid stack (todos los testimonios apilados en la misma celda
   con grid-area 1/1). El track se centra verticalmente: cada quote, sea
   corta o larga, queda centrada en alto. El track crece al contenido de
   la quote más larga, así que la transición entre frases no salta de
   altura — la usuaria solo ve un fade in/out con todo centrado. */
.mis-testimonial-track {
  display: grid;
  min-height: 220px;
  align-items: center;
  justify-items: center;
}
.mis-testimonial {
  grid-area: 1 / 1;
  width: 100%;
  opacity: 0;
  transition: opacity var(--dur-glide) var(--ease-soft);
  pointer-events: none;
}
.mis-testimonial.is-active { opacity: 1; pointer-events: auto; }

.mis-testimonial__quote {
  margin: 0 auto;
  max-width: 36ch;
  font-family: var(--font-sans);
  font-size: clamp(var(--text-lead), 3vw, var(--text-heading-sm));
  font-weight: 300;
  line-height: 1.3;
  font-style: normal;
  color: var(--content-text-default);
}
.mis-testimonial__meta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: clamp(20px, 2.5vw, 28px);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  color: var(--content-text-default-weak);
}
.mis-testimonial__name {
  color: var(--content-text-default);
  font-size: var(--text-mono-md);
}

/* Pager · usa el componente canónico `.pager` del DS (estilos en
   common.css). Aquí solo le damos el margin superior para separarlo
   del track de testimonios. */
.mis-testimonials__pager {
  margin: clamp(24px, 3vw, 36px) auto 0;
}


/* =============================================================================
   11 · FINAL CTA · gradient-strong, 2-col cards.
   ========================================================================== */
.mis-final {
  background: var(--gradient-strong);
  padding: var(--section-pad-y-md) var(--gutter);
}
.mis-final__grid {
  max-width: var(--max-wide);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(24px, 3vw, 40px);
}
@media (min-width: 1024px) {
  .mis-final__grid { grid-template-columns: 1fr 1fr; }
}
.mis-final__card {
  display: flex;
  flex-direction: column;
  padding: clamp(32px, 4vw, 56px);
  border-radius: var(--radius-l);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border-neutral-soft);
}
.mis-final__card--priority { background: rgba(255, 255, 255, 0.06); }
/* Private · el CTA queda pegado al fondo de la card (margin-top: auto)
   y a la izquierda (heredado de `.cta-row--start`). Si la card vecina
   crece por su contenido, esta sigue equilibrada con el CTA anclado. */
.mis-final__card--private .cta-row {
  margin-top: auto;
}
.mis-final__card .section-title {
  font-size: clamp(var(--text-heading-md), 4vw, var(--text-heading-lg));
  font-weight: 600;
  line-height: 1.15;
}
.mis-final__card .pitch-body {
  margin-bottom: 1.5rem;
  font-size: clamp(var(--text-body-md), 1.6vw, var(--text-body-lg));
  line-height: 1.3;
}
.mis-final__card .mis-form { margin-bottom: 1.25rem; }
/* Card priority · espaciado equilibrado entre title → rating → text.
   El title pierde su margin-bottom default — el rating se encarga de
   marcar la distancia (1.5rem) tanto arriba como abajo. */
.mis-final__card--priority .section-title {
  margin-bottom: 0;
}
.mis-final__card--priority .app-rating {
  margin: 1.5rem 0;
}
/* Form anclado al fondo del card priority → el botón submit queda
   alineado horizontalmente con el CTA primary del card private
   (ambos `.btn .btn-primary .btn-l`, mismo alto). Se anula el
   margin-bottom heredado para que el submit toque el padding
   inferior del card. */
.mis-final__card--priority .mis-form {
  margin-top: auto;
  margin-bottom: 0;
}
/* Submit del form en ancho intrínseco (no estirado por el grid)
   y alineado a la izquierda → mismo comportamiento que el CTA de
   "Let's plan your Private Mission" en la card de al lado.
   `margin-top: 12px` suma al gap del grid (12px) → 24px efectivos
   entre el email y el CTA, igual que el espacio entre texto y el
   primer field (margin-bottom: 1.5rem del .pitch-body). */
.mis-final__card--priority .mis-form button[type="submit"] {
  justify-self: start;
  margin-top: 12px;
}


/* =============================================================================
   12 · UTILIDADES locales y responsive
   ========================================================================== */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (max-width: 720px) {
  /* ── Item 1 · hero title · patrón "intermediate hero" del MDS (QA #33)
     No se baja un escalón entero (56→40): clamp fluido entre los dos tokens
     contiguos → ~45px @375, converge a 56px en tablet sin salto. */
  .mis-hero__title { font-size: clamp(var(--text-heading-lg), 12vw, var(--text-heading-xl)); }

  /* ── Botones · un escalón más bajos en móvil · btn-l (62px) → medidas de
     btn-m (52px). Mismo patrón que la home (su style.css hace lo mismo): el
     btn-l a ancho completo pesa demasiado frente a los títulos en el teléfono.
     Solo Missions (este style.css es exclusivo). */
  .btn-l { height: 52px; padding: 14px 22px; }

  /* ── Item 2 · el ticker horizontal animado fuera en móvil ─────────── */
  .mis-hero__ticker { display: none; }

  /* ── "Choose your adventure" ↔ barra de filtros · respiro + sin salto ──
     El `.reveal` del h2 arranca +32px → margen 60px (> ese offset) para que no
     se pisen. */
  .mis-catalog__header { margin-bottom: 60px; }
  /* Al ocultarse la nav en móvil: si la barra AÚN no está pegada arriba, NO se
     mueve (antes el transform la subía hacia el título = "salto"). Pero cuando
     YA está pegada (`.is-stuck`), sí sube la altura de la nav para OCUPAR ese
     hueco y quedarse como topbar sticky (si no, quedaba un vacío feo arriba). */
  body:has(.nav.hidden) .mis-filter-bar { transform: none; }
  body:has(.nav.hidden) .mis-filter-bar.is-stuck {
    transform: translateY(calc(-1 * (var(--nav-height) + env(safe-area-inset-top, 0px))));
  }

  /* ── Item 4 · barra de filtros colapsada tras un icono de ajustes ──
     "Filter by" y las chips desaparecen; la selección vuelve a vivir en
     los desplegables (numerito por filtro). Al tocar el icono se revelan
     los triggers como acordeón vertical a ancho completo. */
  .mis-filter-bar__title { display: none; }
  .mis-filter-bar__selected { display: none; }
  .mis-filter-toggle { display: inline-flex; }

  /* Fila: icono de ajustes (izq) + Grid/Map (der) en una sola línea;
     los triggers ocupan su propia línea completa debajo cuando se abre. */
  .mis-filter-bar__row { align-items: center; }
  .mis-filter-toggle { order: 1; }
  .mis-filter-bar__row .mis-view-toggle {
    order: 2;
    margin-left: auto;
    width: auto;
    align-self: center;
  }
  .mis-view-toggle .tablist__item { flex: 0 0 auto; justify-content: center; }

  .mis-filter-bar__triggers {
    order: 3;
    flex-basis: 100%;
    display: none;               /* oculto hasta abrir */
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    margin-top: 6px;
  }
  .mis-filter-bar.is-filters-open .mis-filter-bar__triggers { display: flex; }

  /* Cada filtro a ancho completo para tap cómodo. El label empuja al badge
     y al caret a la DERECHA (margin-right:auto) → el numerito queda pegado
     al caret, no centrado. */
  .mis-filter-bar__triggers .mis-filter-field { display: block; width: 100%; }
  .mis-filter-bar__triggers .mis-filter-trigger {
    width: 100%;
    justify-content: flex-start;
    gap: 8px;
  }
  .mis-filter-bar__triggers .mis-filter-trigger__label { margin-right: auto; }

  /* Barra inferior del panel · Clear all a la izq · Done (cierra) a la der. */
  .mis-filter-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    margin-top: 6px;
  }
  .mis-filter-done {
    display: inline-flex;
    margin-left: auto;   /* siempre pegado a la derecha, aunque Clear all esté oculto */
  }

  /* Popover en móvil = acordeón EN FLUJO (no flotante): se expande debajo
     de su trigger y empuja al resto, en vez de taparlos. */
  .mis-filter-bar__triggers .mis-popover,
  .mis-filter-bar__triggers .mis-popover[data-popover="month"] {
    position: static;
    left: auto;
    right: auto;
    width: auto;
    max-width: none;
    margin-top: 4px;
    padding: 4px 0 8px 10px;
    background: transparent;
    border: 0;
    box-shadow: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .mis-card,
  .mis-card__media img,
  .mis-testimonial { transition: none; }
  .mis-card:hover .mis-card__media img { transform: none; }
}


/* =============================================================================
   HERO · Ticker live feed + Priority list card
   Banda gradient-strong. El ticker mono vive pegado a la base con loop
   infinito (pausa al hover). Entre el copy y el ticker, una card discreta
   con eyebrow + título + subtítulo + form + rating de Google.
   ============================================================================= */

/* Base del hero con ticker · ticker pegado al borde inferior, sin padding
   abajo. */
/* Hero a UN ÚNICO viewport · min-height 100svh · el inner se centra (H+V) con
   `margin: auto` en el hueco flexible, y el ticker queda EN FLUJO como último
   hijo con `padding-bottom: 0` → siempre a sangre por abajo. Si el contenido
   supera el viewport, el hero crece y el ticker sigue al fondo (sin recorte). */
.mis-hero--ticker-card {
  overflow: hidden;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  padding-top: calc(var(--nav-height) + clamp(20px, 4vh, 48px));
  padding-bottom: 0;
}
/* Móvil · con el ticker oculto (ver bloque responsive), la card quedaba
   pegada al borde inferior del hero (~16px). Devolvemos padding-bottom para
   alargar el fondo (foto + gradient) por debajo de la card y darle aire.
   Va aquí, tras la regla base, para ganar la cascada (misma especificidad). */
@media (max-width: 720px) {
  .mis-hero--ticker-card { padding-bottom: clamp(40px, 7vh, 72px); }
}
.mis-hero--ticker-card .mis-hero__inner { margin: auto; }        /* centra H+V sobre el ticker */
.mis-hero--ticker-card .mis-hero__ticker { margin-top: 0; }      /* pegado al fondo, sin gap extra */
.mis-hero--ticker-card:hover .mis-hero__ticker-track,
.mis-hero--ticker-card:focus-within .mis-hero__ticker-track {
  animation-play-state: paused;
}

/* Inner del copy editorial · cap max-content del DS. */
.mis-hero__inner--narrow {
  max-width: var(--max-content);
  margin: 0 auto;
}
/* Jerarquía de anchos: subtítulo contenido (640) < card destacada (880). */
.mis-hero--ticker-card .section-subtitle {
  max-width: 640px;
  margin-left: auto;
  margin-right: auto;
}
.mis-hero--ticker-card .mis-hero__priority-card { max-width: 880px; }

/* Ticker live feed · loop infinito + máscara en los bordes. Va pegado
   al borde inferior del hero; el aire respecto al copy lo da margin-top. */
.mis-hero__ticker {
  margin-top: clamp(48px, 6vw, 80px);
  padding: clamp(16px, 1.8vw, 20px) 0;
  border-top: 1px solid var(--border-neutral-soft);
  border-bottom: 1px solid var(--border-neutral-soft);
  overflow: hidden;
  position: relative;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 4%, #000 96%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 4%, #000 96%, transparent 100%);
}
.mis-hero__ticker-track {
  display: flex;
  gap: clamp(20px, 2.4vw, 32px);
  white-space: nowrap;
  width: max-content;
  /* Marquee continuo: duración fuera de la rampa --dur-* a propósito (un ticker necesita segundos-escala y easing linear). Excepción documentada. */
  animation: mis-ticker 55s linear infinite;
}
.mis-hero__ticker-item {
  font-family: var(--font-mono);
  font-size: var(--text-mono-md);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--content-text-default-weak);
}
.mis-hero__ticker-sep {
  font-family: var(--font-mono);
  font-size: var(--text-mono-md);
  color: var(--content-text-highlight);
}
@keyframes mis-ticker {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }   /* lista duplicada → 50% = un ciclo */
}

/* Card discreta · fondo gradient-soft + borde sutil. */
.mis-hero__priority-card {
  margin: clamp(32px, 3.6vw, 48px) auto 0;
  max-width: 640px;
  padding: clamp(20px, 2.2vw, 28px);
  border-radius: var(--radius-l);
  border: 1px solid var(--border-neutral-soft);
  background: var(--bg-bold);          /* card oscura · destaca sobre la foto del hero */
  box-shadow: var(--shadow-strong);    /* elevación · la despega de la foto */
}
.mis-hero__priority-card-eyebrow {
  margin: 0 0 clamp(6px, 0.8vw, 10px);
}
.mis-hero__priority-card-title {
  margin: 0 0 clamp(8px, 1vw, 12px);
  font-family: var(--font-sans);
  font-size: clamp(var(--text-heading-sm), 2.4vw, var(--text-heading-md));
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--content-text-default);
}
.mis-hero__priority-card-sub {
  margin: 0 0 clamp(20px, 2.4vw, 28px);
  font-family: var(--font-sans);
  font-size: var(--text-body-md);
  font-weight: 300;
  line-height: 1.4;
  color: var(--content-text-default-weak);
}
.mis-hero__priority-card .mis-form {
  margin: 0;
  max-width: none;
}
.mis-hero__priority-card-rating {
  margin-top: clamp(16px, 2vw, 22px);
  justify-content: flex-start;
}
/* Móvil: estrellas (+ nota) CENTRADAS en una fila y "reviews on Google" en la
   siguiente, también centrada y SIN el divisor vertical (border-left) que trae
   `.app-rating-count` para separarse de las estrellas (colgaba al principio). */
@media (max-width: 720px) {
  .mis-hero__priority-card-rating { flex-wrap: wrap; justify-content: center; }
  .mis-hero__priority-card-rating .app-rating-count {
    flex-basis: 100%;
    border-left: 0;
    padding-left: 0;
    text-align: center;
  }
}

/* ── Modificador --scenic · foto de fondo + card en vidrio ──────────────
   Variante visual: la misma arquitectura (copy + card + ticker) pero sobre
   una foto cinematográfica. Para que la card no quede como un bloque opaco
   sobre la imagen, aplicamos vidrio (alpha + backdrop blur) y dejamos que
   la foto respire detrás. */
.mis-hero--scenic {
  position: relative;
  isolation: isolate;
  background: var(--bg-bold);    /* fallback si la foto no carga */
}
.mis-hero--scenic .mis-hero__inner { position: relative; z-index: 2; }
.mis-hero--scenic .mis-hero__ticker { position: relative; z-index: 2; }

/* Foto a sangre · cubre toda la banda. */
.mis-hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.mis-hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Scrim · degradado de bajada para que el contenido (sobre todo la card y
   el ticker en la zona inferior) tenga contraste suficiente. */
.mis-hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--scrim-photo-strong);
  pointer-events: none;
}

/* Card oscura · alpha alta (casi negra) + blur · destaca sobre la foto del hero. */
.mis-hero--scenic .mis-hero__priority-card {
  background: rgba(10, 12, 16, 0.9);
  backdrop-filter: var(--glass-filter-strong);
  -webkit-backdrop-filter: var(--glass-filter-strong);
  border-color: rgba(255, 255, 255, 0.18);
}

/* Reduced-motion · sin auto-scroll del ticker. */
@media (prefers-reduced-motion: reduce) {
  .mis-hero__ticker-track { animation: none; transform: none; }
}
