/* src/styles/heading-reveal.css */
/* H2 — estilos de apoyo para el reveal por ScrollTrigger.
   Sólo estiliza los spans que genera src/scripts/heading-reveal.js en producción,
   así que en el editor no cambia nada de lo que se ve. */

.heading-reveal-mask {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  /* padding compensado con margen negativo: la máscara recorta la subida
     pero no los acentos ni los descendentes (á, g, y, j). */
  padding-block: 0.16em;
  margin-block: -0.16em;
  padding-inline: 0.02em;
  margin-inline: -0.02em;
}

.heading-reveal-word {
  display: inline-block;
  color: inherit;
  will-change: transform, opacity;
}

@media (prefers-reduced-motion: reduce) {
  .heading-reveal-word {
    transform: none !important;
    opacity: 1 !important;
  }
}


/* src/styles/hero-title-stagger.css */
/* Hero title — stagger up con GSAP.
   Este archivo sólo aporta los estilos base: máscaras por palabra y el color del
   título. NO oculta el título, para que en el editor se vea normal; el estado
   inicial de la animación lo aplica el script (src/scripts/hero-title-stagger.js),
   que no se ejecuta dentro del canvas. */

.hero-title,
.hero h1 {
  color: var(--ink) !important;
}

.hero-title .hero-title-mask,
.hero-title .hero-title-word,
.hero h1 .hero-title-mask,
.hero h1 .hero-title-word {
  color: inherit;
}

/* Máscaras por palabra: overflow hidden + padding compensado con margen negativo
   para no recortar acentos ("Lavandería"). */
.hero-title .hero-title-mask,
.hero h1 .hero-title-mask {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-block: 0.18em;
  margin-block: -0.18em;
  padding-inline: 0.02em;
  margin-inline: -0.02em;
}

.hero-title .hero-title-word,
.hero h1 .hero-title-word {
  display: inline-block;
  will-change: transform, opacity;
}

@media (prefers-reduced-motion: reduce) {
  .hero-title .hero-title-word,
  .hero h1 .hero-title-word {
    transform: none !important;
    opacity: 1 !important;
  }
}


/* src/styles/faq-accordion.css */
/* =========================================================================
   Acordeón .faq-list · icono de flecha y estados
   -------------------------------------------------------------------------
   Fuente ÚNICA de verdad para la pastilla y la flecha.

   El estado abierto se marca con la clase `.is-open` que pone el script
   (src/scripts/faq-accordion.js) y, como respaldo, con `details[open]` y
   con `:first-child` (el primer item siempre está abierto). Así el aspecto
   es el mismo en el canvas del editor y en la página publicada, sin
   depender de que el render resuelva el atributo `open`.
   ========================================================================= */

/* ── Máscara de la flecha ────────────────────────────────────────────────
   El set de iconos del sitio no incluía `arrow-down`: sin mask-image el
   <i> se pintaba como un cuadro sólido. */
i[data-lucide="arrow-down"] {
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14'/%3E%3Cpath d='m19 12-7 7-7-7'/%3E%3C/svg%3E");
  mask-repeat: no-repeat;
  mask-position: center;
  mask-size: contain;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14'/%3E%3Cpath d='m19 12-7 7-7-7'/%3E%3C/svg%3E");
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center;
  -webkit-mask-size: contain;
}

/* ── Pastilla: cerrado (clara) ────────────────────────────────────────── */
.faq-list summary .plus {
  background-color: var(--panel) !important;
  color: var(--dark) !important;
  transition: background-color 0.25s ease, color 0.25s ease;
}

/* ── Pastilla: abierto (oscura) ───────────────────────────────────────────
   Tres disparadores equivalentes; el que aplique gana. */
.faq-list details.is-open summary .plus,
.faq-list details[open] summary .plus,
.faq-list details:first-child summary .plus {
  background-color: var(--dark) !important;
  color: var(--light) !important;
}

/* Durante el repliegue el `open` nativo sigue puesto: se fuerza el aspecto
   cerrado. Va al final para ganar en el orden de la cascada. */
.faq-list details[data-faq-closing] summary .plus {
  background-color: var(--panel) !important;
  color: var(--dark) !important;
}

/* ── Flecha: hereda el color de la pastilla en todos los estados ──────── */
.faq-list summary .plus > i[data-lucide] {
  background-color: currentColor !important;
  width: 0.95em !important;
  height: 0.95em !important;
  transform-origin: 50% 50%;
  will-change: transform;
  backface-visibility: hidden;
}

/* Giro de la flecha en estado abierto (el script lo anima con GSAP). */
.faq-list details.is-open summary .plus > i[data-lucide],
.faq-list details[open] summary .plus > i[data-lucide],
.faq-list details:first-child summary .plus > i[data-lucide] {
  transform: rotate(180deg);
}

.faq-list details[data-faq-closing] summary .plus > i[data-lucide] {
  transform: rotate(0deg);
}

@media (prefers-reduced-motion: reduce) {
  .faq-list summary .plus {
    transition: none;
  }
  .faq-list summary .plus > i[data-lucide] {
    will-change: auto;
  }
}


/* src/styles/button-lift.css */
/* =====================================================================
   Botones del sitio · animación "lift" INVERTIDA
   Adaptada del ejemplo de Uiverse.io (satyamchaudharydev, inspirado en Gumroad).

   ESTADO NORMAL (es exactamente el que antes dibujaba el :hover):
   - el fondo del botón es el token --accent
   - texto e icono van en el color base del botón -> var(--btn-lift-base)
   - contorno COMPLETO (4 lados) en el color base; el grosor es configurable
     por botón con --btn-lift-border
   - sombra desplazada en ese mismo color base. La elevación la dibuja la
     sombra: el botón NO se desplaza, así su borde nunca queda recortado
     (contenedores con overflow: hidden recortaban el borde al elevar el botón)

   ESTADO HOVER / FOCUS-VISIBLE:
   - el fondo cambia al token primario -> var(--primary)
   - texto e icono pasan a --light
   - GAP ELÁSTICO: los dos elementos internos del botón (texto + icono) se
     separan con una curva con rebote -> cubic-bezier(0.34, 1.56, 0.64, 1).
     La separación es configurable por botón con --btn-lift-gap.
   - la sombra desplazada se mantiene (misma lectura de "elevado")

   Al hacer clic suelta la sombra.

   Excepción: los botones outlined (borde, fondo transparente) como
   .btn-hero-ghost NO se rellenan con el fondo del estado normal; solo se
   rellenan con su propio color y el texto pasa a --dark al pasar el cursor.
   ===================================================================== */

body :is(.btn, .btn-hero-primary, .btn-dark, .btn-on-dark, .navbar-cta, .nav-drawer-cta, .pros-cta, .loc-cta, .promo-submit, .svc-pgbtn, .reviews-google-btn) {
  /* --btn-lift-base: color base del botón (texto, contorno y sombra) */
  --btn-lift-base: var(--dark);
  /* --btn-lift-rest: fondo del estado normal (el que antes era el hover) */
  --btn-lift-rest: var(--purple);
  /* --btn-lift-hover: fondo del estado hover -> token primario */
  --btn-lift-hover: var(--accent);
  /* --btn-lift-border: grosor del contorno (igual en reposo y en hover) */
  --btn-lift-border: 2px;
  /* --btn-lift-gap: separación del gap elástico entre texto e icono */
  --btn-lift-gap: var(--space-xs);
  /* --btn-lift-ease: curva elástica (con rebote) del gap */
  --btn-lift-ease: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* Contorno en los 4 lados: el borde superior no desaparece */
  border-width: var(--btn-lift-border);
  border-style: solid;
  border-color: var(--btn-lift-base);
  /* El fondo del estado normal es el que antes solo aparecía en hover */
  background-color: var(--btn-lift-rest) !important;
  color: var(--btn-lift-base) !important;
  /* Sin traslación: el botón conserva su caja y su borde completo.
     El desplazamiento de la sombra da la lectura de "elevado". */
  transform: none;
  box-shadow: 0.25rem 0.25rem 0 var(--btn-lift-base);
  cursor: pointer;
  transition:
    background-color 0.25s ease,
    color 0.25s ease,
    border-color 0.25s ease,
    box-shadow 0.25s ease,
    transform 0.25s ease,
    gap 0.5s var(--btn-lift-ease) !important;
}

/* --- Normalización de los botones de las tarjetas de sucursales ------
   La página declara .loc-foot .loc-cta (y sus variantes .loc-blue /
   .loc-yellow) con !important y más especificidad que el selector
   compartido de arriba, así que esos botones se quedaban con su estilo
   antiguo (fondo oscuro, sin contorno ni sombra). Aquí se repiten las
   mismas declaraciones con especificidad suficiente para que ganen y
   estos botones se vean igual que el resto: fondo --accent en reposo,
   --primary en hover, contorno completo y sombra desplazada. */
body .loc .loc-foot .loc-cta,
body .loc.loc-blue .loc-foot .loc-cta,
body .loc.loc-yellow .loc-foot .loc-cta {
  border-width: var(--btn-lift-border, 2px);
  border-style: solid;
  border-color: var(--btn-lift-base, var(--dark)) !important;
  background-color: var(--btn-lift-rest, var(--accent)) !important;
  color: var(--btn-lift-base, var(--dark)) !important;
  box-shadow: 0.25rem 0.25rem 0 var(--btn-lift-base, var(--dark));
  transition:
    background-color 0.25s ease,
    color 0.25s ease,
    border-color 0.25s ease,
    box-shadow 0.25s ease,
    transform 0.25s ease,
    gap 0.5s var(--btn-lift-ease, cubic-bezier(0.34, 1.56, 0.64, 1)) !important;
}

body .loc .loc-foot .loc-cta:hover,
body .loc.loc-blue .loc-foot .loc-cta:hover,
body .loc.loc-yellow .loc-foot .loc-cta:hover,
body .loc .loc-foot .loc-cta:focus-visible {
  background-color: var(--btn-lift-hover, var(--primary)) !important;
  color: var(--dark) !important;
  border-color: var(--btn-lift-base, var(--dark)) !important;
  box-shadow: 0.25rem 0.25rem 0 var(--btn-lift-base, var(--dark));
  gap: var(--btn-lift-gap, var(--space-xs));
}

body .loc .loc-foot .loc-cta :is(i[data-lucide], svg),
body .loc.loc-blue .loc-foot .loc-cta :is(i[data-lucide], svg),
body .loc.loc-yellow .loc-foot .loc-cta :is(i[data-lucide], svg) {
  background-color: var(--btn-lift-base, var(--dark)) !important;
}

/* --- Icono del estado normal ---------------------------------------- */
body :is(.btn, .btn-hero-primary, .btn-dark, .btn-on-dark, .navbar-cta, .nav-drawer-cta, .pros-cta, .loc-cta, .promo-submit, .svc-pgbtn, .reviews-google-btn) :is(i[data-lucide], svg) {
  background-color: var(--btn-lift-base) !important;
}

/* --- Estado hover / foco de teclado ---------------------------------- */
body :is(.btn, .btn-hero-primary, .btn-dark, .btn-on-dark, .navbar-cta, .nav-drawer-cta, .pros-cta, .loc-cta, .promo-submit, .svc-pgbtn, .reviews-google-btn):hover,
body :is(.btn, .btn-hero-primary, .btn-dark, .btn-on-dark, .navbar-cta, .nav-drawer-cta, .pros-cta, .loc-cta, .promo-submit, .svc-pgbtn, .reviews-google-btn):focus-visible,
body .loc .loc-foot .loc-cta:hover,
body .loc.loc-blue .loc-foot .loc-cta:hover,
body .loc.loc-yellow .loc-foot .loc-cta:hover {
  background-color: var(--btn-lift-hover) !important;
  color: var(--light) !important;
  border-color: var(--btn-lift-base) !important;
  transform: none;
  box-shadow: 0.25rem 0.25rem 0 var(--btn-lift-base);
  /* GAP ELÁSTICO: separa el texto del icono con rebote (la transición
     elástica se declara en el estado normal, arriba) */
  gap: var(--btn-lift-gap);
}

/* --- Icono en hover (lucide se pinta con background-color sobre la máscara) ---
   Se mantiene en el color base para que siga leyéndose sobre el círculo claro */
body :is(.btn, .btn-hero-primary, .btn-dark, .btn-on-dark, .navbar-cta, .nav-drawer-cta, .pros-cta, .loc-cta, .promo-submit, .svc-pgbtn, .reviews-google-btn):hover :is(i[data-lucide], svg),
body :is(.btn, .btn-hero-primary, .btn-dark, .btn-on-dark, .navbar-cta, .nav-drawer-cta, .pros-cta, .loc-cta, .promo-submit, .svc-pgbtn, .reviews-google-btn):focus-visible :is(i[data-lucide], svg),
body .loc .loc-foot .loc-cta:hover :is(i[data-lucide], svg),
body .loc.loc-blue .loc-foot .loc-cta:hover :is(i[data-lucide], svg),
body .loc.loc-yellow .loc-foot .loc-cta:hover :is(i[data-lucide], svg) {
  background-color: var(--btn-lift-base) !important;
}

/* --- Clic: suelta la sombra ----------------------------------------- */
body :is(.btn, .btn-hero-primary, .btn-dark, .btn-on-dark, .navbar-cta, .nav-drawer-cta, .pros-cta, .loc-cta, .promo-submit, .svc-pgbtn, .reviews-google-btn):active,
body .loc .loc-foot .loc-cta:active {
  transform: none;
  box-shadow: none;
}

/* =====================================================================
   Botón outlined (borde + fondo transparente): sin relleno del estado
   normal, solo se rellena con su propio color y texto/icono en --dark
   ===================================================================== */
.btn-hero-ghost {
  cursor: pointer;
  background-color: var(--light);
  color: var(--dark) !important;
  transition:
    background-color 0.2s ease,
    color 0.2s ease,
    border-color 0.2s ease;
}

.btn-hero-ghost:hover,
.btn-hero-ghost:focus-visible {
  background-color: var(--sand) !important;
  border-color: var(--sand) !important;
  color: var(--dark) !important;
  transform: none;
  box-shadow: none;
}

.btn-hero-ghost:hover :is(i[data-lucide], svg),
.btn-hero-ghost:focus-visible :is(i[data-lucide], svg) {
  background-color: var(--dark) !important;
}

.btn-hero-ghost:active {
  transform: none;
  box-shadow: none;
}

/* --- Sin animación si el usuario lo pide ---------------------------- */
@media (prefers-reduced-motion: reduce) {
  body :is(.btn, .btn-hero-primary, .btn-dark, .btn-on-dark, .navbar-cta, .nav-drawer-cta, .pros-cta, .loc-cta, .promo-submit, .svc-pgbtn, .reviews-google-btn) {
    transition: none;
  }
}


/* src/styles/asset-animation-spin.css */
/* =========================================================================
   Giro asset-animation_*.webp — preparación de las piezas
   El movimiento lo aplica src/scripts/asset-animation-spin.js: aquí sólo se
   preparan las imágenes para que el giro sea limpio.
   ========================================================================= */

img[src*="asset-animation"] {
  transform-origin: 50% 50%;
  will-change: transform;
  backface-visibility: hidden;
}

/* En táctil el gesto es el toque: se quita el destello del tap y se evita
   que el doble toque haga zoom mientras se dispara el giro. */
@media (hover: none), (pointer: coarse) {
  img[src*="asset-animation"] {
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
  }
}


/* src/styles/pros-cursor-trail.css */
/* =========================================================================
   Cursor trail · capa y piezas del rastro (.pros-inner / .pros-deco)
   La capa y sus piezas las inyecta src/scripts/pros-cursor-trail.js.
   ========================================================================= */

/* Capa fija: coordenadas de viewport, así que no altera ningún layout.
   Está siempre presente (las apariciones las gobierna el script), y el
   recorte por clip-path la ciñe al rectángulo de la sección. */
.pros-trail-layer {
  position: fixed;
  inset: 0;
  z-index: 4;
  pointer-events: none;
}

/* Piezas del pool: el script les escribe left/top y las centra con
   xPercent/yPercent -50, así que aquí sólo hacen falta la forma y el
   estado de reposo (ocultas hasta que les toca aparecer). */
.pros-trail-item {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  width: var(--pros-trail-size, clamp(4.5rem, 8vw, 8rem));
  height: auto;
  max-width: none;
  opacity: 0;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  transform-origin: 50% 50%;
  will-change: transform;
  filter: drop-shadow(0 12px 28px var(--shadow-primary));
}

/* El rastro es un adorno de puntero: sin puntero fino no se muestra. */
@media (hover: none), (pointer: coarse) {
  .pros-trail-layer {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pros-trail-layer {
    display: none;
  }
}


/* src/styles/cards-slider.css */
/* =====================================================================
   Carrusel infinito de tarjetas de servicios (.cards) y sus .dots
   Sólo se aplica cuando el script src/scripts/cards-slider.js añade las
   clases js-cards-slider / js-cards-track. Sin JS (o con
   prefers-reduced-motion) los .cards se quedan como la rejilla original.
   ===================================================================== */

/* --- Marco: recorta la pista y difumina los bordes --- */
.js-cards-slider {
  position: relative;
  overflow: hidden;
  cursor: grab;
  /* El eje horizontal lo gobierna el arrastre; en vertical la página sigue
     su curso. overscroll-behavior evita el "scroll chaining" en el gesto. */
  touch-action: pan-y;
  overscroll-behavior-x: contain;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 1%, #000 98%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0%, #000 1%, #000 98%, transparent 100%);
}

.js-cards-slider.is-dragging {
  cursor: grabbing;
}

/* La rejilla pasa a ser una pista horizontal continua */
.js-cards-slider .cards {
  display: flex;
  flex-wrap: nowrap;
  align-items: stretch;
  grid-template-columns: none;
  gap: var(--space-s);
  width: max-content;
  will-change: transform;
}

/* Cada tarjeta conserva su ancho propio (no se encoge) */
.js-cards-slider .cards > * {
  flex: 0 0 auto;
  width: var(--cards-slide-width, min(20rem, 74vw));
}

/* Las copias del bucle siguen siendo interactivas. Al girar el carrusel la
   copia queda justo bajo el cursor o el dedo: si no recibiera clics, los
   botones de las tarjetas dejarían de responder a partir del segundo ciclo
   (que es exactamente lo que ocurría con el anterior pointer-events: none).
   Sólo se excluyen del orden de tabulación, vía tabindex="-1" que pone el
   script, para no duplicar paradas de teclado. */
.js-cards-slider .cards > .is-clone {
  pointer-events: auto;
}

/* Enlaces e imágenes no deben arrancar el arrastre nativo del navegador,
   que competiría con el swipe en táctil. */
.js-cards-slider .cards a,
.js-cards-slider .cards img {
  -webkit-user-drag: none;
}

@media (min-width: 1025px) {
  .js-cards-slider .cards > * {
    width: var(--cards-slide-width, 21.5rem);
  }
}

/* --- Indicadores --- */
.js-cards-slider .dots.js-cards-dots {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  margin-top: var(--space-s);
}

.js-cards-slider .dots.js-cards-dots > span {
  flex: 0 0 auto;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 999px;
  background-color: var(--primary);
  opacity: 0.45;
  cursor: pointer;
  transform: scale(0.72);
  transition: background-color 0.3s ease, width 0.3s ease, opacity 0.3s ease;
}

.js-cards-slider .dots.js-cards-dots > span:hover {
  background-color: var(--secondary);
}

.js-cards-slider .dots.js-cards-dots > span.is-active {
  width: 1.75rem;
  background-color: var(--primary);
}

.js-cards-slider .dots.js-cards-dots > span:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .js-cards-slider,
  .js-cards-slider .dots.js-cards-dots > span {
    transition: none;
  }
}


/* src/styles/chat-widget.css */
/* =====================================================================
   Chat widget · el contenedor fijo no debe interceptar la página
   ---------------------------------------------------------------------
   .chat-widget es position: fixed (right/bottom) con z-index 90 y su caja
   abarca casi todo el ancho y buena parte del alto del viewport en mobile:
   el panel mide min(21rem, 100vw - márgenes) y va apilado encima del FAB,
   así que el contenedor resultante es un rectángulo grande anclado abajo.

   El panel cerrado ya era pointer-events: none, pero el CONTENEDOR no lo
   era. Como el contenedor sigue siendo hit-testeable aunque no pinte nada,
   cualquier toque que cayera dentro de su caja (por ejemplo, los botones
   del hero al hacer scroll) se quedaba en el widget y nunca llegaba al
   botón. En escritorio el widget ocupa una esquina y el solape no ocurre,
   de ahí que el fallo sólo se viera en mobile.

   Regla: el contenedor NUNCA captura. Sólo son pulsables el FAB y el panel
   cuando está abierto.
   ===================================================================== */

.chat-widget {
  pointer-events: none;
}

/* El botón flotante conserva su interacción. Si el componente lo oculta
   con el panel abierto, su propia regla (más específica) seguirá mandando. */
.chat-widget .chat-fab {
  pointer-events: auto;
}

/* Cerrado: el panel no captura (refuerza el estado base del componente). */
.chat-widget .chat-panel {
  pointer-events: none;
}

/* Abierto: el panel vuelve a ser interactivo sin depender del orden de carga. */
.chat-widget.is-open .chat-panel {
  pointer-events: auto;
}


/* src/styles/services-responsive.css */
/* =========================================================================
   Filtro "Arma tu servicio" (.svc2-*) · ajustes responsivos
   -------------------------------------------------------------------------
   El sello de la tarjeta de resultado (.svc2-result-badge-img) se oculta en
   tablet y mobile: a esos anchos la tarjeta se apila y el sello sólo roba
   espacio al título, la descripción y el precio.
   El `!important` es necesario porque el nodo de imagen lleva su tamaño en
   estilos inline (width/height/display) puestos desde el editor.
   ========================================================================= */

@media (max-width: 768px) {
  .svc2-section .svc2-result-badge-img,
  .svc2-section .svc2-result-main img.svc2-result-badge-img,
  .svc2-result .svc2-result-badge-img {
    display: none !important;
  }
}
