:root {
  --neon-cyan: #00f2fe;
  --neon-magenta: #fe019a;
}

html, body {
  margin: 0;
  padding: 0;
  background: #09090B;
  color: #fff;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  /* CORRECCIÓN v109 (la barra se desplazaba con `sticky`): aquí había `overflow-y: auto`, que
     convierte a `body` en un CONTENEDOR DE SCROLL. Con eso, el `position: sticky` de la barra se
     resuelve contra un contenedor que no scrollea (el scroll real ocurre en el viewport), así que la
     barra se comporta como `static` y el modo «fija» no se distinguía del «desplazable».
     `overflow-x: clip` NO crea contenedor de scroll (a diferencia de hidden/auto) y mantiene el
     recorte horizontal seguro; el eje vertical vuelve a `visible`, es decir, el scroll vive en el
     documento. Con esto `position: sticky` vuelve a funcionar de verdad. */
  /* v118/v119 · SIN SCROLL HORIZONTAL (causa del desplazamiento lateral en móvil).
     `clip` es lo ideal (no crea contenedor de scroll), pero Safari < 16 y algunos WebView no lo
     entienden y caen a `visible`: entonces cualquier elemento más ancho que la pantalla genera scroll
     horizontal, el navegador se queda «paneado» y se ve un MARGEN a la izquierda con el contenido
     cortado a la derecha (incluida la barra fija, que acompaña al viewport).
     Se declara primero `hidden` —compatible con todo— y después `clip`: los navegadores modernos usan
     `clip` y los antiguos conservan `hidden`, que también impide el scroll lateral. */
  overflow-y: auto;
  overflow-x: hidden;
  overflow-x: clip;
  /* Evita el «rebote» lateral y el paneo accidental al arrastrar sobre los carriles. */
  overscroll-behavior-x: none;
}

/* === RETÍCULA HORIZONTAL ÚNICA (v123) ========================================================
   `--sangria-tarjetas` es la distancia real desde el borde de la pantalla hasta el borde de las
   TARJETAS del catálogo. Sale de sumar la cadena de rellenos de la portada:
     · `#principal-app` .... `px-1` ......... 4 px
     · `main > div` ........ `px-3` ......... 12 px
     · marco del catálogo .. `p-1.5` (móvil) / `sm:p-3` (≥640px) ..... 6 px / 12 px
   ⇒ 4 + 12 + 6 = 22 px en móvil y 4 + 12 + 12 = 28 px desde 640 px.
   La usa la cabecera (y por tanto el carril de navegación) para que el inicio de la primera píldora y
   el final de la última coincidan EXACTAMENTE con los bordes de las tarjetas. Si algún día cambia el
   relleno de la portada, basta con actualizar este número (una sola fuente de verdad). */
:root {
  --sangria-tarjetas: 22px;
}

@media (min-width: 640px) {
  :root {
    --sangria-tarjetas: 28px;
  }
}

/* === AUTOSUFICIENCIA DE `.hidden` (v124) ====================================================
   `.hidden` es una UTILIDAD DE TAILWIND (CDN). Si el CDN no cargara (sin red, red lenta, bloqueo de
   terceros), `app.js` no podría ocultar secciones como «En Línea Ahora» o «Destacadas de la semana» y
   aparecerían **vacías con su título**. Se declara aquí para no depender de nada externo.
   ⚠ SIN `!important` A PROPÓSITO: Tailwind combina `.hidden` con utilidades de breakpoint
   (`hidden sm:inline`, `hidden md:block`…). Un `!important` aquí ganaría también en escritorio y
   dejaría elementos ocultos para siempre; sin él, la utilidad de breakpoint (que el CDN inyecta
   después) recupera el `display` correcto, igual que hoy. */
.hidden {
  display: none;
}

::-webkit-scrollbar {
  width: 6px;
  background-color: #09090B;
}

::-webkit-scrollbar-thumb {
  background-color: #09090B;
  border-radius: 10px;
}

html, body {
  scrollbar-color: #09090B #09090B;
}

/* ============================================================================
   BARRA SUPERIOR FIJA (v94) — cabecera de la aplicación
   La barra del header se queda pegada al borde superior mientras se hace scroll.

   SE USA `position: sticky` (y NO `fixed`) A PROPÓSITO
     · `sticky` reserva su espacio en el flujo: el contenido NUNCA queda oculto
       detrás de la barra y no hay que compensar con números mágicos. La cabecera
       mide distinto en móvil (la navegación baja a una SEGUNDA fila por
       `flex-wrap`) que en escritorio (una sola fila), así que un `padding-top`
       fijo quedaría corto o largo según la pantalla; con `fixed` ese hueco
       habría que acertarlo a mano en cada franja.
     · El resultado visible es el mismo que con `fixed`: arriba de todo, siempre.
     · Por eso `left: 0` / `width: 100%` tampoco son necesarios (la cabecera es
       un bloque a todo lo ancho) y se evita introducir restricciones de sticky
       horizontal en un layout sin scroll lateral (`overflow-x: clip`).

   NIVEL DE APILADO: `z-index: 50`. Mapa real de capas de index.html (nada queda
   tapado): barra 50 < #modal-reseñas 70 < #modal-perfil 80 < #login-modal 90 <
   #lightbox-perfil 95 < #panic-trigger 100 < office-mode 200 < avisos 300.
   Es decir: la barra tapa el contenido de la página y TODOS los overlays tapan
   la barra.

   FONDO: color corporativo oscuro (#09090B → #18181b) casi opaco + difuminado
   con saturación, para que las fotos que pasan por debajo no se lean a través
   del texto. Si el navegador no soporta `backdrop-filter`, el respaldo es un
   fondo SÓLIDO.
   ============================================================================ */
#app-shell > header {
  position: sticky;
  top: 0;
  z-index: 50;
  width: 100%;
  background: linear-gradient(180deg, rgba(9, 9, 11, 0.97) 0%, rgba(24, 24, 27, 0.95) 100%);
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  box-shadow: 0 10px 30px -24px rgba(0, 0, 0, 0.95);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
}

/* Respaldo sin difuminado: opaco del todo (mismo color corporativo). */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  #app-shell > header {
    background: #09090B;
  }
}

/* Desplazamiento de anclas con la barra pegada arriba: al pulsar un enlace del menú
   (p. ej. «Gran Concepción» → #filtros-comuna) el destino no aterriza bajo la barra.
   Móvil/tablet: la barra ocupa dos filas. Escritorio (≥1280px): una sola fila. */
html {
  scroll-padding-top: 6.5rem;
  zoom: 0.85;
}

@media (min-width: 1280px) {
  html {
    scroll-padding-top: 4.5rem;
  }
}

#filtros-comuna {
  scroll-margin-top: 0.5rem;
}

.neon-border {
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 0 18px rgba(0, 242, 254, 0.15), 0 0 32px rgba(254, 1, 154, 0.08);
}

.neon-text {
  text-shadow: 0 0 12px rgba(0, 242, 254, 0.35), 0 0 20px rgba(254, 1, 154, 0.2);
}

.neon-glow {
  box-shadow: 0 0 12px rgba(0, 242, 254, 0.22), 0 0 24px rgba(254, 1, 154, 0.16);
}

.glass-card {
  cursor: pointer;
  background: rgba(255, 255, 255, 0.03);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.08);
  transition: transform 200ms ease, box-shadow 200ms ease;
}

.glass-card:hover,
.glass-card:active {
  transform: scale(1.01);
  box-shadow: 0 0 18px rgba(0, 242, 254, 0.2);
}

.comuna-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  cursor: pointer;
  padding: 0.625rem 0.75rem;
  color: #a1a1aa;
  font-size: 0.875rem;
  font-weight: 500;
  transition: all 200ms ease;
}

.comuna-row:hover,
.comuna-row:active {
  background: rgba(255, 255, 255, 0.03);
  color: #fff;
  text-shadow: 0 0 8px rgba(0, 242, 254, 0.3);
}

.comuna-row:has(input:checked)::before {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: #00f2fe;
  box-shadow: 0 0 8px rgba(0, 242, 254, 0.6);
  content: '';
}

.comuna-row span {
  min-width: 0;
  flex: 1;
}

.comuna-count {
  margin-left: auto;
  color: #52525b;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  font-size: 0.75rem;
  line-height: 1rem;
}

.comuna-row:has(input:checked) .comuna-count {
  color: #00f2fe;
  text-shadow: 0 0 6px rgba(0, 242, 254, 0.5);
}

/* Cabecera de grupo del selector de BARRIO / SECTOR (v98): separa visualmente los barrios de
   cada comuna cuando el selector muestra varias. Mismo tono apagado que el resto del panel. */
.filtros-sector-grupo {
  margin: 0.35rem 0 0.1rem;
  padding: 0 0.75rem;
  color: #52525b;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* Insignia DISCRETA de la franja horaria (v99 · Fase 2) en la tarjeta del catálogo: pastilla
   mínima alineada con el nombre, que no compite con el estado ni con el precio. Sólo se pinta
   cuando el perfil declaró su franja de atención preferente. */
/* === BARRA SUPERIOR: FIJA vs DESPLAZABLE (v113) ==============================================
   El documento scrollea de forma NATURAL en la ventana (v113 revirtió el viewport fijo de v112) y lo
   ÚNICO que cambia entre modos es la POSICIÓN de la barra, elegida por el administrador en el Panel
   Maestro (`configuracion_sistema.barra_superior` → `html[data-barra]`):
     · `fija`  → `position: sticky; top: 0; z-index: 50`: se queda arriba mientras el resto scrollea.
     · `movil` → `position: static`: sube y desaparece junto con el contenido.
   Sin atributo manda la regla base de `#app-shell > header` (sticky), es decir, el modo por defecto.
   `!important` a propósito: la clase Tailwind `sticky` se inyecta DESPUÉS de este archivo.
   -------------------------------------------------------------------------------------------- */

/* ARQUITECTURA DE SCROLL (v113): se RETIRÓ el viewport fijo de v112 (`height: 100vh` + flex +
   scroller interno en `main`) porque el usuario pidió el scroll tradicional de la ventana. El
   documento scrollea con normalidad; `#app-shell` vuelve a su flujo natural. */

/* MODO FIJA (v114): `position: fixed` — es MÁS FUERTE que `sticky`: la barra sale del flujo y el
   contenido se desplaza POR DEBAJO de ella, sin que ningún ancestro con `overflow` pueda anularlo.
   Como `fixed` quita la barra del flujo, el hueco que deja se repone con un relleno calculado en
   `app.js` (`--altura-barra`), que se recalcula al redimensionar y cuando la barra cambia de alto
   (en móvil ocupa dos filas). */
html[data-barra='fija'] #app-shell > header {
  position: fixed !important;
  top: 0 !important;
  left: 0 !important;
  right: 0 !important;
  width: 100% !important;
  z-index: 50 !important;
}

html[data-barra='fija'] #app-shell {
  padding-top: var(--altura-barra, 0px);
}

html[data-barra='movil'] #app-shell {
  padding-top: 0;
}

/* === MARCA DE AGUA «PRIVÉ CONCE» (v116) ======================================================
   Marca de agua DINÁMICA superpuesta al medio (imagen o vídeo) justo antes de renderizarlo en el
   catálogo, en la galería del perfil y en el visor ampliado. Se dibuja como CAPA de CSS (pseudo-
   elemento `::after`) con el logotipo de la marca —cuadro rojo con la «P» + texto PRIVÉ CONCE— en
   SVG embebido, semitransparente (alfa 0,55) y en la esquina INFERIOR DERECHA, con tamaño reducido
   para no tapar el rostro.
   CLAVES DE UX Y SEGURIDAD:
     · `pointer-events: none` → NUNCA intercepta clics: las flechas del visor, la ✕ de cerrar, el
       botón de abrir perfil y los controles del carril siguen funcionando igual.
     · `z-index: 3` → queda por encima de la foto pero por debajo de los controles del visor (que
       viven fuera de la caja del medio), así que no tapa el título ni el contador.
     · Se aplica al CONTENEDOR: en el marcado sólo hay que añadir la clase `marca-agua`.
   LÍMITE HONESTO: es una marca visual disuasoria (dificulta el uso de la foto sin marca al copiar la
   pantalla), pero no cifra ni sirve la imagen «limpia» por otra ruta; el archivo original sigue
   siendo accesible a quien conozca su URL.
   ============================================================================================ */
.marca-agua {
  position: relative;
}

.marca-agua::after {
  content: '';
  position: absolute;
  right: 4%;
  bottom: 4%;
  width: 36%;
  max-width: 130px;
  aspect-ratio: 220 / 48;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 220 48'%3E%3Crect x='0' y='8' width='32' height='32' rx='8' fill='%23E11D48'/%3E%3Ctext x='16' y='31' font-family='Arial,Helvetica,sans-serif' font-size='20' font-weight='bold' fill='%23FFFFFF' text-anchor='middle'%3EP%3C/text%3E%3Ctext x='42' y='31' font-family='Arial,Helvetica,sans-serif' font-size='20' font-weight='bold' letter-spacing='1.5' fill='%23FFFFFF'%3EPRIV%C3%89 CONCE%3C/text%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  opacity: 0.55;
  pointer-events: none;
  z-index: 3;
}

/* En pantallas pequeñas la marca gana algo de tamaño relativo para seguir siendo legible. */
@media (max-width: 640px) {
  .marca-agua::after {
    width: 44%;
  }
}

/* En fichas muy pequeñas (carrusel de destacadas) la marca se reduce para no saturar. */
.marca-agua--mini::after {
  width: 52%;
  max-width: 76px;
  opacity: 0.5;
}

/* === DESTACADAS: TODAS LAS FICHAS EN MÓVIL (v146) ============================================
   Se RETIRÓ el recorte de la v117 —`@media (max-width: 767px) { .destacada-item:nth-child(n + 6)
   { display: none } }`—: en móvil el carril muestra **todas** las fichas cargadas y se desliza en
   horizontal para verlas, exactamente como en escritorio. Ninguna ficha queda oculta por posición;
   el único mecanismo de ocultación del proyecto sigue siendo la utilidad `.hidden` en la SECCIÓN.
   El carril mantiene su scroll táctil con `scroll-snap` (`.destacadas-track`). */

/* A partir de 768px vuelven a verse todas (el escritorio no necesita ninguna regla nueva). */
@media (min-width: 768px) {
  .destacada-item:nth-child(n + 6) {
    display: list-item;
  }
}

/* === ALINEACIÓN HORIZONTAL ROBUSTA (v118) ====================================================
   SINTOMA: en móvil todo el contenido aparecía desplazado hacia un lado.
   CAUSA: el ancho de los contenedores clave dependía del `box-sizing: border-box` que aporta el
   **preflight de Tailwind**, y ese CSS se inyecta DESPUÉS de este archivo (y podría no llegar a
   cargarse). En modo `content-box`, un contenedor con `width: 100%` MÁS relleno —la cabecera `fixed`
   con su padding seguro y el shell con `env(safe-area-inset-*)`— se hace MÁS ANCHO que el viewport y
   descuadra el conjunto hacia un lado.
   SOLUCIÓN: se declara aquí, y sin depender del CDN, el modelo de caja y los anchos máximos de los
   tres niveles raíz y de la cabecera fija. Además `img/video/svg` nunca podrán empujar el layout.
   NOTA: NO se usan `margin: auto` en `#app-shell`; el shell es de ancho completo y centrarlo con
   márgenes automáticos sólo generaría descuadres al combinarlo con el relleno de zona segura. */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  width: 100%;
  max-width: 100%;
}

#app-shell {
  /* v120 · SIN INSETS LATERALES (causa del desplazamiento en móvil).
     `env(safe-area-inset-left/right)` puede devolver un valor DESIGUAL en móviles con borde curvo o
     agujero de cámara (izquierda > 0, derecha = 0). Aplicado como relleno horizontal, eso empuja TODO
     el contenido hacia un lado: exactamente el «margen a la izquierda» reportado. Los insets
     VERTICALES (notch arriba, barra gestual abajo) no afectan al centrado y se conservan. */
  padding-left: 0;
  padding-right: 0;
  width: 100%;
  max-width: 100%;
  margin-left: 0;
  margin-right: 0;
  /* Nadie dentro del shell puede generar scroll lateral: lo que se salga se recorta aquí (la barra
     fija no se ve afectada porque está fuera del flujo del shell). */
  overflow-x: clip;
  /* v134 · ALTURA MÍNIMA Y COLUMNA FLEX: el shell mide al menos la pantalla y ordena sus piezas en
     vertical, de modo que el contenido (`#principal-app`) crece (`flex: 1`) y el pie queda SIEMPRE
     empujado al fondo con un colchón sólido debajo. Es `min-height` (no `height`) y sin `overflow`, así
     el scroll sigue viviendo en el documento y la barra (fixed) no se ve afectada. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* El contenido empuja al pie: ocupa todo el espacio libre del shell. */
#principal-app {
  flex: 1;
}

/* La cabecera fija ocupa EXACTAMENTE el viewport: izquierda, derecha y ancho explícitos y con el
   relleno incluido en ese ancho (border-box). */
#app-shell > header {
  left: 0;
  right: 0;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

/* Ningún medio puede exceder su contenedor (causa clásica de scroll lateral en móvil). */
img,
video,
svg,
canvas {
  max-width: 100%;
}
/* === CARRILES HORIZONTALES SIN BARRA VISIBLE (v115) ==========================================
   El marcado de la navegación móvil y del carril de filtros usa la clase `scrollbar-none`, pero NO
   estaba definida en este archivo: en escritorio las barras de esos carriles se dibujaban y robaban
   espacio útil (y ensuciaban el borde inferior). Aquí se ocultan en los tres motores. */
.scrollbar-none {
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.scrollbar-none::-webkit-scrollbar {
  width: 0;
  height: 0;
}

/* ============================================================================
   §2.110 · OPTIMIZACIÓN MÓVIL (FASE 1) — filtros compactos y deslizables «above the fold»
   ----------------------------------------------------------------------------
   QUÉ HACE (sólo en móvil)
     · `#catalog-search` ocupa el 100 % del ancho en SU PROPIA LÍNEA (`basis-full`).
     · El carril `#filtros-strip` queda SIEMPRE en una sola línea con desplazamiento horizontal
       táctil (`overflow-x: auto` + `nowrap`), sin barra de scroll visible (la oculta `.scrollbar-none`).
     · Los botones de filtro pasan a «píldoras» compactas (`px-2.5 py-1 text-[11px]`) con
       glassmorphism sutil (`rgba(255,255,255,.05)` + `blur(8px)`) y bordes redondeados.
   REGLA CRÍTICA: EXCLUSIVO MÓVIL
     Todo vive dentro de `@media (max-width: 767px)`. En ≥768 px NO se aplica ninguna de estas reglas:
     el escritorio conserva EXACTAMENTE el layout y el comportamiento anteriores (buscador flexible en
     la misma fila, carril con `sm:flex-wrap` y píldoras grandes). Los selectores usan el id
     (`#filtros-strip`, `#filtros-strip summary`) para ganar a las utilidades de Tailwind en el rango
     640–767 px, donde `sm:` ya está activo.
   Sin `100vw`, sin márgenes negativos y sin bloquear el scroll de la página (reglas de la casa).
   ============================================================================ */
@media (max-width: 767px) {
  /* 1) Buscador a ancho completo en su propia línea. */
  .buscador-principal {
    flex: 1 0 100%;
    width: 100%;
    padding: 0.375rem 0.75rem;
  }

  /* 2) Carril de filtros: una sola línea deslizable con el dedo. */
  #filtros-strip {
    flex-wrap: nowrap;
    overflow-x: auto;
    gap: 0.5rem;
    padding-top: 0.25rem;
    padding-bottom: 0.25rem;
  }

  /* 3) Píldoras compactas con glassmorphism sutil. */
  #filtros-strip summary {
    padding: 0.25rem 0.625rem;
    font-size: 11px;
    border-radius: 9999px;
    border-color: rgba(255, 255, 255, 0.10);
    background-color: rgba(255, 255, 255, 0.05);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
  }

  /* ---------------------------------------------------------------------------
     §2.111 · FASE 2 — BLOQUES DESTACADOS / BANNERS SUPERIORES (sólo móvil)
     Recorta el AIRE VERTICAL de la cabecera de la portada para que la primera fila de
     tarjetas del catálogo quede dentro de la primera pantalla, sin scroll:
       · `#destacadas-portada`: separación superior 1.25rem → 0.375rem y relleno vertical
         del panel 0.45/0.35rem → 0.375/0.25rem.
       · `#destacadas-track` (el carril): relleno vertical 0.85/0.8rem → 0.375rem (py-1.5); el relleno
         LATERAL sigue siendo `var(--relleno-destacadas-lados)`, que es la medida que
         garantiza la alineación con la retícula del catálogo (arnés móvil v127).
         Se apunta por ID (no por clase) a propósito: así la regla base del carril —de la que dependen
         los arneses v83/v127— sigue siendo la primera regla de esa clase que aparece en la hoja.
       · `#stories-en-linea` («En Línea ahora»): 0.75rem → 0.375rem.
       · buscador y filtros (`#principal-app aside`): 1.25rem → 0.5rem.
     Nada de esto se modifica fuera de la media query: en ≥768 px las alturas son las de siempre.
     --------------------------------------------------------------------------- */
  #destacadas-portada {
    margin-top: 0.375rem;
    padding-top: 0.375rem;
    padding-bottom: 0.25rem;
  }

  .destacadas-portada h2 {
    margin-bottom: 0.15rem;
  }

  #destacadas-track {
    padding-top: 0.375rem;
    padding-bottom: 0.375rem;
  }

  #stories-en-linea {
    margin-top: 0.375rem;
  }

  #principal-app aside {
    margin-top: 0.5rem;
  }

  /* ---------------------------------------------------------------------------
     §2.112 · FASE 3 — MODAL DE PERFIL `#modal-perfil` (sólo móvil)
     1) PESTAÑAS: barra compacta Galería · Detalles · Reputación que evita el scroll infinito. Se
        muestra sólo aquí (en el HTML nace con `hidden`) y el gating se hace con el atributo
        `data-perfil-tab-activa` que fija app.js → mostrarTabPerfil().
     2) REPUTACIÓN 2×2: los cuatro ejes (Veracidad, Puntualidad, Higiene, Trato) en una cuadrícula
        compacta de dos columnas, con la barra a lo ancho de su celda.
     3) CTA FIJO: la fila de WhatsApp/Llamar se queda pegada al borde inferior con `z-index` alto,
        siempre al alcance del pulgar.
     Nada de esto existe fuera de la media query: en ≥768 px el modal se ve EXACTAMENTE como antes
     (todas las secciones visibles, sin barra de pestañas y con la reputación en tres columnas).
     --------------------------------------------------------------------------- */
  /* v2.11 · Prominencia de las pestañas: barra con halo cian, píldoras más grandes y legibles,
     pestaña activa de alto contraste con PUNTO LUMINOSO, y «Detalles» resaltada (es la sección que
     más se consulta). Sigue siendo exclusivo de móvil: nada de esto existe fuera de la media query. */
  #perfil-tabs {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 0.3rem;
    overflow-x: auto;
    white-space: nowrap;
    border-bottom: 1px solid rgba(34, 211, 238, 0.25);
    background: rgba(20, 20, 20, 0.94);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 10px 18px -16px rgba(0, 0, 0, 0.95);
    padding: 0.4rem 0.5rem;
    -webkit-overflow-scrolling: touch;
  }

  .perfil-tab {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 0.3rem;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 9999px;
    background: rgba(255, 255, 255, 0.07);
    padding: 0.3rem 0.7rem;
    font-size: 12px;
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: 0.01em;
    color: #e4e4e7;
    white-space: nowrap;
  }

  /* Pestaña activa: contraste alto + borde luminoso + punto brillante. */
  .perfil-tab--activa,
  .perfil-tab[aria-selected="true"] {
    border-color: rgba(34, 211, 238, 0.8);
    background: linear-gradient(135deg, rgba(34, 211, 238, 0.24), rgba(225, 29, 72, 0.18));
    color: #a5f3fc;
    font-weight: 800;
    box-shadow: inset 0 0 0 1px rgba(34, 211, 238, 0.35), 0 0 12px -2px rgba(34, 211, 238, 0.6);
  }

  .perfil-tab--activa::before,
  .perfil-tab[aria-selected="true"]::before {
    content: '';
    flex: 0 0 auto;
    width: 5px;
    height: 5px;
    border-radius: 9999px;
    background: #67e8f9;
    box-shadow: 0 0 6px 1px rgba(34, 211, 238, 0.9);
  }

  /* Gating de secciones: §2.118 · «Detalles» dejó de ser pestaña propia y ahora se muestra INTEGRADA
     en la pestaña «Galería» (fotos + datos, servicios y descripción en la misma columna vertical), así
     que sólo se oculta lo que pertenece a «Reputación» y viceversa. */
  #modal-perfil[data-perfil-tab-activa="galeria"] [data-perfil-seccion]:not([data-perfil-seccion="galeria"]):not([data-perfil-seccion="detalles"]),
  #modal-perfil[data-perfil-tab-activa="reputacion"] [data-perfil-seccion]:not([data-perfil-seccion="reputacion"]) {
    display: none;
  }

  /* Legibilidad de la información integrada (servicios, medidas y descripción) en móvil. */
  #perfil-descripcion {
    font-size: 12px;
    line-height: 1.55;
  }

  /* Reputación de los cuatro ejes en 2×2 compacto (etiqueta + valor arriba, barra debajo). */
  #perfil-reputacion-barras {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.375rem;
  }

  #perfil-reputacion-barras > * + * {
    margin-top: 0;                       /* neutraliza el `space-y-1` del contenedor original */
  }

  #perfil-reputacion-barras .reputacion-fila {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "etiqueta valor" "barra barra";
    gap: 0.2rem 0.35rem;
  }

  #perfil-reputacion-barras .reputacion-etiqueta { grid-area: etiqueta; font-size: 0.625rem; }
  #perfil-reputacion-barras .reputacion-valor { grid-area: valor; }
  #perfil-reputacion-barras .reputacion-barra { grid-area: barra; }

  /* CTA de conversión siempre a la vista (pegado al borde inferior de la ficha). */
  .perfil-cta-barra {
    position: sticky;
    bottom: 0;
    z-index: 70;
  }

  /* ---------------------------------------------------------------------------
     §2.114 · FASE 4 — MÁRGENES Y CONTENEDORES DEL CATÁLOGO (sólo móvil)
     Recorta el «aire» muerto de la retícula y abarata el pintado de las tarjetas para que el scroll
     táctil se sienta más fluido, sin tocar ninguna medida lateral (la sangría de la retícula sigue
     siendo la que verifican los arneses v119/v123).
       · `#ads-grid`: separación entre bloques 0.5rem (Tailwind `gap-2`) → 0.375rem.
       · `.bloque-categoria > div` (la banda de categoría): margen y relleno vertical reducidos y
         tipografía algo más ajustada, para que entren más tarjetas en pantalla.
       · `#catalog-resumen` y `#filtros-chips`: menos aire respecto a los filtros.
       · Tarjetas: sin resalte azul de toque (`-webkit-tap-highlight-color`) y con una sombra de UNA
         capa en vez del `shadow-xl` de varias (mismo aspecto percibido en pantalla pequeña, menos
         pintado por fotograma durante el scroll). Se respeta el `touch-action: pan-y` de v79.
     EXCLUSIVO MÓVIL: fuera de esta media query no cambia nada; el escritorio mantiene su retícula de
     6 columnas, sus separaciones y su `shadow-xl` originales.
     --------------------------------------------------------------------------- */
  #ads-grid {
    gap: 0.375rem;
  }

  #ads-grid .bloque-categoria > div {
    margin-top: 0.25rem;
    margin-bottom: 0.25rem;
    padding-top: 0.2rem;
    padding-bottom: 0.2rem;
    font-size: 11px;
    letter-spacing: 0.08em;
  }

  #catalog-resumen,
  #filtros-chips {
    margin-top: 0.25rem;
  }

  #ads-grid article[data-id] {
    -webkit-tap-highlight-color: transparent;
    box-shadow: 0 3px 10px -8px rgba(0, 0, 0, 0.75);
  }

  /* ---------------------------------------------------------------------------
     §2.116 · FASE 5.1 — BOTONERA 50/50 Y DELGADA (sólo móvil)
     Los dos botones de la tarjeta (WhatsApp y llamada, generados por `contacto.js`) reparten el ancho
     de forma ESTRICTAMENTE SIMÉTRICA y pierden grosor:
       · `flex: 1 1 0` en ambos ⇒ ancho exacto = (100 % − gap) / 2 para cada uno, sin importar el
         contenido; `width: auto` neutraliza el `w-7` del botón de llamada y `min-width: 0` evita que
         el texto fuerce el ancho.
       · Alto por RELLENO: `padding: 0.375rem 0.25rem` con `line-height: 1` (≈24 px en vez de los
         28 px del `h-7`), esquinas limpias de `0.5rem` y relleno lateral recortado para que la
         etiqueta quepa en su mitad.
       · Tipografía e iconos proporcionados: texto 11 px, iconos 0.875rem.
     Los selectores llevan la clase de la tarjeta (`.tarjeta-contacto-host .tarjeta-contacto`) para
     ganar a las utilidades de Tailwind con independencia del orden de inyección del CDN.
     EXCLUSIVO MÓVIL: en ≥768 px la botonera conserva su `h-7`, su `gap-1`, su reparto
     (`flex-1` + `w-7` cuadrados) y su tipografía originales, sin ninguna interferencia.
     --------------------------------------------------------------------------- */
  .tarjeta-contacto-host .tarjeta-contacto {
    gap: 0.25rem;
    align-items: stretch;
  }

  /* §2.117 · ULTRA DELGADO (sólo móvil): barra de 22 px fijos (máx. 24 px) con relleno vertical
     mínimo, manteniendo el reparto 50/50 exacto de §2.116 y el icono reducido a 0.75rem. */
  .tarjeta-contacto-host .tarjeta-contacto > a,
  .tarjeta-contacto-host .tarjeta-contacto > span {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    height: 22px;
    max-height: 24px;
    min-height: 22px;
    padding: 0.15rem 0.25rem;
    border-radius: 0.375rem;
    font-size: 10px;
    line-height: 1;
    gap: 0.15rem;
  }

  .tarjeta-contacto-host .tarjeta-contacto svg {
    width: 0.75rem;
    height: 0.75rem;
  }

  /* ---------------------------------------------------------------------------
     §2.119 · FASE 7 — WIDGET VIP EN MÓVIL (cierre accesible para cualquier visitante)
     El widget flota sobre el catálogo, así que en móvil la «✕» debe ser un blanco de toque cómodo
     (2rem = 32 px) y con contraste suficiente incluso sobre las fotos. A quién se le ofrece la «✕» y
     qué se recuerda vive en `app.js` (sesión registrada **o** vista móvil; el cierre se guarda en
     `localStorage`, por cuenta si hay sesión). Los perfiles VIP, además, entran en la retícula del
     catálogo en móvil (Fase 7.2, `app.js`), de modo que nunca desaparecen al cerrar el widget.
     EXCLUSIVO MÓVIL: en ≥768 px la «✕» conserva su tamaño y su aspecto originales.
     --------------------------------------------------------------------------- */
  #vip-fila.vip-widget .vip-widget-cerrar {
    height: 2rem;
    width: 2rem;
    font-size: 0.8125rem;
    background: rgba(0, 0, 0, 0.82);
    color: #ffffff;
  }
}

/* === MÁRGENES SEGUROS EN MÓVIL (v115, corregido en v120) =====================================
   `index.html` declara `viewport-fit=cover`, así que el layout puede invadir el notch/isla y la barra
   gestual. Sólo se usan los insets VERTICALES (arriba en la barra, abajo en el pie): son simétricos y
   no alteran el centrado horizontal. Los LATERALES se eliminaron en v120 porque en móviles con borde
   curvo/agujero de cámara pueden venir DESIGUALES (izquierda > 0, derecha = 0) y desplazaban todo el
   contenido a un lado. En escritorio `env()` vale 0 y todo queda igual que antes. */
#app-shell > header {
  /* RELLENO LATERAL RETIRADO (v122/v123) — antes 0.75rem, que se SUMABA al `px-3 sm:px-4` de la fila
     interior: la barra quedaba a 24 px del borde mientras el catálogo empezaba a 22 px (desalineado y
     con menos ancho útil). Ahora la sangría la aporta la FILA con `--sangria-tarjetas` (ver regla
     siguiente), así que la cabecera no acumula nada. Se conserva el inset VERTICAL (notch), que sí es
     simétrico y no afecta al centrado horizontal. */
  padding-left: 0;
  padding-right: 0;
  padding-top: env(safe-area-inset-top);
  max-width: 100%;
  box-sizing: border-box;
}

/* LA FILA DE LA CABECERA COMPARTE LA RETÍCULA DE LAS TARJETAS (v123) --------------------------
   `#app-shell > header > div` es un selector con ID: gana siempre al `px-3 sm:px-4` de utilidades
   (especificidad 1-0-2 frente a 0-1-0) sin necesidad de `!important`. Con esto el logotipo, el bloque
   de acciones y el carril de navegación empiezan y terminan exactamente donde las tarjetas, en TODOS
   los anchos (móvil y escritorio), porque el valor sale de la misma variable. */
#app-shell > header > div {
  padding-left: var(--sangria-tarjetas);
  padding-right: var(--sangria-tarjetas);
}

#app-shell > footer {
  /* v134 · El pie nunca se pega al borde inferior: `margin-top: auto` lo empuja al fondo del shell
     (que mide al menos una pantalla) y el relleno inferior se queda en 5rem como mínimo, respetando el
     inset de la barra gestual del móvil cuando es mayor. */
  margin-top: auto;
  padding-bottom: max(5rem, env(safe-area-inset-bottom));
}

html[data-barra='movil'] #app-shell > header {
  /* `!important` a propósito: la clase Tailwind `sticky` (inyectada por el CDN DESPUÉS de este
     archivo) y la regla base deben perder SIEMPRE contra el modo elegido por el administrador. */
  position: static !important;
  top: auto !important;
  z-index: auto !important;
}

.franja-pill {
  display: block;
  max-width: 100%;
  margin-top: 0.15rem;
  overflow: hidden;
  color: #fcd34d;
  font-size: 9px;
  line-height: 1.2;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: 0.9;
}

/* INSIGNIAS DE CONFIANZA (v100 · Fase 3): en la ficha del catálogo van sólo los iconos, en una
   fila mínima que no compite con el nombre ni con el precio; en el modal se añade el texto. */
.insignias-pill {
  display: flex;
  max-width: 100%;
  margin-top: 0.15rem;
  gap: 0.15rem;
  overflow: hidden;
}

.insignia-pill {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 0.35rem;
  background: rgba(255, 255, 255, 0.06);
  font-size: 9px;
  line-height: 1;
}

/* Variante con texto (modal): la pastilla se estira para que se lea la insignia. */
.insignia-pill--texto {
  gap: 0.2rem;
  width: auto;
  height: auto;
  padding: 0.15rem 0.4rem;
  color: #d4d4d8;
  font-size: 10px;
  white-space: nowrap;
}

aside input[type="checkbox"] {
  appearance: none;
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
  margin: 0;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 0.375rem;
  background: transparent;
  cursor: pointer;
  transition: all 200ms ease;
}

aside input[type="checkbox"]:checked {
  border-color: #00f2fe;
  background: #00f2fe;
  box-shadow: 0 0 8px rgba(0, 242, 254, 0.6);
}

aside input[type="checkbox"]:checked::after {
  display: block;
  color: #121212;
  content: '✓';
  font-size: 12px;
  font-weight: 800;
  line-height: 14px;
  text-align: center;
}

.status-live {
  animation: status-pulse 1.6s ease-in-out infinite;
}

@media (max-width: 1279px) {
  #ads-grid a[aria-label] > span {
    display: none !important;
  }
}

@keyframes status-pulse {
  50% { box-shadow: 0 0 0 5px rgba(34, 197, 94, 0.08); }
}

/* Se retiró la regla legacy `body, main, aside, nav, section, div { -webkit-overflow-scrolling: touch }`:
   en iOS 13+ es el comportamiento por defecto y aplicada de forma global creaba contenedores
   compuestos que congelaban el scroll vertical de la página. */

/* Tarjetas del catálogo: permiso explícito de desplazamiento vertical nativo (dedo y rueda).
   Las tarjetas (`article` / `.abrir-perfil`) NO llevan `touch-action: none` ni
   `pointer-events: none`; esos valores solo existen en overlays decorativos internos
   (degradado, marca de agua, badge), que deben seguir sin interceptar el clic de apertura. */
#ads-grid article,
#ads-grid .abrir-perfil {
  touch-action: pan-y;
}

/* ============================================================================
   RETÍCULA DEL CATÁLOGO EN ESCRITORIO (v143)
   Escritorio (≥1024px): exactamente **6 tarjetas por fila**. La versión móvil no
   se toca: 3 columnas fijas por debajo de 768px (`index.html`) y 4 de 768 a
   1023px (`md:grid-cols-4`). Espejo en utilidades de `app.js`: `lg:grid-cols-6`.
   ============================================================================ */
@media (min-width: 1024px) {
  #ads-grid .bloque-categoria > .grid {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

/* ============================================================================
   BOTONERA DE CONTACTO DE LAS TARJETAS (v79, generalizada en v80)
   WhatsApp (verde corporativo) + llamada directa (cian, en armonía con el botón
   de llamada del modal de perfil) sobre el borde INFERIOR de la tarjeta, para no
   tapar la foto de portada.

   Se aplica a TODA tarjeta marcada con `.tarjeta-contacto-host`, es decir:
     · las tarjetas del catálogo público (#ads-grid, app.js) y
     · las tarjetas de «Mis escorts favoritas» del panel del cliente.
   El HTML de la botonera lo genera `contacto.js` para que ambas vistas sean
   idénticas (mismo verde/cian, mismos tamaños, mismos aria-label).

   · Sin hover (móvil/tablet táctil): SIEMPRE visibles y pulsables. Son la vía
     principal de contacto y no existe hover que las revele.
   · Con ratón (hover + puntero fino): en reposo quedan ocultas y con
     `pointer-events: none`, de modo que un clic en esa franja siga abriendo el
     perfil; se revelan al pasar el cursor o al enfocar con el teclado dentro de
     la tarjeta (`:focus-within`), así también son accesibles por teclado.
   · En pantallas híbridas (portátil táctil con ratón) el navegador declara hover:
     con el dedo la franja abre el perfil, que ya incluye su propia fila de
     contacto; con el ratón la botonera aparece con normalidad.
   ============================================================================ */
.tarjeta-contacto {
  opacity: 1;
  transform: none;
  transition: opacity .18s ease, transform .18s ease;
}

@media (hover: hover) and (pointer: fine) {
  .tarjeta-contacto-host .tarjeta-contacto {
    opacity: 0;
    transform: translateY(4px);
    pointer-events: none;
  }

  .tarjeta-contacto-host:hover .tarjeta-contacto,
  .tarjeta-contacto-host:focus-within .tarjeta-contacto {
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }
}

/* ----------------------------------------------------------------------------
   HOVER CORPORATIVO DE LA TARJETA (v92)
   Mismo carmesí que el carrusel destacado y que los elementos de la casa
   (`.salida-rapida`, `.cta-publicar`): borde rojo + brillo carmesí al pasar el
   cursor por las tarjetas del catálogo tradicional (`#ads-grid`) — y también por
   las de «Mis escorts favoritas» del panel del cliente, porque ambas comparten
   `.tarjeta-contacto-host` por diseño (mismos colores y tamaños en las dos vistas).
     · En reposo nada cambia: la tarjeta conserva su `border-zinc-900/60` y su
       `shadow-xl`. Al hacer hover (o al enfocar con el teclado dentro de ella) el
       borde se enciende y la sombra plana pasa a ser un resplandor carmesí.
     · GANA por especificidad `(0,2,0)` frente al `(0,1,0)` de las clases de
       Tailwind del marcado (app.js): no hace falta `!important`.
     · NO interfiere con los colores de estado del catálogo: el punto «En Línea»
       (`.status-live` + `bg-emerald-400`), la insignia «Verificada»
       (`bg-red-600/80`) y el corazón de favoritos (`rose`) conservan los suyos.
       Esta regla sólo declara `border-color` y `box-shadow` del CONTENEDOR.
     · La transición vive en la tarjeta, de modo que el encendido es fluido y
       respeta `prefers-reduced-motion` (bloque de más abajo).
   ---------------------------------------------------------------------------- */
.tarjeta-contacto-host {
  transition: border-color 180ms ease, box-shadow 200ms ease;
}

.tarjeta-contacto-host:hover,
.tarjeta-contacto-host:focus-within {
  border-color: rgba(248, 113, 113, 0.7);
  box-shadow: 0 0 14px -2px rgba(225, 29, 72, 0.55), 0 20px 40px -26px rgba(0, 0, 0, 0.95);
}

/* Tarjetas estrechas (rejilla de 3 columnas en móvil): los botones van sólo con
   icono, porque el texto no cabe y el nombre de la escort debe seguir mandando. */
@media (max-width: 1279px) {
  .tarjeta-contacto-texto {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .tarjeta-contacto,
  .tarjeta-contacto-host {
    transition: none;
  }
}

/* Barra de categorías: scroll horizontal fluido con la scrollbar oculta
   (se aplica solo a este contenedor; no se usa la regla global que congelaba el scroll). */
.category-scroll {
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.category-scroll::-webkit-scrollbar {
  display: none;
}

.sidebar-glass {
  background: rgba(18, 18, 18, 0.6);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-right: 1px solid rgba(255, 255, 255, 0.05);
  padding: 0.75rem 0;
}

/* ============================================================================
   BOTÓN DE PÁNICO / SALIDA RÁPIDA
   Visible en la cabecera fija (`sticky top-0`), accesible con el pulgar en móvil
   y con el ratón en desktop. El color de urgencia es discreto (rojo apagado)
   para no romper la estética oscura del catálogo. Sin utilidades Tailwind en
   conflicto: todo el aspecto vive aquí.
   ============================================================================ */
.salida-rapida {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 0.375rem;
  min-height: 34px;
  padding: 0.35rem 0.5rem;
  border: 1px solid rgba(248, 113, 113, 0.45);
  border-radius: 9999px;
  background: rgba(127, 29, 29, 0.28);
  color: #fecaca;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.02em;
  white-space: nowrap;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  transition: background 160ms ease, border-color 160ms ease, color 160ms ease, transform 160ms ease;
}

.salida-rapida:hover {
  border-color: rgba(248, 113, 113, 0.8);
  background: rgba(185, 28, 28, 0.5);
  color: #fff;
}

.salida-rapida:active {
  transform: scale(0.96);
}

.salida-rapida:focus-visible {
  outline: 2px solid #f87171;
  outline-offset: 2px;
}

.salida-rapida-icono {
  width: 1rem;
  height: 1rem;
  flex: 0 0 auto;
}

/* En pantallas estrechas el botón queda como ícono puro (accesible por aria-label) para no
   saturar la cabecera; desde 640px recupera el texto "Salida Rápida". */
.salida-rapida-texto {
  display: none;
}

@media (min-width: 640px) {
  .salida-rapida {
    padding: 0.35rem 0.75rem;
  }

  .salida-rapida-texto {
    display: inline;
  }
}

/* ============================================================================
   CTA DE CONVERSIÓN «ANÚNCIATE» (v82)
   Botón de captación de la barra superior (nuevas escorts / anunciantes).
   Va junto a la Salida Rápida, ANTES del bloque de sesión: es el único botón
   de acento cálido de la cabecera y no debe quedar bajo el overlay invisible
   #panic-trigger (z-[100], esquina superior derecha).
   Visible para invitados y clientes; app.js lo oculta a escorts y superadmin.
   Como en la Salida Rápida, todo el aspecto vive aquí (sin utilidades Tailwind
   en conflicto) para que el degradado no dependa del CDN de Tailwind.
   ============================================================================ */
.cta-publicar {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 0.375rem;
  min-height: 34px;
  padding: 0.35rem 0.7rem;
  border: 1px solid rgba(251, 113, 133, 0.5);
  border-radius: 9999px;
  background: linear-gradient(135deg, #e11d48 0%, #be123c 55%, #881337 100%);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.02em;
  white-space: nowrap;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  box-shadow: 0 0 12px rgba(225, 29, 72, 0.35);
  transition: filter 160ms ease, box-shadow 200ms ease, transform 160ms ease;
}

.cta-publicar:hover {
  filter: brightness(1.1);
  box-shadow: 0 0 20px rgba(225, 29, 72, 0.55);
}

.cta-publicar:active {
  transform: scale(0.96);
}

.cta-publicar:focus-visible {
  outline: 2px solid #fb7185;
  outline-offset: 2px;
}

.cta-publicar-icono {
  width: 1rem;
  height: 1rem;
  flex: 0 0 auto;
}

/* En pantallas muy estrechas (≤359px) el CTA queda como icono puro para no empujar
   la Salida Rápida ni el bloque de sesión; desde 360px recupera el texto. */
.cta-publicar-texto {
  display: none;
}

@media (min-width: 360px) {
  .cta-publicar-texto {
    display: inline;
  }
}

/* Navegación de la cabecera: en móvil/tablet vive en una segunda fila con scroll
   horizontal fluido (nunca desborda la pantalla); desde 1280px se integra en la
   fila única con el logotipo y las acciones. */
#nav-principal {
  -webkit-overflow-scrolling: touch;
  /* Deslizamiento fluido (v122): el rebote lateral se contiene EN EL PROPIO CARRIL (no arrastra la
     página, que era la vía por la que el viewport quedaba «paneado») y el desplazamiento es suave. */
  overscroll-behavior-x: contain;
  scroll-behavior: smooth;
}

/* === CARRIL DE NAVEGACIÓN ALINEADO CON LA RETÍCULA DE TARJETAS (v122 · afinado en v123) ===
   Por debajo de 1280px la navegación vive en su PROPIA fila (ocupa el 100% por `flex-wrap`) y es un
   carril con scroll horizontal. La sangría lateral NO se declara aquí: ya la aporta la fila de la
   cabecera con `--sangria-tarjetas` (22 px en móvil, 28 px desde 640 px), que es EXACTAMENTE la misma
   que separa las tarjetas del borde. Consecuencias buscadas:
     · la primera píldora arranca en el borde izquierdo de las tarjetas y, al deslizar hasta el final,
       la última termina en el borde derecho: alineación milimétrica con la retícula;
     · al no haber relleno propio en el carril, no se suma ninguna sangría y la última píldora queda
       SIEMPRE completa (su borde derecho coincide con el del carril, ya dentro de la pantalla);
     · `scroll-padding` usa la misma medida como referencia al desplazar o al enfocar con teclado;
     · `scroll-snap` (proximidad, nunca forzado) deja cada píldora asentada en esa misma línea.
   Desde 1280px la navegación vuelve a ser una fila en línea (`xl:overflow-visible`) y nada de esto se
   aplica: el espaciado recupera el comportamiento de escritorio. */
@media (max-width: 1279.98px) {
  #nav-principal {
    width: 100%;
    min-width: 0;
    max-width: 100%;
    /* Sin relleno: la alineación la garantiza la fila de la cabecera (una sola fuente de verdad). */
    padding-left: 0;
    padding-right: 0;
    scroll-padding-left: var(--sangria-tarjetas);
    scroll-padding-right: var(--sangria-tarjetas);
    scroll-snap-type: x proximity;
  }

  .nav-enlace {
    scroll-snap-align: start;
  }
}

/* ============================================================================
   ENLACES DE LA NAVEGACIÓN (v82)
   Un único <nav> con dos comportamientos según el ancho:
     · <1280px → píldoras táctiles en una segunda fila con scroll horizontal fluido.
     · ≥1280px → enlaces en línea dentro de la fila única (logotipo · enlaces · acciones).
   El aspecto vive aquí y no en clases Tailwind del marcado: así la cabecera no
   depende del CDN y el ancho de cada píldora es predecible.
   ============================================================================ */
.nav-enlace {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 0.375rem;
  min-height: 32px;
  padding: 0.35rem 0.75rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 9999px;
  background: rgba(255, 255, 255, 0.05);
  color: #d4d4d8;
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  transition: background 160ms ease, border-color 160ms ease, color 160ms ease, transform 160ms ease;
}

.nav-enlace:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.18);
  color: #fff;
}

.nav-enlace:active {
  transform: scale(0.98);
}

.nav-enlace:focus-visible {
  outline: 2px solid #22d3ee;
  outline-offset: 2px;
}

.nav-enlace-icono {
  width: 0.875rem;
  height: 0.875rem;
  flex: 0 0 auto;
}

/* AJUSTE ARMÓNICO DE LA PÍLDORA EN PANTALLAS MUY ESTRECHAS (v123) ------------------------------
   Con la sangría de retícula (22 px por lado) el ancho útil del carril en un móvil de 360 px es 316 px,
   y las cuatro etiquetas (Explorar · Nuevas · Gran Concepción · Verificación) suman ~480 px: el carril
   desliza —que es exactamente su cometido—. Para que antes de deslizar quepan más etiquetas COMPLETAS,
   por debajo de 400 px la píldora reduce su relleno lateral (0.75rem → 0.6rem, ~5 px por botón).
   Nunca se encoge ni parte el texto: `flex: 0 0 auto` + `white-space: nowrap` hacen que el conjunto
   deslice en lugar de aplastarse, y el ancho total jamás desborda el contenedor (es él quien scrollea). */
@media (max-width: 400px) {
  .nav-enlace {
    padding-left: 0.6rem;
    padding-right: 0.6rem;
  }
}

@media (min-width: 1280px) {
  .nav-enlace {
    min-height: 38px;
    padding: 0.5rem 0.95rem;
    border-color: transparent;
    background: transparent;
    color: #a1a1aa;
    font-size: 0.875rem;
  }

  .nav-enlace:hover {
    background: rgba(39, 39, 42, 0.7);
    border-color: transparent;
    color: #fff;
  }

  .nav-enlace-icono {
    width: 1rem;
    height: 1rem;
  }
}

/* ============================================================================
   CARRUSEL DESTACADO · MINITARJETAS FOTOGRÁFICAS COMPACTAS (v83 · v84 · v85 · v93)
   Banda superior de la portada. El orden lo decide el algoritmo híbrido de
   `get_destacadas.php` (VIP manual + clics reales + cortesía a cuentas nuevas) y
   la vista muestra como MÁXIMO 12 perfiles (`LIMITE_DESTACADAS` en app.js).
   Diseño v93 — BANDA MÍNIMA, TODA LA SELECCIÓN A LA VISTA:
     · Escala reducida por tercera vez: el TECHO de cada minitarjeta baja de
       10rem (160 px) → 7rem (112 px, v85) → 5rem (80 px). La superficie de la
       ficha queda en ~51% respecto de la v85 y en ~25% respecto del diseño
       original: la banda ocupa la mitad de alto que antes de la v85.
     · Nada puede ocupar el ancho completo: el `clamp()` fija el techo y el
       ancho FLUIDO (`calc((100% - huecos) / visibles)` con `--destacadas-visibles`
       por franja de pantalla) reparte el resto: 4 fichas en móvil, 8 en
       escritorio y hasta 14 en pantallas anchas — así los 12 perfiles del tope
       caben sin deslizar. Si el endpoint enviara menos, el carril se queda con
       hueco a la derecha: jamás estira una tarjeta para rellenar.
     · Paddings, huecos, radios, tipografías e insignia se escalan en la misma
       proporción (~0.71×) para que el conjunto guarde armonía a este tamaño.
     · Sigue siendo un carrusel: scroll horizontal táctil con scroll-snap para
       los perfiles que no caben (móvil y tableta).
   Geometría: rectángulo limpio 3/4 con esquinas redondeadas sutiles. Los acentos de
   neón son bordes discretos: ROJO al pasar el cursor (`.destacada-ficha:hover`), ámbar
   si el perfil es VIP (`.destacada-foto--vip`) o verde si está En Línea
   (`.destacada-foto--live`) — el VIP y En Línea conservan su color también en el hover.
   Aquí no se pinta ninguna métrica.
   ============================================================================ */
.destacadas-portada {
  position: relative;
  /* Panel también más liviano: menos relleno y sombra más contenida (v85, afinado en v93). */
  padding: 0.45rem 0.4rem 0.35rem;
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 1.25rem;
  background: linear-gradient(180deg, rgba(24, 24, 27, 0.6), rgba(9, 9, 11, 0.66));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.035), 0 14px 34px -30px rgba(0, 0, 0, 0.95);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  /* Techo duro del ancho de cada minitarjeta: nunca una tarjeta a pantalla completa. */
  --destacadas-ancho-max: 5rem;
}

/* Aire proporcional dentro del panel: el título respira del carril. */
.destacadas-portada h2 {
  margin-bottom: 0.3rem;
}


.destacadas-track {
  /* ANCHO FLUIDO (v85): `--destacadas-visibles` fija cuántas fichas caben a la vez
     y el hueco se descuenta del 100% disponible, así el carril nunca desborda ni
     estira la última tarjeta. Se ajusta por franjas de pantalla más abajo. */
  --destacadas-gap: 0.3rem;
  --destacadas-visibles: 4;
  /* RETÍCULA COMPARTIDA CON LAS TARJETAS DEL CATÁLOGO (v127) --------------------------------
     La banda NO arranca en el borde de la pantalla: su contenedor padre (`#principal-app` con
     `px-1` + el `div.px-3` de la portada) ya la deja a 16 px. Las tarjetas de ESCORTS, en cambio,
     van dentro de un marco con `p-1.5` (móvil) / `sm:p-3` (≥640px), así que su borde izquierdo cae a
     16 + 6 = 22 px y a 16 + 12 = 28 px, que es exactamente `--sangria-tarjetas` (v123).
     Para que el borde izquierdo de la PRIMERA ficha destacada —y el derecho de la última— coincidan
     con los de esas tarjetas, el carril suma esa misma diferencia: 6 px en móvil y 12 px desde
     640px (más abajo). Así ninguna medida queda escrita dos veces y la alineación es verificable:
        16 px (portada) + var(--relleno-destacadas-lados) = var(--sangria-tarjetas).
     NOTA: el aire lateral también protege el halo carmesí/ámbar/verde de la primera y la última
     ficha, que el `overflow-y: hidden` del carril recortaría (motivo original de la v97). */
  --relleno-destacadas-lados: 6px;
  display: flex;
  gap: var(--destacadas-gap);
  margin: 0;
  /* AIRE DEL HALO (v97 · laterales revisados en v127): el carril recorta con `overflow-y: hidden`,
     así que reserva el radio del brillo EXTERIOR de las fichas —glow carmesí del hover y de los
     estados VIP (ámbar) y En Línea (verde): `0 0 14px -2px` = 12 px de radio, más el 1 px de
     elevación del hover arriba— y, a los lados, la diferencia de retícula calculada justo arriba. */
  padding: 0.85rem var(--relleno-destacadas-lados) 0.8rem;
  list-style: none;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-behavior: smooth;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}

/* Desde 640px el marco del catálogo engorda a `sm:p-3` (12 px): la banda suma lo mismo para seguir
   alineada con las tarjetas de ESCORTS (16 + 12 = 28 px = `--sangria-tarjetas`). */
@media (min-width: 640px) {
  .destacadas-track {
    --relleno-destacadas-lados: 12px;
  }
}

/* Minitarjeta fluida pero ACOTADA: el `clamp()` garantiza que ni con un único
   perfil la ficha ocupa el ancho de la pantalla (techo de 5rem = 80 px; la v85 lo
   dejó en 7rem y el diseño original en 10rem). */
.destacada-item {
  flex: 0 0 auto;
  /* Respaldo para navegadores sin `clamp()`: mismo techo, ancho fijo. */
  width: 5rem;
  width: clamp(
    3.4rem,
    calc((100% - (var(--destacadas-visibles) - 1) * var(--destacadas-gap)) / var(--destacadas-visibles)),
    var(--destacadas-ancho-max)
  );
  scroll-snap-align: start;
}

.destacada-ficha {
  display: flex;
  width: 100%;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
}

.destacada-ficha:focus-visible {
  outline: 2px solid rgba(34, 211, 238, 0.9);
  outline-offset: 2px;
  border-radius: 0.5rem;
}

/* Minitarjeta fotográfica: rectángulo limpio con esquinas redondeadas sutiles. */
.destacada-foto {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 0.45rem;
  background: #18181b;
  transition: border-color 180ms ease, box-shadow 200ms ease, transform 200ms ease;
}

.destacada-avatar {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Retrato centrado en el rostro dentro del rectángulo. */
  object-position: center 22%;
}

/* HOVER NEUTRO EN ROJO (v91): realce de las fichas que no son VIP ni están En Línea.
   Las reglas `--vip` y `--live` vienen DESPUÉS con la MISMA especificidad (0,3,0), así
   que siguen mandando: el ámbar del VIP y el verde de En Línea no se pisan con el rojo.
   Los tonos son los de la casa (borde de `.salida-rapida` + brillo de `.cta-publicar`). */
.destacada-ficha:hover .destacada-foto {
  transform: translateY(-1px);
  border-color: rgba(248, 113, 113, 0.7);
  box-shadow: 0 0 14px -2px rgba(225, 29, 72, 0.55), 0 8px 18px -14px rgba(0, 0, 0, 0.9);
}

/* Único acento de neón: borde discreto para VIP (prioridad de pago) o En Línea. */
.destacada-foto--vip {
  border-color: rgba(251, 191, 36, 0.55);
  box-shadow: 0 0 9px -2px rgba(251, 191, 36, 0.45);
}

.destacada-ficha:hover .destacada-foto--vip {
  border-color: rgba(251, 191, 36, 0.85);
  box-shadow: 0 0 14px -2px rgba(251, 191, 36, 0.6);
}

.destacada-foto--live {
  border-color: rgba(52, 211, 153, 0.45);
  box-shadow: 0 0 9px -3px rgba(52, 211, 153, 0.4);
}

.destacada-ficha:hover .destacada-foto--live {
  border-color: rgba(52, 211, 153, 0.75);
  box-shadow: 0 0 14px -3px rgba(52, 211, 153, 0.55);
}

/* --- Nombre e indicador de estado (debajo de la minitarjeta) --- */
.destacada-nombre {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.625rem;
  font-weight: 600;
  line-height: 1.25;
  color: #fff;
}

.destacada-estado {
  display: inline-flex;
  max-width: 100%;
  align-items: center;
  overflow: hidden;
  gap: 0.2rem;
  font-size: 0.5625rem;
  line-height: 1;
  white-space: nowrap;
  color: #a1a1aa;
}

.destacada-estado i {
  width: 0.25rem;
  height: 0.25rem;
  flex: 0 0 auto;
  border-radius: 9999px;
  background: #52525b;
}

.destacada-estado--live {
  color: #6ee7b7;
}

.destacada-estado--live i {
  background: #34d399;
  animation: status-pulse 2s infinite;
}

.destacada-estado--libre {
  color: #67e8f9;
}

.destacada-estado--libre i {
  background: #22d3ee;
}

/* --- Insignia VIP: un único distintivo discreto dentro de la foto --- */
.destacada-insignia {
  position: absolute;
  z-index: 2;
  font-weight: 800;
  line-height: 1;
  pointer-events: none;
}

.destacada-insignia--vip {
  top: 0.2rem;
  left: 0.2rem;
  display: inline-flex;
  width: 0.7rem;
  height: 0.7rem;
  align-items: center;
  justify-content: center;
  border-radius: 0.35rem;
  background: rgba(9, 9, 11, 0.62);
  border: 1px solid rgba(251, 191, 36, 0.6);
  color: #fcd34d;
  font-size: 0.4375rem;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

/* FRANJAS DE PANTALLA (v85): cuántas minitarjetas se ven a la vez. El ancho real
   de cada ficha lo calcula `.destacada-item` a partir de esta variable, así que el
   número de tarjetas simultáneas está garantizado sin depender del contenedor. */
@media (min-width: 480px) {
  .destacadas-track {
    --destacadas-visibles: 5;
  }
}

@media (min-width: 640px) {
  .destacadas-track {
    --destacadas-visibles: 6;
  }

  .destacada-foto {
    border-radius: 0.5rem;
  }
}

@media (min-width: 768px) {
  .destacadas-track {
    --destacadas-visibles: 7;
  }
}

/* Escritorio: 8 fichas a la vista (y hasta 14 en pantallas anchas, por el techo de
   5rem), así los 12 perfiles del tope caben sin deslizar y ninguna tarjeta domina
   la fila. */
@media (min-width: 1024px) {
  .destacadas-track {
    --destacadas-visibles: 8;
  }

  .destacada-nombre {
    font-size: 0.6875rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .destacada-foto,
  .destacada-ficha:hover .destacada-foto {
    transition: none;
    transform: none;
  }

  .destacada-estado--live i {
    animation: none;
  }
}

/* ============================================================================
   CARRUSEL "STORIES / EN LÍNEA" (parte superior del catálogo)
   Scroll horizontal táctil con avatares de borde neón animado. La sección la
   muestra app.js solo cuando hay perfiles con estado En Línea vigente.
   ============================================================================ */
.stories-track {
  display: flex;
  gap: 0.75rem;
  margin: 0;
  /* Aire suficiente para que el HALO del anillo no se recorte arriba ni abajo (`overflow-y: hidden`
     los recortaría con el relleno antiguo de 0.25/0.5rem). Los avatares son visibles al 100%. */
  padding: 0.5rem 0.25rem 0.6rem;
  list-style: none;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-behavior: smooth;
  scroll-snap-type: x proximity;
  /* Misma referencia que el relleno: al asentarse (snap) o al enfocar con teclado, la ficha no queda
     pegada al borde del carril. */
  scroll-padding-left: 0.25rem;
  scroll-padding-right: 0.25rem;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}

.stories-item {
  flex: 0 0 auto;
  width: 4.5rem;
  scroll-snap-align: start;
}

.stories-ficha {
  display: flex;
  width: 100%;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
}

/* Anillo luminoso: gradiente cian→magenta en movimiento continuo. */
.stories-anillo {
  display: block;
  width: 4.5rem;
  height: 4.5rem;
  padding: 2px;
  border-radius: 50%;
  background: linear-gradient(135deg, #00f2fe, #fe019a, #00f2fe);
  background-size: 220% 220%;
  box-shadow: 0 0 12px rgba(0, 242, 254, 0.45), 0 0 22px rgba(254, 1, 154, 0.28);
  animation: stories-glow 3.5s linear infinite;
}

.stories-avatar {
  display: block;
  width: 100%;
  height: 100%;
  border: 2px solid #09090b;
  border-radius: 50%;
  background: #18181b;
  object-fit: cover;
}

.stories-nombre {
  width: 100%;
  overflow: hidden;
  color: #d4d4d8;
  font-size: 0.625rem;
  font-weight: 600;
  line-height: 1.1;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.stories-ficha:hover .stories-avatar,
.stories-ficha:active .stories-avatar {
  filter: brightness(1.1);
}

.stories-ficha:focus-visible .stories-anillo {
  outline: 2px solid #00f2fe;
  outline-offset: 2px;
}

@keyframes stories-glow {
  0% { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .stories-anillo {
    animation: none;
  }
}

/* === BLINDAJE DEL CARRUSEL «EN LÍNEA AHORA» (v124) ==========================================
   ENCARGO: asegurar que ninguna regla global de ocultación (`display: none`) ni de acortamiento por
   clases o posición (tipo `.destacada-item:nth-child(n + 6)`) afecte por error a esta sección.
   AUDITORÍA (marcado + CSS + render):
     · Las fichas se crean como `li.stories-item` (app.js → renderStories) y NUNCA llevan la clase
       `.destacada-item`, así que el recorte a 5 fichas de móvil (v117) no las alcanza.
     · Ninguna otra regla `display: none` del proyecto coincide con sus clases (`.stories-item`,
       `.stories-ficha`, `.stories-anillo`, `.stories-avatar`, `.stories-nombre`).
     · El carril ya es un flex con scroll propio, `list-style: none` y `margin: 0` (sin depender del
       preflight de Tailwind para no mostrar viñetas ni sangría de lista).
   Aun así, se BLINDA para que no pueda ocurrir en el futuro: al incluir el ID en el selector, estas
   declaraciones tienen especificidad 1-1-0 y ganan a cualquier regla de clase —incluida una
   `:nth-child(n + 6)` copiada del carrusel de destacadas— porque el número de IDs se compara antes
   que el de clases. El único mecanismo de ocultación válido sigue siendo `.hidden` en la SECCIÓN
   (lo aplica app.js y ocultar al padre oculta a los hijos), así que este blindaje no estorba. */
#stories-track > .stories-item {
  display: block;
  flex: 0 0 auto;
  width: 4.5rem;
  max-width: none;
}

#stories-track .stories-ficha {
  display: flex;
}

#stories-track .stories-anillo {
  display: block;
  width: 4.5rem;
  height: 4.5rem;
  aspect-ratio: 1 / 1;
}

#stories-track .stories-avatar {
  display: block;
  width: 100%;
  height: 100%;
  /* El avatar nunca se encoge ni se recorta por una regla global de anchos máximos. */
  max-width: none;
  object-fit: cover;
}

/* ============================================================================
   MODAL DE DETALLE DEL PERFIL · GALERÍA UNIFORME (v137)
   La galería `#perfil-galeria` es una rejilla de miniaturas idéntica en todos
   los tamaños: se retiró la regla v129 que agrandaba la primera foto (2×2) en
   escritorio. Cada miniatura abre el visor ampliado (#lightbox-perfil).
   ============================================================================ */
/* Uniformidad forzada: ninguna miniatura puede ocupar más de una celda, en ningún breakpoint. */
#perfil-galeria > [data-galeria-indice] {
  grid-column: auto !important;
  grid-row: auto !important;
  aspect-ratio: 1 / 1;
}

#perfil-galeria > [data-galeria-indice] > img,
#perfil-galeria > [data-galeria-indice] > video {
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

/* ============================================================================
   MODAL DE DETALLE DEL PERFIL · TARJETA ESTRECHA Y CENTRADA (v140)
   El panel queda anclado a **28rem (`max-w-md`) pase lo que pase**: aunque el
   navegador sirviera un HTML anterior o Tailwind no llegara a generar la
   utilidad, la tarjeta se ve como en móvil (flotante, centrada y estrecha) y las
   fotos se leen como MINIATURAS dentro de la rejilla de 3 columnas.
   Espejo en utilidades de `index.html`: `max-w-md` en el panel y
   `grid grid-cols-3` en `#perfil-galeria`.
   ============================================================================ */
#modal-perfil:not(.hidden) {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
}

#modal-perfil > div {
  width: 100% !important;
  max-width: 28rem !important;
  margin-left: auto !important;
  margin-right: auto !important;
}

#modal-perfil #perfil-galeria {
  grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
  gap: .5rem !important;
  max-height: 50vh !important;
}

/* ============================================================================
   PIE DE PÁGINA (v95) — aviso legal, mayoría de edad y créditos
   Cierre discreto y acorde al tema oscuro: tipografía pequeña (12 px), tonos
   neutros apagados, filete superior apenas visible y relleno cómodo para que no
   quede pegado al catálogo. El texto legal va en una sola línea de lectura,
   centrada y con ancho máximo para que no se estire en pantallas anchas.
   Equivalencias Tailwind del diseño (si algún día se migrara a utilidades):
     border-t border-neutral-800 · text-neutral-400 / text-neutral-500 ·
     text-xs · text-center · pt-10 px-4 pb-16 mt-16   (v133: antes py-6 px-4 mt-10)
   ============================================================================ */
.pie-pagina {
  /* v133 · AIRE INFERIOR: el pie quedaba pegado a la barra de tareas de Windows. El relleno inferior
     pasa de 2rem a 4rem y el margen superior de 2.5rem a 4rem, de modo que respira en cualquier
     pantalla (en móvil se le suma además el inset de la barra gestual, v115). */
  margin-top: 4rem;
  padding: 2.5rem 1rem 5rem;      /* v134: 5rem abajo = colchón sólido frente al borde de la pantalla */
  border-top: 1px solid #262626;      /* neutral-800: casi imperceptible sobre #09090B */
  color: #a3a3a3;                     /* neutral-400 */
  font-size: 0.75rem;                 /* text-xs */
  line-height: 1.6;
  text-align: center;
}

.pie-pagina p {
  max-width: 46rem;
  margin: 0 auto;
}

/* En pantallas grandes se apaga un punto más (neutral-500): es acompañamiento,
   nunca protagonista. En móvil se queda en neutral-400 para que siga legible. */
@media (min-width: 768px) {
  .pie-pagina {
    color: #737373;                   /* neutral-500 */
  }
}

/* ============================================================================
   v162 · CONSENTIMIENTO INFORMADO Y CENTRO DE CONFIANZA (Ley 21.719)
   ----------------------------------------------------------------------------
   Aviso PREVIO y no descartable: nada viene premarcado; el visitante decide (todo,
   sólo lo esencial o preferencias a medida). Se declara aquí —y no con utilidades—
   porque el MISMO panel se abre desde `index.html` y desde `confianza.html`, y esta
   hoja la cargan ambas vistas.
   z-index 260: por encima del catálogo, los banners (45), los modales (70-95) y la
   salida rápida (100), y por debajo de los avisos efímeros de `showToast` (300).
   ============================================================================ */
.consentimiento-velo {
  position: fixed;
  inset: 0;
  z-index: 260;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0.75rem;
  background: rgba(9, 9, 11, 0.86);
  backdrop-filter: blur(6px);
  overflow-y: auto;
}

.consentimiento-panel {
  width: 100%;
  max-width: 44rem;
  max-height: 92vh;
  overflow-y: auto;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 1.25rem;
  background: #131317;
  padding: 1.25rem;
  color: #e4e4e7;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.65);
}

.consentimiento-marca {
  margin: 0;
  font-size: 0.625rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #67e8f9;
}

.consentimiento-titulo {
  margin: 0.35rem 0 0;
  font-size: 1.15rem;
  font-weight: 700;
  color: #fff;
}

.consentimiento-texto {
  margin: 0.5rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: #a1a1aa;
}

.consentimiento-grupo {
  margin: 1rem 0 0;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 1rem;
  padding: 0.75rem 0.9rem 1rem;
}

.consentimiento-leyenda {
  padding: 0 0.35rem;
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #71717a;
}

.consentimiento-fila {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.5rem 0.25rem;
  border-radius: 0.75rem;
  cursor: pointer;
}

.consentimiento-fila:hover {
  background: rgba(255, 255, 255, 0.03);
}

.consentimiento-casilla {
  flex-shrink: 0;
  margin-top: 0.2rem;
  width: 1.05rem;
  height: 1.05rem;
  accent-color: #22d3ee;
}

.consentimiento-fila-titulo {
  display: block;
  font-size: 0.8125rem;
  color: #f4f4f5;
}

.consentimiento-fila-texto {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.75rem;
  line-height: 1.5;
  color: #a1a1aa;
}

.consentimiento-error {
  margin: 0.75rem 0 0;
  border: 1px solid rgba(251, 113, 133, 0.4);
  border-radius: 0.75rem;
  background: rgba(244, 63, 94, 0.12);
  padding: 0.6rem 0.75rem;
  font-size: 0.75rem;
  line-height: 1.5;
  color: #fda4af;
}

.consentimiento-acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1rem;
}

.consentimiento-boton {
  border: 1px solid rgba(34, 211, 238, 0.45);
  border-radius: 0.75rem;
  background: rgba(34, 211, 238, 0.14);
  padding: 0.55rem 1rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: #67e8f9;
  cursor: pointer;
}

.consentimiento-boton:hover {
  background: rgba(34, 211, 238, 0.24);
}

.consentimiento-boton-secundario {
  border-color: rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.05);
  color: #d4d4d8;
}

.consentimiento-enlace {
  border: 0;
  background: none;
  padding: 0.35rem 0.25rem;
  font-size: 0.75rem;
  color: #67e8f9;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

.consentimiento-letra {
  margin: 0.9rem 0 0;
  font-size: 0.6875rem;
  line-height: 1.5;
  color: #71717a;
}

.consentimiento-letra a {
  color: #a5f3fc;
}

@media (min-width: 640px) {
  .consentimiento-velo {
    align-items: center;
  }
  .consentimiento-panel {
    padding: 1.5rem;
  }
}

/* PIE DE PÁGINA · enlace permanente al Centro de Confianza (v162). Discreto: mismo tono
   apagado del pie, sólo con el subrayado de un enlace informativo. */
.pie-confianza {
  margin-top: 0.75rem;
}

.pie-confianza-enlace {
  color: #67e8f9;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.pie-confianza-enlace:hover {
  color: #a5f3fc;
}

/* ============================================================================
   v163 · MARKETPLACE DISCOVERY — resumen y chips de filtros activos
   ----------------------------------------------------------------------------
   La fila de chips es la «memoria visible» del buscador: cada filtro activo
   (comuna, barrio, servicio, franja, confianza, tarifa o texto) aparece con su
   «✕» para quitarlo de un toque, sin abrir su panel. Las filas de los selectores
   dinámicos reutilizan `.comuna-row`, así que heredan el aspecto del filtro de
   comunas y no hay un segundo lenguaje visual que mantener.
   ============================================================================ */
.filtros-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
}

.chip-filtro {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  max-width: 100%;
  border: 1px solid rgba(236, 72, 153, 0.45);
  border-radius: 9999px;
  background: rgba(236, 72, 153, 0.12);
  padding: 0.2rem 0.55rem;
  font-size: 0.6875rem;
  font-weight: 500;
  color: #f9a8d4;
  cursor: pointer;
}

.chip-filtro:hover {
  background: rgba(236, 72, 153, 0.22);
}

.chip-filtro span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chip-filtro-x {
  font-size: 0.625rem;
  opacity: 0.75;
}

@media (min-width: 640px) {
  #catalog-resumen {
    flex: 1 1 12rem;
  }
}

/* ============================================================================
   v164 · PERFIL 2.0 — VERIFICACIÓN EN DOS SELLOS Y REPUTACIÓN MULTIDIMENSIONAL
   ----------------------------------------------------------------------------
   · .verificacion-* : lista de sellos de la ficha (identidad y huellas de medios).
     El color comunica el estado sin depender del color: cada fila lleva su
     propio icono y su texto («Identidad verificada», «Medios repetidos»…).
   · .reputacion-*   : una barra por eje (puntualidad, veracidad, higiene y
     trato) con el promedio sobre 5. El relleno cambia de tono según el nivel
     (alta ≥4,5 · media ≥3,5 · baja por debajo) y la etiqueta y el valor son
     texto real, no una imagen: la ficha se entiende también con lector de
     pantalla y con la barra al 0 %.
   Nota: el mismo bloque se pinta dentro del modal de la portada, que ya carga
   Tailwind; estos nombres existen para que el bloque no dependa de utilidades
   ad hoc y para poder ajustarlo desde aquí sin tocar el marcado.
   ============================================================================ */
.verificacion-lista {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.verificacion-item {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 0.75rem;
  padding: 0.4rem 0.5rem;
  background: rgba(255, 255, 255, 0.03);
}

.verificacion-item--ok {
  border-color: rgba(52, 211, 153, 0.35);
  background: rgba(16, 185, 129, 0.10);
}

.verificacion-item--alerta {
  border-color: rgba(251, 191, 36, 0.40);
  background: rgba(245, 158, 11, 0.12);
}

.verificacion-item--pendiente,
.verificacion-item--neutro {
  border-color: rgba(255, 255, 255, 0.10);
}

.verificacion-icono {
  font-size: 0.8125rem;
  line-height: 1.2;
}

.verificacion-texto {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
  font-size: 0.6875rem;
  line-height: 1.35;
  color: #a1a1aa;
}

.verificacion-texto strong {
  color: #f4f4f5;
  font-size: 0.75rem;
}

.reputacion-fila {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr) 2.75rem;
  align-items: center;
  gap: 0.4rem;
}

.reputacion-etiqueta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.6875rem;
  color: #d4d4d8;
}

.reputacion-barra {
  display: block;
  height: 0.4rem;
  border-radius: 9999px;
  background: rgba(255, 255, 255, 0.10);
  overflow: hidden;
}

.reputacion-relleno {
  display: block;
  height: 100%;
  border-radius: 9999px;
  background: #34d399;
  transition: width 0.25s ease-out;
}

.reputacion-relleno--alta {
  background: #34d399;
}

.reputacion-relleno--media {
  background: #fbbf24;
}

.reputacion-relleno--baja {
  background: #fb7185;
}

.reputacion-valor {
  text-align: right;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.625rem;
  color: #67e8f9;
}

@media (max-width: 380px) {
  .reputacion-fila {
    grid-template-columns: 6.5rem minmax(0, 1fr) 2.5rem;
  }
}

/* ============================================================================
   v165 · MI PRIVÉ — RETENCIÓN Y ENGAGEMENT
   ----------------------------------------------------------------------------
   Bloque con tres pestañas (Favoritos · Vistos · Novedades), el interruptor de
   alertas y el comparador. Se declara aquí —y no con utilidades sueltas— porque
   el mismo marcado convive con Tailwind del CDN en la portada: así el bloque
   tiene un solo aspecto y se ajusta sin tocar el HTML.
   Grilla fluida: 2 columnas en móvil, 3 en tablet y 4 en escritorio; las
   mini-fichas usan el mismo lenguaje visual que las tarjetas del catálogo.
   ============================================================================ */
.mi-prive-cabecera {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

.mi-prive-titulo {
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #f4f4f5;
}

.mi-prive-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.mi-prive-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 9999px;
  background: rgba(255, 255, 255, 0.05);
  padding: 0.25rem 0.7rem;
  font-size: 0.6875rem;
  font-weight: 500;
  color: #d4d4d8;
  cursor: pointer;
}

.mi-prive-tab:hover {
  background: rgba(255, 255, 255, 0.10);
}

.mi-prive-tab.is-active {
  border-color: rgba(236, 72, 153, 0.45);
  background: rgba(236, 72, 153, 0.12);
  color: #f9a8d4;
}

.mi-prive-contador {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.625rem;
  opacity: 0.85;
}

.mi-prive-grilla {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem;
}

@media (min-width: 768px) {
  .mi-prive-grilla {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .mi-prive-grilla {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.mi-prive-vacio {
  margin: 0.5rem 0 0;
  font-size: 0.75rem;
  color: #71717a;
}

.mi-prive-ficha {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 0.85rem;
  background: rgba(255, 255, 255, 0.03);
}

.mi-prive-media {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  width: 100%;
  background: #18181b;
  cursor: pointer;
}

.mi-prive-imagen {
  height: 100%;
  width: 100%;
  object-fit: cover;
}

.mi-prive-precio {
  position: absolute;
  right: 0.35rem;
  bottom: 0.35rem;
  border-radius: 9999px;
  background: rgba(0, 0, 0, 0.65);
  padding: 0.1rem 0.45rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.625rem;
  color: #67e8f9;
}

.mi-prive-datos {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: 0.4rem 0.5rem 0;
}

.mi-prive-nombre {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.75rem;
  font-weight: 700;
  color: #f4f4f5;
}

.mi-prive-comuna {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.625rem;
  color: #a1a1aa;
}

.mi-prive-ficha-acciones {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.4rem 0.5rem 0.5rem;
}

.mi-prive-mini {
  border: 1px solid rgba(34, 211, 238, 0.35);
  border-radius: 0.6rem;
  background: rgba(34, 211, 238, 0.10);
  padding: 0.2rem 0.45rem;
  font-size: 0.625rem;
  font-weight: 600;
  color: #67e8f9;
  cursor: pointer;
}

.mi-prive-mini[aria-pressed="true"] {
  border-color: rgba(236, 72, 153, 0.5);
  background: rgba(236, 72, 153, 0.16);
  color: #f9a8d4;
}

.mi-prive-mini--quitar {
  margin-left: auto;
  border-color: rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.05);
  color: #a1a1aa;
}

.mi-prive-acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.6rem;
}

.mi-prive-boton {
  border: 1px solid rgba(34, 211, 238, 0.45);
  border-radius: 0.75rem;
  background: rgba(34, 211, 238, 0.12);
  padding: 0.35rem 0.75rem;
  font-size: 0.6875rem;
  font-weight: 600;
  color: #67e8f9;
  cursor: pointer;
}

.mi-prive-boton:disabled {
  cursor: not-allowed;
  opacity: 0.45;
}

.mi-prive-enlace {
  border: 0;
  background: none;
  padding: 0.25rem;
  font-size: 0.6875rem;
  color: #67e8f9;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

.mi-prive-aviso {
  flex: 1 1 14rem;
  margin: 0;
  font-size: 0.6875rem;
  line-height: 1.4;
  color: #a1a1aa;
}

.mi-prive-comparador {
  margin-top: 0.6rem;
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 0.85rem;
  background: rgba(255, 255, 255, 0.03);
  padding: 0.55rem 0.7rem;
}

.mi-prive-subtitulo {
  margin: 0;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #d4d4d8;
}

.mi-prive-seleccion {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.4rem;
}

/* --- COMPARADOR: tabla desplazable con la columna de etiquetas fija ------- */
.comparador-scroll {
  overscroll-behavior-x: contain;
}

.comparador-tabla {
  width: 100%;
  min-width: 32rem;
  border-collapse: collapse;
  font-size: 0.6875rem;
}

.comparador-etiqueta {
  position: sticky;
  left: 0;
  z-index: 1;
  background: #131317;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  padding: 0.4rem 0.5rem;
  text-align: left;
  font-weight: 600;
  white-space: nowrap;
  color: #a1a1aa;
}

.comparador-cabecera {
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  padding: 0.4rem 0.5rem;
  min-width: 9rem;
  vertical-align: top;
  text-align: left;
}

.comparador-nombre {
  display: block;
  font-size: 0.75rem;
  font-weight: 700;
  color: #f4f4f5;
}

.comparador-sub {
  display: block;
  margin-top: 0.1rem;
  font-size: 0.625rem;
  color: #a1a1aa;
}

.comparador-valor {
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  padding: 0.4rem 0.5rem;
  vertical-align: top;
  line-height: 1.35;
  color: #d4d4d8;
}

/* ============================================================================
   v167 · LANDINGS TERRITORIALES (SEO) — comunas.php
   ----------------------------------------------------------------------------
   Aspecto de las páginas de aterrizaje por comuna. Viven aquí (y no en estilos
   ad hoc de la plantilla) porque `comunas.php` SÍ enlaza `styles.css`, a
   diferencia de los paneles privados.
   v172 · MISMA LÍNEA VISUAL QUE LA PORTADA: la landing reutiliza el lenguaje de
   componentes del portal en vez de inventar uno propio.
     · Ancho de caja: `max-width: 80rem`, el MISMO `max-w-7xl` del `#app-shell`
       de `index.html` (antes 64rem: por eso la landing se veía más estrecha).
     · Tarjetas (`.landing-ficha`) y bloques de texto (`.landing-faq`): mismo
       borde `rgba(255,255,255,.08)`, mismo radio `1rem`, mismo panel
       `linear-gradient(158deg, #14141a 0%, #0c0c10 100%)`, misma sombra
       `0 10px 26px rgba(0,0,0,.35)` y MISMO realce carmesí al pasar el ratón
       (`rgba(248,113,113,.7)` + `translateY(-2px)`) que `.noticia-tarjeta` y
       `.tarjeta-contacto-host` (v91-v92).
     · Pastillas de sector: los valores de `.mi-prive-tab`; enlaces del silo de
       comunas: `.chip-filtro` del portal; botones: `.mi-prive-boton`, aplicados
       también en el marcado de `comunas.php`.
     · Títulos de sección: el mismo tratamiento que `.mi-prive-titulo`
       (mayúsculas, `letter-spacing`, `#f4f4f5`) y texto en los neutros del
       portal (`#d4d4d8`, `#a1a1aa`, `#71717a`).
   Reglas de la casa: nada de `width: 100vw`, nada de márgenes negativos y todo
   contenedor puede encogerse (`min-width: 0`), así que el desbordamiento
   horizontal sigue siendo imposible también en estas vistas.
   ============================================================================ */
.landing-cabecera {
  position: sticky;
  top: 0;
  z-index: 1000;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  background: rgba(9, 9, 11, 0.92);
  backdrop-filter: blur(10px);
}

.landing-cabecera-fila {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  max-width: 80rem;            /* v172: mismo ancho de caja que `max-w-7xl` */
  margin: 0 auto;
  padding: 0.625rem 0.75rem;
}

@media (min-width: 640px) {
  .landing-cabecera-fila {
    padding: 0.625rem 1rem;
  }
}

.landing-marca {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
}

.landing-logo {
  height: 2.25rem;
  width: auto;
  object-fit: contain;
}

.landing-marca-texto {
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #fff;
}

/* El botón de la cabecera toma su aspecto de `.mi-prive-boton` (marcado con las dos clases);
   aquí sólo queda lo que es específico de la landing. */
.landing-cta {
  white-space: nowrap;
}

.landing-main {
  max-width: 80rem;            /* v172: el ancho del catálogo, no una columna aparte */
  margin: 0 auto;
  padding: 0.75rem 0.75rem 0;
  min-width: 0;
}

.landing-migas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.6875rem;
  color: #a1a1aa;
}

.landing-migas a {
  color: #67e8f9;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.landing-ceja {
  margin: 0.9rem 0 0;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #67e8f9;
}

.landing-titulo {
  margin: 0.35rem 0 0;
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: #fff;
}

@media (min-width: 768px) {
  .landing-titulo {
    font-size: 1.85rem;
  }
}

.landing-intro {
  margin: 0.75rem 0 0;
  max-width: 52rem;
  font-size: 0.875rem;
  line-height: 1.65;
  color: #d4d4d8;
}

.landing-aviso {
  margin: 1rem 0 0;
  border: 1px solid rgba(251, 191, 36, 0.4);
  border-radius: 0.85rem;
  background: rgba(245, 158, 11, 0.12);
  padding: 0.6rem 0.8rem;
  font-size: 0.8125rem;
  color: #fcd34d;
}

.landing-bloque {
  margin-top: 1.75rem;
  min-width: 0;
}

/* Títulos de sección: MISMO tratamiento que `.mi-prive-titulo` del portal
   (micro-título en mayúsculas con `letter-spacing`), para que la landing respire igual. */
.landing-subtitulo {
  margin: 0;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #f4f4f5;
}

.landing-texto {
  margin: 0.5rem 0 0;
  max-width: 52rem;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: #a1a1aa;
}

.landing-texto a,
.landing-aviso a,
.landing-legal a {
  color: #67e8f9;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.landing-pildoras {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.6rem 0 0;
  padding: 0;
  list-style: none;
}

/* Pastillas de sector: EXACTAMENTE los valores de `.mi-prive-tab` del portal. */
.landing-pildora {
  display: inline-flex;
  align-items: center;
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 9999px;
  background: rgba(255, 255, 255, 0.05);
  padding: 0.25rem 0.7rem;
  font-size: 0.6875rem;
  font-weight: 500;
  color: #d4d4d8;
}

/* Grilla de tarjetas: mismo ritmo que `.mi-prive-grilla` / `#noticias-seccion .noticias-grilla`. */
.landing-grilla {
  display: grid;
  grid-template-columns: repeat(1, minmax(0, 1fr));
  gap: 0.875rem;
  margin: 0.75rem 0 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 640px) {
  .landing-grilla {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .landing-grilla {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* Tarjeta de perfil: MISMA receta que `.noticia-tarjeta` / `.tarjeta-contacto-host` del portal
   (borde `rgba(255,255,255,.08)`, radio `1rem`, panel degradado, sombra y realce carmesí). */
.landing-ficha {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-width: 0;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 1rem;
  background: linear-gradient(158deg, #14141a 0%, #0c0c10 100%);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.35);
  padding: 1rem 1rem 0.85rem;
  transition: border-color 180ms ease, box-shadow 200ms ease, transform 200ms ease;
}

.landing-ficha:hover,
.landing-ficha:focus-within {
  border-color: rgba(248, 113, 113, 0.7);
  transform: translateY(-2px);
  box-shadow: 0 0 14px -2px rgba(225, 29, 72, 0.55), 0 20px 40px -26px rgba(0, 0, 0, 0.95);
}

.landing-ficha-nombre {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.35;
  color: #f4f4f5;
}

.landing-ficha-datos {
  margin: 0;
  font-size: 0.6875rem;
  color: #a1a1aa;
}

.landing-ficha-texto {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.62);
}

.landing-ficha-acciones {
  margin-top: auto;
  padding-top: 0.5rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 0.6875rem;
}

/* El enlace conserva el subrayado cian SÓLO cuando no lleva el botón del portal. */
.landing-ficha-acciones a:not(.mi-prive-boton) {
  color: #67e8f9;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Silo de comunas: cada enlace es un `.chip-filtro` del portal (clase aplicada también en el
   marcado de `comunas.php`); el estilo de abajo es sólo el respaldo sin la clase. */
.landing-enlaces {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.75rem 0 0;
  padding: 0;
  list-style: none;
}

.landing-enlaces a:not(.chip-filtro) {
  font-size: 0.8125rem;
  color: #67e8f9;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Preguntas frecuentes: el MISMO panel de tarjeta del portal, con el punto cian del portal
   (`.noticia-categoria::before`) delante de cada pregunta. */
.landing-faq {
  margin: 0.75rem 0 0;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 1rem;
  background: linear-gradient(158deg, #14141a 0%, #0c0c10 100%);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.35);
  padding: 0.25rem 1rem 1rem;
}

.landing-faq dt {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.85rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: #f4f4f5;
}

.landing-faq dt::before {
  content: '';
  flex: 0 0 auto;
  width: 0.35rem;
  height: 0.35rem;
  border-radius: 999px;
  background: #67e8f9;
  box-shadow: 0 0 8px rgba(34, 211, 238, 0.35);
}

.landing-faq dd {
  margin: 0.25rem 0 0 0.75rem;
  max-width: 52rem;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: #a1a1aa;
}

/* Cierre legal con los MISMOS tokens del pie del portal (`.pie-pagina`). */
.landing-legal {
  margin: 2rem 0 0;
  border-top: 1px solid #262626;
  padding-top: 1rem;
  font-size: 0.75rem;
  line-height: 1.6;
  color: #a3a3a3;
}

/* PIE · enlaces territoriales de la portada (v167): misma línea discreta del pie. */
.pie-territorios {
  margin-top: 0.35rem;
}

/* === BLINDAJE ANTI-DESBORDAMIENTO HORIZONTAL (v121) ==========================================
   BÚSQUEDA CIEGA de los causantes clásicos del desplazamiento lateral en móvil, revisando TODOS
   los archivos de interfaz (styles.css, index.html, app.js, contacto.js, perfil_escort.html,
   panel_maestro.html). Resultado de la auditoría:
     · `width: 100vw` ........................ 0 usos (unidad prohibida; el arnés móvil la vigila).
     · márgenes negativos horizontales ........ 1 uso: `#filtros-strip` con `-mx-3`; SUSTITUIDO por el
       relleno estándar del contenedor padre (`div.px-3`) y limitado con `max-w-full` (v121).
     · posicionamientos negativos (`-left-*`) . sólo el contador de notificaciones (`-right-0.5` = 2 px),
       dentro del propio botón y sin salir de la barra.
     · anchos grandes (`min-w-[640px]`, `w-[90%]`, `w-64`) .. siempre dentro de un carril con
       `overflow-x-auto` o con `max-width` propio (menús desplegables).
   RED DE SEGURIDAD: para que ninguna pieza futura pueda volver a desbordar, todo contenedor de
   rejilla/flex del shell puede ENCOGER (`min-width: 0`, porque el valor por defecto `min-width: auto`
   es la causa nº 1 de desbordamiento en flex/grid) y nunca supera a su padre (`max-width: 100%`). */
#app-shell main,
#app-shell section,
#app-shell aside,
#app-shell article,
#app-shell header,
#app-shell nav,
#app-shell form,
#app-shell ul,
#app-shell .grid,
#app-shell [class*='grid-cols-'],
#app-shell .flex,
#app-shell [class*='flex-'],
#app-shell [class*='overflow-x'],
#app-shell .destacadas-track,
#app-shell .stories-track {
  min-width: 0;
  max-width: 100%;
}

/* EXCEPCIÓN NECESARIA: el contenido de un carril con scroll SÍ debe poder ser más ancho que el
   carril (es justo lo que lo hace desplazable: fichas, píldoras de filtro, tablas del panel). Si se
   recortara a lo ancho, el carril dejaría de deslizarse. */
#app-shell [class*='overflow-x'] > *,
#app-shell .destacadas-track > *,
#app-shell .stories-track > * {
  max-width: none;
}

/* ============================================================================
   DISEÑO CENTRADO (BOXED) EN ESCRITORIO (v144)
   En monitores anchos (≥1280px, el mismo corte en el que ya manda `max-w-7xl`) el
   portal completo —barra, contenido y pie— se encaja en **80rem** con márgenes
   laterales automáticos: deja de verse estirado de borde a borde.
   SIN bordes, SIN sombra y SIN fondo propio (v145): el contenedor se funde de
   manera invisible con el fondo general del sitio, de modo que no aparecen líneas
   a los costados ni cortes horizontales arriba/abajo, y cabecera y pie fluyen
   continuos (sus propios estilos quedan intactos, sin filetes añadidos).
   Móvil y tablet NO cambian: la regla vive dentro del media query, así que por
   debajo de 1280px el shell sigue con ancho completo (`width/max-width: 100%`,
   v118) y sin marcos.
   La barra acompaña el MISMO ancho: en modo *desplazable* (`sticky`) ya se recorta
   con el shell; en modo *fija* (`position: fixed` + `left/right: 0`) se le repite
   el tope y los márgenes automáticos para quedar centrada con el contenido.
   ============================================================================ */
@media (min-width: 1280px) {
  #app-shell {
    width: 100%;
    max-width: 80rem;
    margin-left: auto;
    margin-right: auto;
  }

  html[data-barra='fija'] #app-shell > header {
    max-width: 80rem;
    margin-left: auto;
    margin-right: auto;
  }
}


/* ============================================================================
   NOTICIAS (v151) — TARJETAS MODERNAS DE LA PORTADA
   ----------------------------------------------------------------------------
   El administrador publica los avisos en el Panel Maestro (backend/noticias.php)
   y `app.js` → `cargarNoticias()` los pinta en `#noticias-lista` con esta forma:

     <article class="noticia-tarjeta">
       <p   class="noticia-categoria">…</p>   · cabecera de categoría pequeña, dorada
       <h3  class="noticia-titulo">…</h3>     · titular destacado
       <p   class="noticia-extracto">…</p>    · extracto de 3 líneas (desplegable)
       <div class="noticia-pie">…</div>       · «Leer más…» + fecha con icono
     </article>

   Los selectores van prefijados con `#noticias-seccion` para GANAR en la cascada a
   las utilidades de Tailwind (que se inyectan después de esta hoja, ver §1.2 de la
   bitácora) y el dorado `--noticias-oro` se suma a la paleta oscura del portal.
   ============================================================================ */
#noticias-seccion {
  --noticias-oro: #d8b061;
  --noticias-oro-suave: rgba(216, 176, 97, 0.22);
  --noticias-borde: rgba(255, 255, 255, 0.08);
  --noticias-panel: linear-gradient(158deg, #14141a 0%, #0c0c10 100%);
}

/* La ocultación es siempre de la propia hoja (`.hidden` de styles.css) y esta regla la refuerza con
   la especificidad del id SIN `!important`; así el arnés móvil sigue exigiendo que no haya abusos. */
#noticias-seccion.hidden {
  display: none;
}

#noticias-seccion .noticias-cabecera {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}

#noticias-seccion .noticias-titulo-seccion {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--noticias-oro);
}

/* (v153) La línea divisoria de la cabecera se retiró: el título dorado queda solo. */

/* Grilla: 1 columna en móvil (se apilan), 2 en tablet, 3 idénticas en escritorio. */
#noticias-seccion .noticias-grilla {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.875rem;
}

@media (min-width: 640px) {
  #noticias-seccion .noticias-grilla {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  #noticias-seccion .noticias-grilla {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

#noticias-seccion .noticia-tarjeta {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1rem 1rem 0.85rem;
  /* Mismo borde y misma transición que las tarjetas de perfiles (`.tarjeta-contacto-host`). */
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 1rem;
  background: var(--noticias-panel);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.35);
  transition: border-color 180ms ease, box-shadow 200ms ease, transform 200ms ease;
}

/* (v154) Se retiró el filete dorado superior de la tarjeta (`::before`): el recuadro ya no
   lleva ninguna línea de color en su interior ni justo encima. */

/* Resplandor rojizo/rosado IDÉNTICO al de las tarjetas de perfiles (v92): mismo borde
   `rgba(248, 113, 113, .7)` y misma sombra carmesí que `.tarjeta-contacto-host:hover`. */
#noticias-seccion .noticia-tarjeta:hover,
#noticias-seccion .noticia-tarjeta:focus-within {
  border-color: rgba(248, 113, 113, 0.7);
  transform: translateY(-2px);
  box-shadow: 0 0 14px -2px rgba(225, 29, 72, 0.55), 0 20px 40px -26px rgba(0, 0, 0, 0.95);
}

#noticias-seccion .noticia-categoria {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--noticias-oro);
}

#noticias-seccion .noticia-categoria::before {
  content: '';
  width: 0.35rem;
  height: 0.35rem;
  border-radius: 999px;
  background: var(--noticias-oro);
  box-shadow: 0 0 8px var(--noticias-oro-suave);
}

#noticias-seccion .noticia-titulo {
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.35;
  color: #f4f4f5;
}

#noticias-seccion .noticia-extracto {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.62);
  white-space: pre-line;
}

/* La tarjeta ENTERA abre el popup (v152): el cursor y el realce lo anuncian. */
#noticias-seccion .noticia-tarjeta {
  cursor: pointer;
}

#noticias-seccion .noticia-pie {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--noticias-borde);
}

#noticias-seccion .noticia-leer {
  padding: 0;
  border: 0;
  background: none;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--noticias-oro);
  cursor: pointer;
  transition: color 0.2s ease;
}

#noticias-seccion .noticia-leer:hover {
  color: #f0d9a4;
}

/* «Leer más…» (v152) abre el popup igual que el resto de la tarjeta: sin estados intermedios. */
#noticias-seccion .noticia-leer:focus-visible {
  outline: 1px solid var(--noticias-oro);
  outline-offset: 2px;
}

/* La fecha y su icono se comparten con el popup de la noticia completa (v152). */
#noticias-seccion .noticia-fecha,
#modal-noticia .noticia-fecha {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.6875rem;
  color: rgba(255, 255, 255, 0.45);
}

#noticias-seccion .noticia-fecha svg,
#modal-noticia .noticia-fecha svg {
  width: 0.85rem;
  height: 0.85rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ============================================================================
   NOTICIA COMPLETA (v152) — POPUP DE LA SECCIÓN «NOTICIAS»
   ----------------------------------------------------------------------------
   Cualquier clic dentro de `.noticia-tarjeta` (o en su botón «Leer más…») llama a
   `abrirNoticia(id)` de app.js, que rellena este panel con el aviso ÍNTEGRO leído
   de `backend/noticias.php`: título, fecha y contenido completo. Se cierra con la
   «✕» (`.cerrar-noticia`), con un clic FUERA del panel o con la tecla Escape.
   Los colores repiten el dorado de la sección (`--noticias-oro`) y el borde/panel
   oscuro del portal (mismo lenguaje que `#modal-perfil`).
   ============================================================================ */
#modal-noticia {
  --noticias-oro: #d8b061;
}

#modal-noticia .noticia-modal-categoria {
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--noticias-oro);
}

/* Una sola noticia NO deforma la grilla: la tarjeta conserva su columna y se alinea
   arriba; con varias, todas las de una fila comparten altura. */
#noticias-seccion .noticias-grilla {
  align-items: stretch;
  align-content: start;
  grid-auto-rows: minmax(0, auto);
}




/* ============================================================================
   v2.06 · WIDGET FLOTANTE DE PERFILES VIP (esquina inferior derecha) — index.html → `#vip-fila`
   ----------------------------------------------------------------------------
   Era la fila VIP a lo ancho del marco del catálogo (v2.05); ahora es un widget COMPACTO y CERRABLE
   anclado a la esquina inferior derecha. Los perfiles siguen siendo los mismos: impulso `vip_boost`
   con membresía VIGENTE (regla centralizada de la Fase 2.01: `active` y `expiring_soon` cuentan,
   `expired` no) y la MISMA tarjeta del catálogo (`.tarjeta-contacto-host`) con el resplandor
   cian/carmesí de la casa; la etiqueta «🔥 Promo Especial» se dibuja con `::before` para que la
   plantilla de la tarjeta siga siendo ÚNICA.
   El widget vive FUERA de `#app-shell` (el shell lleva `transform: scale(0.8)` en escritorio y un
   contenedor transformado captura los `position: fixed`): así queda pegado al viewport de verdad.
   Nace oculto: `app.js` → renderAnuncios() lo muestra sólo si hay perfiles VIP y la cuenta no lo
   cerró. El ancho se mide con `min(...)` y `%` (nunca `100vw`: regla anti-desbordamiento de la casa).
   ============================================================================ */
#vip-fila.vip-widget {
  position: fixed;
  right: 0.75rem;
  /* §2.181 · CARRUSEL COMPACTO: el widget deja de estirarse al borde inferior (v2.10) y vuelve a medir
     SÓLO lo que ocupan sus tarjetas (alto automático, acotado): nunca queda una columna vacía debajo.
     El sobrante de perfiles se resuelve rotando dentro del propio carrusel (app.js, cada 3 s). */
  scroll-behavior: smooth;
  /* v2.08 · Cuelga JUSTO DEBAJO de la barra de navegación (alto real medido por app.js). */
  top: calc(var(--altura-barra, 4rem) + 0.75rem);
  z-index: 60;
  /* v2.07 · Una sola tarjeta de ancho: el widget mide EXACTAMENTE lo que mide una tarjeta VIP. */
  width: min(13rem, calc(100% - 1.5rem));
  /* §2.181 · Alto COMPACTO: se ajusta a las tarjetas activas (alto automático) y sólo se acota para que
     el carrusel nunca desborde la pantalla; las tarjetas que no caben rotan dentro (§2.133). */
  max-height: min(80vh, 54rem);
  /* v2.09 · GLASSMORPHISM: fondo semi-transparente + desenfoque del catálogo que pasa por detrás.
     El scroll vive aquí dentro, así que las tarjetas se desplazan mientras la cabecera queda fija. */
  overflow-y: auto;
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  min-width: 0;
  border: 1px solid rgba(34, 211, 238, 0.35);
  border-radius: 1rem;
  background: rgba(15, 15, 18, 0.75);
  box-shadow: 0 0 16px -6px rgba(225, 29, 72, 0.45), 0 10px 26px rgba(0, 0, 0, 0.45);
  padding: 0;
}

/* Cabecera FIJA del widget: se queda pegada al borde superior del widget mientras las tarjetas VIP
   pasan por debajo (`position: sticky` dentro del propio scroll interno). Más opaca que el cuerpo
   (0.85) para que el texto no pierda legibilidad sobre las tarjetas al desplazarse. */
#vip-fila .vip-widget-header {
  position: sticky;
  top: 0;
  z-index: 2;
  border-radius: 1rem 1rem 0 0;
  border-bottom: 1px solid rgba(34, 211, 238, 0.22);
  background: rgba(15, 15, 18, 0.85);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  padding: 0.6rem 0.75rem;
}

/* El cuerpo del widget (tarjetas VIP) se desplaza bajo la cabecera fija. */
#vip-fila #vip-grid {
  padding: 0.6rem 0.75rem 0.75rem;
}

#vip-fila.vip-widget.hidden {
  display: none;
}

/* «✕» de cierre: aparece SÓLO con cuenta registrada (patrón de la casa, v161) y oculta el widget
   recordando la decisión en `localStorage` por cuenta. */
.vip-widget-cerrar {
  /* v2.09 · Va DENTRO de la cabecera (ya no es absoluta): se alinea a la derecha con `margin-left`. */
  margin-left: auto;
  flex: 0 0 auto;
  z-index: 2;
  display: flex;
  height: 1.5rem;
  width: 1.5rem;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 9999px;
  background: rgba(0, 0, 0, 0.7);
  font-size: 0.6875rem;
  line-height: 1;
  color: rgba(255, 255, 255, 0.8);
  transition: background-color 0.15s ease, color 0.15s ease;
}

.vip-widget-cerrar:hover,
.vip-widget-cerrar:focus-visible {
  background: rgba(0, 0, 0, 0.92);
  color: #fff;
}

.vip-widget-cerrar[hidden] {
  display: none;
}

/* Rejilla del widget: UNA sola columna (el widget mide exactamente una tarjeta VIP). */
#vip-fila #vip-grid {
  display: grid;
  grid-template-columns: repeat(1, minmax(0, 1fr));
  gap: 0.375rem;
}

.vip-fila-cabecera {
  display: flex;
  /* §2.182 · FLEXBOX SIN SOLAPE: antes `nowrap` obligaba a encogerse por debajo del contenido y, en el
     widget de 13 rem, el título y la píldora se solapaban sobre la «✕». Con `wrap` cada pieza conserva
     su tamaño real (el título nunca se estruja) y, si no caben juntas en la misma línea, la píldora de
     la promo baja a su propia línea: nunca se encavalgan. */
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 0.5rem;
  min-width: 0;
}

.vip-fila-titulo {
  margin: 0;
  flex: 1 1 auto;              /* cede espacio si hace falta, pero sin encogerse por debajo del texto */
  min-width: 0;
  font-size: 0.75rem;
  line-height: 1.25;
  font-weight: 600;
  letter-spacing: 0.12em;      /* antes 0.18em: ocupaba de más y empujaba la píldora fuera del widget */
  text-transform: uppercase;
  color: #fda4af;
}

.vip-fila-etiqueta {
  flex: 0 0 auto;              /* la píldora NUNCA se encoge ni se deforma */
  white-space: nowrap;         /* «🔥 Promo Especial» siempre legible en una sola línea */
  border: 1px solid rgba(248, 113, 113, 0.6);
  border-radius: 9999px;
  background: rgba(225, 29, 72, 0.18);
  padding: 0.15rem 0.55rem;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #fda4af;
}

.vip-fila-nota {
  margin: 0.35rem 0 0.6rem;
  font-size: 0.6875rem;
  color: #a1a1aa;
}

/* Resplandor de las tarjetas VIP: borde cian corporativo + halo carmesí (los dos acentos del portal). */
#vip-fila article[data-id] {
  border-color: rgba(34, 211, 238, 0.55);
  box-shadow: 0 0 16px -3px rgba(225, 29, 72, 0.55), 0 0 18px -6px rgba(34, 211, 238, 0.55);
}

#vip-fila article[data-id]:hover,
#vip-fila article[data-id]:focus-within {
  border-color: rgba(248, 113, 113, 0.8);
  box-shadow: 0 0 20px -2px rgba(225, 29, 72, 0.7), 0 0 24px -6px rgba(34, 211, 238, 0.65);
}

/* Etiqueta «🔥 Promo Especial»: se dibuja por CSS, así la plantilla de la tarjeta se mantiene única. */
#vip-fila article[data-id]::before {
  content: '🔥 Promo Especial';
  position: absolute;
  left: 0.3rem;

/* ============================================================================
   v2.06 · ZOOM OUT PERMANENTE DEL 80% EN ESCRITORIO (landing page)
   ----------------------------------------------------------------------------
   QUÉ RESUELVE
   A escala 1.0 la portada de escritorio se siente comprimida en vertical: por el ancho útil
   (hasta `max-w-7xl`) la grilla del catálogo y la Fila VIP caen bajo el pliegue y el visitante
   tiene que hacer scroll para ver la oferta. Al reducir el lienzo al 80 % entra ~25 % más de
   contenido en el MISMO alto de ventana, sin tocar ni un tamaño del diseño.
   CÓMO (v2.09 · escalado por TRANSFORMACIÓN, no por `zoom`)
   `transform: scale(0.8)` sobre `#app-shell`, con `transform-origin: top center` para que el lienzo
   crezca desde el centro hacia abajo. Para que el contenido siga ocupando TODO el ancho (y no quede
   una franja vacía a la derecha), el contenedor se ensancha al 125 % y se recentra desplazándolo
   12,5 % a la izquierda: 125 % × 0,8 = 100 % exacto, el sobrante se reparte por igual a ambos lados y
   no aparece scroll horizontal.
   POR QUÉ `left` Y NO MÁRGENES NEGATIVOS
   El desplazamiento pedido (`margin-left/-right: -12.5 %`) es la regla que el arnés móvil prohíbe de
   forma GLOBAL («NO queda ningún margen negativo horizontal en toda la interfaz», v119/v121). El
   posicionamiento relativo consigue la MISMA geometría —el elemento abarca de −12,5 % a +112,5 % del
   contenedor, igual que con los dos márgenes negativos— sin declarar ni un solo margen negativo.
   POR QUÉ YA NO `zoom`
   `zoom` (v2.06) dependía del motor de Tailwind CDN: al reinyectarse las utilidades el navegador
   reescalaba el contexto y la regla quedaba sin efecto.
   LO QUE SIGUE INTACTO
   No se modifica NINGUNA medida `px`, `rem` o `%` de ningún elemento: sólo se cambia la escala del
   lienzo completo. La base de `#app-shell` (flex column, `min-height: 100vh`, `overflow-x: clip`, sin
   insets laterales y sin márgenes automáticos) se mantiene tal cual.
   NOTA CONOCIDA
   Un contenedor con `transform` se convierte en bloque contenedor de sus descendientes `position:
   fixed`, así que con la barra en modo «fija» (`html[data-barra='fija']`) la cabecera queda anclada al
   lienzo escalado en lugar de al viewport: sigue viéndose arriba, pero deja de acompañar al scroll.
   Es el precio del escalado por transformación pedido; con `zoom` ese efecto no ocurría.
   ============================================================================ */

  bottom: 2.5rem;
  z-index: 25;
  border: 1px solid rgba(248, 113, 113, 0.6);
  border-radius: 9999px;
  background: rgba(9, 9, 11, 0.78);
  padding: 0.1rem 0.45rem;
  font-size: 0.5rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #fda4af;
  backdrop-filter: blur(4px);
  pointer-events: none;
}

/* ============================================================================
   §2.120 · FASE 8 — SELECTOR DE TEMA (☀️/🌙) — MODO CLARO
   ----------------------------------------------------------------------------
   El tema OSCURO es el de SIEMPRE y sigue siendo el estado por defecto: sin la clase
   `theme-light` en `<html>` no se aplica ninguna de estas reglas, así que no hay ninguna
   regresión ni en móvil ni en escritorio.
   Con la clase (la pone `app.js` → aplicarTema(), con la preferencia guardada en
   `localStorage['prive_conce_tema']`) sólo se sustituyen FONDOS, TEXTOS y BORDES:
     · lienzo del portal           → #f8f9fa
     · tarjetas, modales y capas   → #ffffff
     · texto principal / secundario→ #111827 / #4b5563
     · bordes y separadores        → #e5e7eb
   NO se toca ninguna retícula, espaciado, tamaño, sombra, transición ni efecto (ni el vidrio
   esmerilado, ni los halos cian/carmesí, ni el acento carmesí de la casa): son reglas de color
   acotadas por `html.theme-light`, que gana a las utilidades de Tailwind por especificidad.
   ============================================================================ */
html.theme-light {
  color-scheme: light;
}

html.theme-light body,
html.theme-light #app-shell,
html.theme-light #principal-app,
html.theme-light main {
  background: #f8f9fa;
  color: #111827;
}

/* Superficies elevadas: cabecera, tarjetas, modales, panel del perfil y widget VIP. */
html.theme-light #app-shell > header,
html.theme-light #modal-perfil > div,
html.theme-light #login-modal > div,
html.theme-light #vip-fila.vip-widget,
html.theme-light #vip-fila .vip-widget-header,
html.theme-light .perfil-cta-barra,
html.theme-light .tarjeta-contacto-host,
html.theme-light #filtros-strip summary,
html.theme-light .filtros-chips,
html.theme-light .noticia-tarjeta {
  background: #ffffff;
  border-color: #e5e7eb;
  color: #111827;
}

/* Jerarquía de texto. */
html.theme-light .text-white,
html.theme-light .text-zinc-100,
html.theme-light .text-zinc-200,
html.theme-light .text-zinc-300,
html.theme-light .text-gray-300 {
  color: #111827;
}

html.theme-light .text-zinc-400,
html.theme-light .text-zinc-500,
html.theme-light .text-zinc-600,
html.theme-light .text-gray-400 {
  color: #4b5563;
}

/* Bordes y separadores. */
html.theme-light .border-white\/10,
html.theme-light .border-white\/15,
html.theme-light .border-zinc-800,
html.theme-light .border-zinc-900\/60,
html.theme-light .border-neutral-700 {
  border-color: #e5e7eb;
}

/* Fondos de utilidad oscuros que ahora deben ser claros. */
html.theme-light .bg-white\/5,
html.theme-light .bg-zinc-900\/60,
html.theme-light .bg-zinc-950\/40,
html.theme-light .bg-zinc-950\/95,
html.theme-light .bg-black\/40 {
  background-color: #ffffff;
}

/* Botón del selector de tema (mismo tamaño y forma en ambos temas: sólo cambian los colores).
   §2.121 · Además, `touch-action: manipulation` evita el retardo de doble toque y el resalte azul en
   móvil; el botón nunca navega ni envía formularios. */
.theme-toggle {
  display: inline-flex;
  flex: 0 0 auto;
  height: 2rem;
  width: 2rem;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 9999px;
  background: rgba(255, 255, 255, 0.06);
  font-size: 0.875rem;
  line-height: 1;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.theme-toggle:hover {
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.28);
}

.theme-toggle:active {
  transform: scale(0.94);
}

html.theme-light .theme-toggle {
  border-color: #e5e7eb;
  background: #ffffff;
}

/* ============================================================================
   §2.122 · FASE 8.2 — TARJETAS DE NOTICIAS EN MODO CLARO
   ----------------------------------------------------------------------------
   INCIDENCIA: en claro, las tarjetas de noticias conservaban el panel oscuro
   (`--noticias-panel` = degradado #14141a → #0c0c10) y desentonaban contra el fondo `#f8f9fa`.
   CAUSA: el fondo lo fija `#noticias-seccion .noticia-tarjeta` con un ID (1-1-0), que GANA a
   cualquier regla de clase como `html.theme-light .noticia-tarjeta` (0-2-1).
   SOLUCIÓN: redefinir las variables de la sección (y del popup) en el ámbito del tema claro, con
   un selector de ID (`html.theme-light #noticias-seccion` = 1-2-1), de modo que TODAS las reglas
   de noticias hereden los valores claros sin reescribir una por una. El dorado se oscurece un punto
   (#a16207) porque el `#d8b061` original no tiene contraste suficiente sobre blanco.
   El MODO OSCURO queda intacto: sin `theme-light` no se aplica ninguna de estas líneas.
   ============================================================================ */
html.theme-light #noticias-seccion {
  --noticias-panel: #ffffff;
  --noticias-borde: #e5e7eb;
  --noticias-oro: #a16207;
  --noticias-oro-suave: rgba(161, 98, 7, 0.18);
}

html.theme-light #modal-noticia {
  --noticias-oro: #a16207;
}

html.theme-light #noticias-seccion .noticias-titulo-seccion,
html.theme-light #noticias-seccion .noticia-titulo {
  color: #111827;
}

html.theme-light #noticias-seccion .noticia-extracto {
  color: #4b5563;
}

/* Sombra suave de tarjeta clara (la del modo oscuro es un halo negro muy marcado). */
html.theme-light #noticias-seccion .noticia-tarjeta {
  box-shadow: 0 10px 24px -20px rgba(15, 23, 42, 0.28);
}

/* ============================================================================
   §2.176 · TEMAS DINÁMICOS (SKINS) — v233
   ----------------------------------------------------------------------------
   Sistema centralizado de paletas OSCURAS. El administrador elige el tema activo
   en el Panel Maestro (`configuracion_sistema.tema`) y se persiste en el servidor;
   `app.js` (portada), `comunas.php` (landings, ya en el servidor) y las vistas
   legales lo inyectan como `html[data-theme="…"]`. Cada paleta redefine los DESIGN
   TOKENS (superficies + acento) y el resto de la hoja los consume vía `var()`.
   · Paletas: grafito · cobre · zafiro · esmeralda · rubi.
   · Sin `data-theme` se usa el tema por DEFECTO (grafito) declarado en `:root`.
   · Las reglas de aplicación usan `html:not(.theme-light)`: en MODO CLARO manda el
     bloque `theme-light` (§2.120) y ninguna de estas líneas se aplica, así la
     preferencia del visitante sigue intacta.
   · Todas las paletas son OSCURAS: el texto blanco/zinc conserva su contraste.
   ============================================================================ */

/* --- Paleta por defecto · GRAFITO (fondo grafito + acento morado/magenta) ---- */
:root,
html[data-theme='grafito'] {
  --tema-fondo: #0b0d12;
  --tema-fondo-rgb: 11, 13, 18;
  --tema-panel: #14161f;
  --tema-panel-rgb: 20, 22, 31;
  --tema-panel-2: #0f1119;
  --tema-borde: rgba(168, 85, 247, 0.16);
  --tema-acento: #a855f7;
  --tema-acento-rgb: 168, 85, 247;
  --tema-acento-2: #ec4899;
  --tema-acento-2-rgb: 236, 72, 153;
}

/* --- COBRE (fondo carbón + acento cobrizo/bronce) --------------------------- */
html[data-theme='cobre'] {
  --tema-fondo: #0e0c0a;
  --tema-fondo-rgb: 14, 12, 10;
  --tema-panel: #1a1410;
  --tema-panel-rgb: 26, 20, 16;
  --tema-panel-2: #120e0a;
  --tema-borde: rgba(217, 119, 6, 0.20);
  --tema-acento: #d97706;
  --tema-acento-rgb: 217, 119, 6;
  --tema-acento-2: #f59e0b;
  --tema-acento-2-rgb: 245, 158, 11;
}

/* --- ZAFIRO (fondo azul marino + acento azul cian) -------------------------- */
html[data-theme='zafiro'] {
  --tema-fondo: #090d16;
  --tema-fondo-rgb: 9, 13, 22;
  --tema-panel: #0f1725;
  --tema-panel-rgb: 15, 23, 37;
  --tema-panel-2: #0b1120;
  --tema-borde: rgba(56, 189, 248, 0.20);
  --tema-acento: #38bdf8;
  --tema-acento-rgb: 56, 189, 248;
  --tema-acento-2: #06b6d4;
  --tema-acento-2-rgb: 6, 182, 212;
}

/* --- ESMERALDA (fondo gris verdoso + acento esmeralda) ---------------------- */
html[data-theme='esmeralda'] {
  --tema-fondo: #0a100d;
  --tema-fondo-rgb: 10, 16, 13;
  --tema-panel: #0f1814;
  --tema-panel-rgb: 15, 24, 20;
  --tema-panel-2: #0b130f;
  --tema-borde: rgba(16, 185, 129, 0.20);
  --tema-acento: #10b981;
  --tema-acento-rgb: 16, 185, 129;
  --tema-acento-2: #34d399;
  --tema-acento-2-rgb: 52, 211, 153;
}

/* --- RUBÍ (fondo obsidiana + acento rojo rubí) ------------------------------ */
html[data-theme='rubi'] {
  --tema-fondo: #110c0e;
  --tema-fondo-rgb: 17, 12, 14;
  --tema-panel: #1c1417;
  --tema-panel-rgb: 28, 20, 23;
  --tema-panel-2: #130d10;
  --tema-borde: rgba(244, 63, 94, 0.20);
  --tema-acento: #f43f5e;
  --tema-acento-rgb: 244, 63, 94;
  --tema-acento-2: #fb7185;
  --tema-acento-2-rgb: 251, 113, 133;
}

/* --- Superficies globales (fondo, scrollbar, acento de controles) ----------- */
html:not(.theme-light) {
  background-color: var(--tema-fondo);
  scrollbar-color: var(--tema-acento) var(--tema-fondo);
  accent-color: var(--tema-acento);
}

html:not(.theme-light) body {
  background-color: var(--tema-fondo);
}

html:not(.theme-light) ::-webkit-scrollbar {
  background-color: var(--tema-fondo);
}

html:not(.theme-light) ::-webkit-scrollbar-thumb {
  background-color: var(--tema-acento);
}

/* --- Cabecera corporativa: mismo degradado con los tonos del tema ----------- */
html:not(.theme-light) #app-shell > header {
  background: linear-gradient(180deg, rgba(var(--tema-fondo-rgb), 0.97) 0%, rgba(var(--tema-panel-rgb), 0.95) 100%);
  border-bottom-color: var(--tema-borde);
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  html:not(.theme-light) #app-shell > header {
    background: var(--tema-fondo);
  }
}

/* --- Acentos de neón: cian/carmesí → acento del tema ------------------------ */
html:not(.theme-light) .neon-border {
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06), 0 0 18px rgba(var(--tema-acento-rgb), 0.18), 0 0 32px rgba(var(--tema-acento-2-rgb), 0.10);
}

html:not(.theme-light) .neon-text {
  text-shadow: 0 0 12px rgba(var(--tema-acento-rgb), 0.38), 0 0 20px rgba(var(--tema-acento-2-rgb), 0.22);
}

html:not(.theme-light) .neon-glow {
  box-shadow: 0 0 12px rgba(var(--tema-acento-rgb), 0.25), 0 0 24px rgba(var(--tema-acento-2-rgb), 0.18);
}

html:not(.theme-light) .glass-card:hover,
html:not(.theme-light) .glass-card:active {
  box-shadow: 0 0 18px rgba(var(--tema-acento-rgb), 0.22);
}

/* --- Superficies de utilidad: fondo/panel/borde del tema --------------------
   Paralelo al bloque `theme-light` (§2.122), pero para las paletas oscuras: las
   tarjetas y paneles translúcidos (glassmorphism) toman el panel y el borde del
   tema sin tocar retículas ni tamaños. La especificidad (0,2,1) supera a la
   utilidad de Tailwind (0,1,0) y también a las reglas base, de modo que el cambio
   se ve aunque `output.css` se cargue después. */
html:not(.theme-light) .bg-bg { background-color: var(--tema-fondo); }
html:not(.theme-light) .bg-bg\/95 { background-color: rgba(var(--tema-fondo-rgb), 0.95); }
html:not(.theme-light) .bg-panel { background-color: var(--tema-panel); }
html:not(.theme-light) .bg-white\/5,
html:not(.theme-light) .bg-white\/10,
html:not(.theme-light) .bg-zinc-900,
html:not(.theme-light) .bg-zinc-900\/60,
html:not(.theme-light) .bg-zinc-950\/40,
html:not(.theme-light) .bg-zinc-950\/95 {
  background-color: rgba(var(--tema-panel-rgb), 0.72);
}
html:not(.theme-light) .border-white\/5,
html:not(.theme-light) .border-white\/10,
html:not(.theme-light) .border-white\/15,
html:not(.theme-light) .border-zinc-800,
html:not(.theme-light) .border-zinc-900\/60 {
  border-color: var(--tema-borde);
}
html:not(.theme-light) .text-neon { color: var(--tema-acento); }
html:not(.theme-light) .bg-neon { background-color: var(--tema-acento); }

/* --- Superficies principales de la aplicación -------------------------------
   El cambio de paleta debe notarse en TODA la interfaz, no sólo en los acentos:
   el lienzo (`#app-shell`/`#principal-app`/`main`) toma el fondo del tema y las
   tarjetas y paneles que hasta ahora llevaban color propio (fijo o translúcido)
   pasan a la superficie del tema. En MODO CLARO nada de esto se aplica. */
html:not(.theme-light) #app-shell,
html:not(.theme-light) #principal-app,
html:not(.theme-light) main {
  background-color: var(--tema-fondo);
}

/* Tarjeta translúcida del portal → panel del tema (tinte evidente). */
html:not(.theme-light) .glass-card {
  background: rgba(var(--tema-panel-rgb), 0.62);
  border-color: var(--tema-borde);
}

/* Tarjetas y bloques con degradado fijo → degradado panel→panel-2 del tema. */
html:not(.theme-light) .destacadas-portada,
html:not(.theme-light) .landing-ficha,
html:not(.theme-light) .landing-faq {
  background: linear-gradient(158deg, var(--tema-panel) 0%, var(--tema-panel-2) 100%);
  border-color: var(--tema-borde);
}

/* Paneles con color fijo → superficie del tema. */
html:not(.theme-light) .consentimiento-panel,
html:not(.theme-light) .comparador-etiqueta {
  background: var(--tema-panel);
  border-color: var(--tema-borde);
}

/* Tarjetas de noticias: la sección fija `--noticias-panel`/`--noticias-borde` con ID
   (1-0-0), así que se redefinen las variables con ID+clase (1-1-1), no el color. */
html:not(.theme-light) #noticias-seccion {
  --noticias-panel: linear-gradient(158deg, var(--tema-panel) 0%, var(--tema-panel-2) 100%);
  --noticias-borde: var(--tema-borde);
}

/* Paneles de los modales oscuros (colores fijos de Tailwind) → superficie del tema. */
html:not(.theme-light) .bg-\[\#131317\],
html:not(.theme-light) .bg-\[\#1a1a1a\],
html:not(.theme-light) .bg-\[\#141414\]\/95 {
  background-color: var(--tema-panel);
}


/* ============================================================================
   §2.183 · WIDGET VIP ALTERNATIVO «ORBITA NEON 3D» (vip-orbita.js)
   ----------------------------------------------------------------------------
   Segundo estilo de banner VIP, COEXISTENTE con el carrusel clasico `#vip-fila`.
   Vive en su propio bloque, con paleta derivada de los tokens de tema
   (`--tema-*`), asi que respeta las cuatro paletas y el tema claro. El marcado
   lo inyecta `vip-orbita.js`; aqui solo hay presentacion.
   ============================================================================ */
/* Cuando el usuario elige la orbita, el cuerpo lleva `vip-estilo-orbita` y el
   carrusel clasico se aparta por completo (regla declarativa: no pelea con la
   logica de `hidden` que aplica `app.js`). */
/* §2.186 · Paleta NEON propia (fucsia/rojo) para el widget VIP en orbita,
   independiente de los acentos de tema, y anclaje que cuelga bajo la barra
   igual que el resto de widgets flotantes. */
body.vip-estilo-orbita #vip-fila.vip-widget {
  display: none;
}

.vip-orbita {
  --vip-neon: 255, 43, 128;        /* fucsia NEON del rediseno */
  --vip-neon-2: 255, 36, 92;       /* rojo NEON perimetral */
  position: fixed;
  /* Mismo anclaje y misma franja que el widget clasico (cuelga bajo la barra). */
  top: calc(var(--altura-barra, 4rem) + 0.75rem);
  right: 0.75rem;
  z-index: 60;
  width: min(18rem, calc(100% - 1.5rem));
  min-width: 0;
  pointer-events: none;
}

.vip-orbita.hidden {
  display: none;
}

.vip-orbita.hidden {
  display: none;
}

.vip-orbita-marco {
  pointer-events: auto;
  position: relative;
  overflow: hidden;
  border: 1px solid rgba(var(--vip-neon), 0.55);
  border-radius: 1.6rem;
  background:
    radial-gradient(130% 80% at 50% -10%, rgba(var(--vip-neon), 0.22), transparent 60%),
    radial-gradient(120% 70% at 50% 118%, rgba(var(--vip-neon-2), 0.2), transparent 62%),
    linear-gradient(158deg, #160a18 0%, #080409 55%, #0d0510 100%);
  box-shadow:
    0 0 22px -4px rgba(var(--vip-neon), 0.75),
    0 0 42px -10px rgba(var(--vip-neon-2), 0.6),
    0 24px 54px rgba(0, 0, 0, 0.65);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

/* Resplandor perimetral difuso: segunda capa recortada como borde degradado. */
.vip-orbita-marco::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(150deg, rgba(var(--vip-neon), 0.85), rgba(var(--vip-neon-2), 0.45) 42%, transparent 72%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
}

.vip-orbita-cabecera {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 0.5rem;
  padding: 0.7rem 0.85rem 0.35rem;
}

.vip-orbita-titulo {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.2;
  color: #fff;
  text-shadow: 0 0 12px rgba(var(--vip-neon), 0.9);
}

.vip-orbita-corona {
  color: rgb(var(--vip-neon));
  filter: drop-shadow(0 0 6px rgba(var(--vip-neon), 0.95));
}

.vip-orbita-subtitulo {
  position: relative;
  z-index: 1;
  margin: 0;
  padding: 0 0.85rem 0.4rem;
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}

.vip-orbita-etiqueta {
  flex: 0 0 auto;
  white-space: nowrap;
  border-radius: 9999px;
  border: 1px solid rgba(var(--vip-neon-2), 0.6);
  background: rgba(var(--vip-neon-2), 0.16);
  padding: 0.15rem 0.5rem;
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #ffd9e4;
}

.vip-orbita-cerrar {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  margin-left: auto;
  display: flex;
  height: 1.5rem;
  width: 1.5rem;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(var(--vip-neon), 0.5);
  border-radius: 9999px;
  background: rgba(0, 0, 0, 0.5);
  font-size: 0.6875rem;
  line-height: 1;
  color: rgba(255, 255, 255, 0.85);
  transition: background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.vip-orbita-cerrar:hover,
.vip-orbita-cerrar:focus-visible {
  background: rgba(var(--vip-neon), 0.9);
  color: #fff;
  box-shadow: 0 0 14px -2px rgba(var(--vip-neon), 0.95);
}

.vip-orbita-escena {
  position: relative;
  height: 24rem;
  margin: 0.2rem 0.5rem 0;
  overflow: hidden;
  perspective: 900px;
  perspective-origin: 50% 50%;
}

.vip-orbita-anillo,
.vip-orbita-halo,
.vip-orbita-nucleo {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
}

/* Anillos de luz inclinados (matriz radial vista en perspectiva 3D). */
.vip-orbita-anillo {
  border-radius: 50%;
  border: 1px solid rgba(var(--vip-neon), 0.3);
  transform: translate(-50%, -50%) rotateX(70deg);
}

.vip-orbita-anillo--exterior {
  width: 17rem;
  height: 17rem;
  box-shadow: 0 0 26px -8px rgba(var(--vip-neon), 0.7), 0 0 22px -8px rgba(var(--vip-neon), 0.6) inset;
}

.vip-orbita-anillo--interior {
  width: 11rem;
  height: 11rem;
  border-style: dashed;
  border-color: rgba(var(--vip-neon-2), 0.45);
  opacity: 0.6;
}

.vip-orbita-halo {
  width: 10rem;
  height: 10rem;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--vip-neon), 0.34), rgba(var(--vip-neon-2), 0.14) 55%, transparent 72%);
  filter: blur(2px);
}

/* Centro de la orbita: ISOTIPO «Prive Conce» con anillo de luz. */
.vip-orbita-nucleo {
  z-index: 5;
  display: flex;
  flex-direction: column;
  height: 6rem;
  width: 6rem;
  align-items: center;
  justify-content: center;
  gap: 0.15rem;
  border-radius: 50%;
  border: 1px solid rgba(var(--vip-neon), 0.75);
  background: radial-gradient(circle at 50% 34%, #1b0818 0%, #060309 78%);
  box-shadow:
    0 0 20px -2px rgba(var(--vip-neon), 0.85),
    0 0 42px -8px rgba(var(--vip-neon-2), 0.6),
    0 0 0 6px rgba(var(--vip-neon), 0.07);
}

.vip-orbita-nucleo-img {
  height: 2.5rem;
  width: 2.5rem;
  object-fit: contain;
  filter: drop-shadow(0 0 8px rgba(var(--vip-neon), 0.95));
}

.vip-orbita-nucleo-marca {
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.16em;
  line-height: 1;
  text-align: center;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 0 10px rgba(var(--vip-neon), 0.9);
}

.vip-orbita-nucleo-marca span {
  display: block;
  margin-top: 0.1rem;
  font-size: 0.48rem;
  letter-spacing: 0.32em;
  color: rgb(var(--vip-neon));
}

/* Nodos (tarjetas VIP): posicion radial, escala, opacidad y desenfoque por
   profundidad los calcula `vip-orbita.js`; aqui solo el aspecto y la transicion. */
.vip-orbita-nodos {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

.vip-orbita-nodo {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 4.8rem;
  aspect-ratio: 3 / 4;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  transform-origin: 50% 50%;
  will-change: transform, opacity, filter;
  transition: transform 0.9s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.9s ease, filter 0.9s ease;
}

.vip-orbita-nodo-marco {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: 1rem;
  border: 1px solid rgba(var(--vip-neon), 0.6);
  background: rgba(10, 4, 10, 0.9);
  box-shadow:
    0 0 14px -2px rgba(var(--vip-neon), 0.7),
    0 0 24px -8px rgba(var(--vip-neon-2), 0.6),
    0 16px 32px rgba(0, 0, 0, 0.62);
  transition: box-shadow 0.3s ease, border-color 0.3s ease;
}

.vip-orbita-nodo--frente .vip-orbita-nodo-marco {
  border-color: rgba(var(--vip-neon), 1);
  box-shadow:
    0 0 20px -1px rgba(var(--vip-neon), 0.95),
    0 0 44px -6px rgba(var(--vip-neon-2), 0.75),
    0 24px 44px rgba(0, 0, 0, 0.72);
}

.vip-orbita-nodo:hover .vip-orbita-nodo-marco,
.vip-orbita-nodo:focus-visible .vip-orbita-nodo-marco {
  border-color: rgba(var(--vip-neon), 1);
}

.vip-orbita-nodo-img {
  display: block;
  height: 100%;
  width: 100%;
  object-fit: cover;
}

.vip-orbita-nodo-info {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  padding: 0.9rem 0.45rem 0.4rem;
  text-align: left;
  background: linear-gradient(to top, rgba(6, 2, 7, 0.96), rgba(6, 2, 7, 0.5) 58%, transparent);
}

.vip-orbita-nodo-nombre {
  display: block;
  font-size: 0.62rem;
  font-weight: 800;
  line-height: 1.15;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.9);
}

.vip-orbita-nodo-meta {
  display: flex;
  align-items: center;
  gap: 0.2rem;
  margin-top: 0.12rem;
  font-size: 0.5rem;
  line-height: 1.2;
  color: rgba(255, 255, 255, 0.78);
}

.vip-orbita-nodo-meta > :last-child {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.vip-orbita-nodo-pin {
  flex: 0 0 auto;
  color: rgb(var(--vip-neon));
}

.vip-orbita-nodo-punto {
  flex: 0 0 auto;
  height: 0.38rem;
  width: 0.38rem;
  border-radius: 9999px;
  background: #34d399;
  box-shadow: 0 0 6px #34d399;
}

.vip-orbita-nodo-punto--off {
  background: #71717a;
  box-shadow: none;
}

.vip-orbita-nodo-ver {
  display: none;
  margin-top: 0.35rem;
  width: 100%;
  border-radius: 9999px;
  border: 1px solid rgba(var(--vip-neon), 0.85);
  background: rgba(var(--vip-neon), 0.18);
  padding: 0.2rem 0;
  text-align: center;
  font-size: 0.48rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #fff;
  box-shadow: 0 0 14px -4px rgba(var(--vip-neon), 0.95);
}

.vip-orbita-nodo--frente .vip-orbita-nodo-ver {
  display: block;
}

/* §2.189 · Transición suave al rotar la cola de perfiles: fade + leve desliz. */
.vip-orbita-nodo--swap .vip-orbita-nodo-marco {
  animation: vip-orbita-swap 0.9s ease;
}

@keyframes vip-orbita-swap {
  0% { opacity: 0; transform: translateY(6px) scale(0.96); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

.vip-orbita-controles {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.4rem 0.85rem 0.7rem;
}

.vip-orbita-control {
  display: flex;
  height: 1.6rem;
  width: 1.6rem;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(var(--vip-neon), 0.5);
  border-radius: 9999px;
  background: rgba(0, 0, 0, 0.45);
  font-size: 0.95rem;
  line-height: 1;
  color: rgb(var(--vip-neon));
  transition: background-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}

.vip-orbita-control:hover,
.vip-orbita-control:focus-visible {
  background: rgba(var(--vip-neon), 0.2);
  transform: scale(1.06);
  box-shadow: 0 0 14px -3px rgba(var(--vip-neon), 0.9);
}

.vip-orbita-pista {
  font-size: 0.58rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
}

/* Tema claro: fondo solido del panel y textos legibles; el nucleo conserva su
   resplandor NEON pero sobre superficie clara. */
html.theme-light .vip-orbita-marco {
  background: linear-gradient(158deg, #ffffff 0%, #f1f5f9 100%);
  border-color: rgba(236, 72, 153, 0.35);
  box-shadow: 0 0 24px -8px rgba(236, 72, 153, 0.6), 0 18px 40px rgba(15, 23, 42, 0.18);
}

html.theme-light .vip-orbita-cabecera {
  border-color: rgba(15, 23, 42, 0.1);
}

html.theme-light .vip-orbita-titulo {
  color: #9d174d;
  text-shadow: none;
}

html.theme-light .vip-orbita-subtitulo {
  color: rgba(15, 23, 42, 0.5);
}

html.theme-light .vip-orbita-pista {
  color: rgba(15, 23, 42, 0.5);
}


