/* ==========================================================================
   Custom code portado 1:1 desde Webflow (Site Settings > Custom Code).
   Fuente: capturado por Webflow Data API (get_site_freeform_code), Fase 0.
   No reescribir a mano: si Webflow cambia esto, se vuelve a exportar igual.
   ========================================================================== */

/* ----- Fix de paridad: reset real encontrado -----
   La regla real NO vive en ningún archivo .css enlazado (export, ni las 2
   hojas del sitio en vivo) — vive como un <style> inline embebido en el
   HTML de la página (un Embed de Webflow, igual que el grain/glow). Solo
   se encuentra leyendo el HTML servido, no las hojas de CSS. Sin esto,
   ".w-nav-link{color:#222222}" de webflow.css gana porque es un selector
   de clase (más específico que un simple "a{color:inherit}", que fue mi
   primer intento y perdía la cascada). Copiado tal cual del embed real. */
a,
.w-input,
.w-select,
.w-tab-link,
.w-nav-link,
.w-nav-brand,
.w-dropdown-btn,
.w-dropdown-toggle,
.w-slider-arrow-left,
.w-slider-arrow-right,
.w-dropdown-link {
  color: inherit;
  text-decoration: inherit;
  font-size: inherit;
}

/* Líneas punteadas reutilizables (Our values, tarjetas de industrias, etc.).
   Encontrado 2026-07-20 en un Embed real del export fresco de Webflow
   (index.html, "other-custome-styles", comentado como réplica de Figma:
   dashed 8/8, 1px, blanco 32%) — reemplaza un intento anterior a ojo que
   usaba border-left dashed sin el color/spacing reales. Mismo bloque
   también define .dashed-line-h con el patrón real (ver más abajo, donde
   se reemplaza el fix de color sólido de la Ronda 5). */
.dashed-line-h,
.dashed-line-v,
.dashed-line-v-extended {
  --dash-color: rgba(255, 255, 255, 0.32);
  --dash-length: 8px;
  --gap-length: 8px;
  --line-thickness: 1px;
  z-index: 1;
}
.dashed-line-v {
  width: var(--line-thickness);
  background-image: repeating-linear-gradient(
    180deg,
    var(--dash-color) 0,
    var(--dash-color) var(--dash-length),
    transparent var(--dash-length),
    transparent calc(var(--dash-length) + var(--gap-length))
  );
}
.dashed-line-v-extended {
  background-image: repeating-linear-gradient(
    180deg,
    var(--dash-color) 0,
    var(--dash-color) var(--dash-length),
    transparent var(--dash-length),
    transparent calc(var(--dash-length) + var(--gap-length))
  );
}

/* Ídem para el navbar: ".glass-bg" no tiene NINGUNA regla en ninguna hoja
   CSS capturada (export, ni las 2 hojas del sitio en vivo) — cae al default
   de Webflow ".w-nav{background:#dddddd}" si no se corrige. A diferencia del
   primer intento (que usó un tono oscuro inventado), estos valores son los
   REALES: medidos con getComputedStyle directo sobre el sitio publicado
   (mentaexpertsv1.webflow.io) vía Playwright — es un tinte BLANCO al 8%
   con blur 20px + saturate 1.8, no un tinte oscuro. El mecanismo que lo
   aplica en Webflow (qué clase/regla exacta) sigue sin ubicarse en ningún
   CSS, pero el valor ya no es una reconstrucción a ojo. */
.navbar.glass-bg {
  background-color: rgba(255, 255, 255, 0.08);
  -webkit-backdrop-filter: blur(20px) saturate(1.8);
  backdrop-filter: blur(20px) saturate(1.8);
  box-shadow:
    0 4px 24px rgba(0, 0, 0, 0.15),
    inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

/* ----- Logo del navbar: tamaño fijo, nunca se encoge -----
 * Ni el export ni el CSS del sitio publicado traen regla propia para
 * `.navbar_logo`: el logo tomaba su tamaño intrínseco del SVG (medido con
 * Playwright: 121×40) más el `max-width:100%` de Webflow. Como
 * `.navbar_logo-link` es flex item de `.navbar_container` con `flex-shrink:1`
 * por default, al angostar la ventana el link cedía ancho y el <img> se
 * encogía con él — medido: 121×40 → 38×12.6 a 1024px → 9×3 a 992px (colapso
 * casi total). `flex:none` congela el link en su ancho de contenido y
 * `max-width:none` evita que un ancestro estrecho vuelva a escalar el SVG; el
 * tamaño resultante es el intrínseco, no un valor nuevo inventado. */
.navbar_logo-link {
  flex: none;
}
.navbar_logo {
  max-width: none;
}

/* ----- Navbar compacto: solo el megamenú (≤1399px) -----
 * El navbar es el .navbar_component (.w-nav) de Webflow. En un sitio Webflow
 * normal, a ≤991px la regla `.w-nav[data-collapse='medium'] .w-nav-menu{display:none}`
 * oculta el menú inline y aparece el hamburguesa `.w-nav-button` que abre
 * `webflow.js`. En este port NO existe `data-collapse` en el .navbar, NO existe
 * `.w-nav-button`, y NO se carga webflow.js (se reemplazó por el megamenú custom
 * + site.js). Como consecuencia, la regla de Webflow (mentaexperts.webflow.css)
 * que a ≤991px convierte `.navbar_menu` en un panel `position:absolute;
 * height:100dvh` quedaba SIEMPRE visible mostrando el menú viejo
 * (.navbar_menu-left con los dropdowns) — "el menú anterior" reportado.
 * Fix: acá se elimina ese menú viejo y se neutraliza el modo panel, dejando
 * la barra superior compacta con solo el CTA + el trigger del megamenú. El
 * cambio de idioma en este modo vive dentro del megamenú (.megamenu_lang), no
 * en la barra; por eso se oculta el toggle del top-bar (.navbar_lang) acá.
 *
 * El umbral es 1399px (no 991px) porque el menú inline necesita más ancho del
 * que Webflow suponía. Medido con Playwright: .navbar_menu-left ocupa 571px
 * rígidos y la barra completa (logo 121 + menú 571 + idioma 44 + CTA 266 +
 * trigger 44 + gaps 56) necesitaba ~1102px de contenedor, disponibles solo
 * desde ~1255px de ventana. Entre 992 y 1279 el original lo absorbía encogiendo
 * el logo hasta 9px; ahora que el logo es de tamaño fijo, ese faltante empujaba
 * el hamburguesa fuera de la pantalla (48px afuera a 1024px) y partía el CTA en
 * dos líneas.
 *
 * 2026-07-28: el umbral sube de 1279 a 1399 al añadirse el dropdown
 * "Resources" (Blog + QA Checklist) en la fila superior. Re-medido con
 * Playwright por búsqueda binaria: .navbar_menu-left pasa de 571px a ~700px, y
 * el ancho mínimo de ventana sin que el CTA parta en dos líneas es 1397px en EN
 * y 1388px en ES. Con 1399 el menú inline solo aparece desde 1400px, con 3px de
 * margen sobre el peor caso. Por debajo, el megamenú (que ya contiene Resources
 * como categoría propia) cubre la navegación completa. */
@media screen and (max-width: 1399px) {
  .navbar_menu-left {
    display: none;
  }
  .navbar_menu {
    position: static;
    height: auto;
    min-height: 0;
    margin-left: auto;
    padding: 0;
    background-color: transparent;
    border-bottom: none;
    overflow: visible;
    justify-content: flex-end;
  }
  .navbar_menu-right {
    flex-direction: row;
    align-items: center;
    margin-top: 0;
  }
  /* El selector de idioma de la barra (hoy el dropdown con ícono de mundo,
   * .navbar_lang-dropdown) se oculta en modo compacto igual que antes el
   * toggle EN|ES: en este modo el cambio de idioma vive en el megamenú. */
  .navbar_menu-right > .navbar_lang-dropdown {
    display: none;
  }
}

/* ----- CTA: en la barra desde 768px, flotante abajo a la derecha en móvil -----
 * Medido con Playwright a 375px: logo fijo (121) + CTA (173 comprimido) +
 * hamburguesa (44) + gaps (32) piden 370px sobre los ~340px útiles, así que el
 * CTA quedaba pegado al logo, partido en dos líneas y empujaba el hamburguesa
 * 10px fuera de la pantalla. En ≤767px el CTA sale de la barra (queda logo +
 * hamburguesa, ambos completos) y pasa a un pill fijo abajo a la derecha, para
 * seguir visible durante todo el scroll. Desde 768px la barra vuelve a llevar
 * el CTA inline (medido: 266×48, una línea, sin desborde) y el flotante se
 * oculta. El markup del flotante vive en Navbar.astro, fuera de .navbar. */
.mobile-cta {
  display: none;
}
@media screen and (max-width: 767px) {
  .navbar_menu-right > .button {
    display: none;
  }
  .mobile-cta {
    display: block;
    position: fixed;
    right: var(--_ui-styles---spacing-padding--space-lg);
    bottom: var(--_ui-styles---spacing-padding--space-lg);
    /* Debajo del scrim del megamenú (1050) y del modal (9999). */
    z-index: 1040;
    transition:
      opacity 0.25s ease,
      transform 0.25s ease;
  }
  /* Misma sombra que la barra (.navbar.glass-bg) para que el pill se despegue
   * del contenido con el mismo lenguaje visual, sin introducir otro valor. */
  .mobile-cta .button {
    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
    white-space: nowrap;
  }
  /* Con el megamenú o el modal abiertos el flotante estorba: se retira en vez
   * de quedar atenuado detrás del scrim semitransparente. */
  body:has(.megamenu_root.is-open) .mobile-cta,
  body:has([data-modal="root"].is-open) .mobile-cta {
    opacity: 0;
    transform: translateY(0.5rem);
    pointer-events: none;
  }
}
@media screen and (max-width: 767px) and (prefers-reduced-motion: reduce) {
  .mobile-cta {
    transition: none;
  }
  body:has(.megamenu_root.is-open) .mobile-cta,
  body:has([data-modal="root"].is-open) .mobile-cta {
    transform: none;
  }
}

/* El toggle de idioma dentro del megamenú (rail-foot) va sobre el botón de
 * Contacto, con un respiro debajo. Visible en móvil (nivel 1) y desktop. */
.megamenu_rail-foot .megamenu_lang {
  margin-bottom: 0.875rem;
}

/* ----- Film grain overlay ----- */
[data-grain] {
  filter: url(#grain);
  mix-blend-mode: soft-light;
  pointer-events: none;
}

/* ----- Glow beam ----- */
:root {
  --glow-color-r: 59;
  --glow-color-g: 191;
  --glow-color-b: 173;
  --glow-opacity: 0.4;
  --glow-spread: 45%;
  --glow-base-y: 100%;
  --glow-size-start: 60%;
  --glow-size-end: 110%;
}
[data-glow] {
  pointer-events: none;
  overflow: hidden;
  opacity: var(--glow-opacity);
  background: radial-gradient(
    ellipse at var(--glow-x, 50%) var(--glow-base-y),
    rgba(var(--glow-color-r), var(--glow-color-g), var(--glow-color-b), 1) 0%,
    rgba(var(--glow-color-r), var(--glow-color-g), var(--glow-color-b), 0.85) 8%,
    rgba(var(--glow-color-r), var(--glow-color-g), var(--glow-color-b), 0.65) 18%,
    rgba(var(--glow-color-r), var(--glow-color-g), var(--glow-color-b), 0.45) 28%,
    rgba(var(--glow-color-r), var(--glow-color-g), var(--glow-color-b), 0.28) 38%,
    rgba(var(--glow-color-r), var(--glow-color-g), var(--glow-color-b), 0.15) var(--glow-spread),
    rgba(var(--glow-color-r), var(--glow-color-g), var(--glow-color-b), 0.06) 60%,
    rgba(var(--glow-color-r), var(--glow-color-g), var(--glow-color-b), 0.02) 75%,
    rgba(var(--glow-color-r), var(--glow-color-g), var(--glow-color-b), 0) 100%
  );
  background-repeat: no-repeat;
  background-position: var(--glow-x, 50%) var(--glow-base-y);
  background-size: var(--glow-bg-size, 100%) var(--glow-bg-size, 100%);
}
[data-glow="bottom-center"] { --glow-x: 50%; }
[data-glow="bottom-left"] { --glow-x: 25%; }
[data-glow="bottom-right"] { --glow-x: 75%; }

/* ----- Hero reveal (anti-flash cover, debe ir siempre en head/antes del paint) ----- */
[data-hero-reveal] {
  --reveal-overlay-color: rgb(46, 41, 37);
  --reveal-columns: 4;
}
[data-hero-reveal]::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--reveal-overlay-color);
  z-index: 6;
  pointer-events: none;
}
[data-hero-reveal].hero-reveal--ready::after { display: none; }
[data-hero-stagger] { opacity: 0; }
.hero-reveal__overlay {
  position: absolute;
  top: 0;
  bottom: 0;
  background-color: var(--reveal-overlay-color);
  z-index: 5;
  transform: scaleY(1);
  will-change: transform;
  pointer-events: none;
}
.hero-reveal__line-position {
  position: absolute;
  top: 0;
  bottom: 0;
  /* Capas del hero (medido en el sitio publicado): fondo .hero_bg-image-wrapper
     z=0 < líneas z=1 < contenido .hero_content(-v2) z=2 — con z=2 las líneas
     empataban con el contenido y, al ir últimas en el DOM, tapaban texto y
     imagen/video. */
  z-index: 1;
  height: auto !important;
  pointer-events: none;
  /* El transform (centrado xPercent + scaleY del dibujado) lo controla
     enteramente GSAP desde site.js — no declararlo acá o se pisan. */
}
[data-hero-reveal] .header5_content { z-index: 3; }

/* ----- Modal scroll lock ----- */
body.modal-scroll-lock {
  position: fixed;
  overflow-y: scroll;
  width: 100%;
}

/* ----- Line reveal ----- */
:root {
  --line-duration: 0.9s;
  --line-easing: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
[data-line="horizontal"] {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--line-duration) var(--line-easing);
  transition-delay: var(--line-delay, 0ms);
}
[data-line="vertical"] {
  transform: scaleY(0.001);
  transform-origin: center top;
  transition: transform var(--line-duration) var(--line-easing);
  transition-delay: var(--line-delay, 0ms);
}
[data-line="horizontal"].is-line-visible { transform: scaleX(1); }
[data-line="vertical"].is-line-visible { transform: scaleY(1); }

/* ----- Megamenú ----- */
:root {
  /* Alias local del verde de marca: se mantiene el nombre corto porque lo
     usan ~30 reglas del megamenú, pero el valor ya no se duplica. */
  --mm-accent: var(--_primitives---colors--menta);
  --mm-open-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --mm-open-duration: 0.38s;
  --mm-view-duration: 0.3s;
  --mm-mobile-slide-duration: 0.42s;
  --mm-accordion-duration: 0.32s;
  --mm-hover-bg: rgba(255, 255, 255, 0.04);
}
@media (prefers-reduced-motion: reduce) {
  :root {
    --mm-open-duration: 0.01ms;
    --mm-view-duration: 0.01ms;
    --mm-mobile-slide-duration: 0.01ms;
    --mm-accordion-duration: 0.01ms;
  }
}
/* .megamenu_scrim/.megamenu_root traen "display:none" base en el CSS del
   sitio, pero la variante ".is-open{display:...}" que lo revierte no está
   en ninguna de las 2 hojas actuales del sitio (shared + home-optimized) —
   probablemente vive en una hoja per-página distinta que no descargamos.
   Sin esto, el is-open nunca se ve aunque la clase se agregue bien. */
.megamenu_scrim.is-open { display: block !important; }
.megamenu_root.is-open { display: flex !important; }
.megamenu_view.is-active { display: block !important; }

.megamenu_scrim {
  opacity: 0;
  transition: opacity var(--mm-open-duration) ease, display var(--mm-open-duration) allow-discrete;
}
.megamenu_scrim.is-open { opacity: 1; }
@starting-style { .megamenu_scrim.is-open { opacity: 0; } }
.megamenu_root {
  opacity: 0;
  transform: translateY(8px) scale(0.98);
  transition:
    opacity var(--mm-open-duration) var(--mm-open-ease),
    transform var(--mm-open-duration) var(--mm-open-ease),
    display var(--mm-open-duration) allow-discrete;
}
.megamenu_root.is-open { opacity: 1; transform: translateY(0) scale(1); }
@starting-style { .megamenu_root.is-open { opacity: 0; transform: translateY(8px) scale(0.98); } }
.megamenu_view.is-active { animation: mmViewIn var(--mm-view-duration) var(--mm-open-ease) both; }
@keyframes mmViewIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}
.megamenu_cat { transition: background-color 0.2s ease; }
.megamenu_cat:hover:not(.is-active):not(.is-disabled) { background-color: var(--mm-hover-bg); }
.megamenu_cat-chevron { transition: border-color 0.2s ease; }
.megamenu_cat:hover:not(.is-disabled) .megamenu_cat-chevron { border-color: var(--mm-accent); }
.megamenu_rail-cta { transition: background-color 0.2s ease; }
.megamenu_rail-cta:hover { background-color: color-mix(in srgb, var(--_primitives---colors--menta) 16%, transparent); }
.megamenu_close-line,
.megamenu_trigger-line { transition: background-color 0.2s ease; }
.megamenu_close:hover .megamenu_close-line,
.megamenu_trigger:hover .megamenu_trigger-line { background-color: var(--mm-accent); }
/* Este diseño no usa bordes contorneados en ningún elemento (corrección del
 * usuario 2026-07-21); .megamenu_col-head traía un border-left heredado del
 * export de Webflow que rompe esa regla. */
.megamenu_col-head { border-left: none; padding-left: 0; }
.navbar-dropdown-title-container { border-left: none; }
/* .megamenu_root traía además un contorno de 1px alrededor de todo el panel
 * (heredado del export de Webflow) — mismo error, mismo criterio: este
 * diseño no enmarca cards/paneles con borde. "Bordes contorneados" (corrección
 * 2026-07-21) resultó referirse también a las esquinas redondeadas de los
 * paneles/cards, no solo al borde en sí: este diseño usa esquinas rectas
 * (border-radius: 0) en paneles y cards, reservando el radio circular/pill
 * solo para botones e íconos (Button.astro, trigger/close del megamenu). */
.megamenu_root { border: none; border-radius: 0; }
.megamenu_cat { border-radius: 0; }
@media (max-width: 991px) {
  .megamenu_root { height: 100dvh; max-height: 100dvh; }
  .megamenu_inner { position: relative; overflow: hidden; }
  .megamenu_rail,
  .megamenu_panel {
    position: absolute;
    inset: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    transition:
      transform var(--mm-mobile-slide-duration) var(--mm-open-ease),
      opacity var(--mm-mobile-slide-duration) ease;
  }
  .megamenu_root:not(.is-mobile-lvl1) .megamenu_panel {
    opacity: 0;
    transform: translateX(24px);
    pointer-events: none;
  }
  .megamenu_root.is-mobile-lvl1 .megamenu_rail {
    opacity: 0;
    transform: translateX(-24px);
    pointer-events: none;
  }
  .megamenu_panel .mm-col-body {
    overflow: hidden;
    max-height: 0;
    opacity: 0;
    transition:
      max-height var(--mm-accordion-duration) var(--mm-open-ease),
      opacity calc(var(--mm-accordion-duration) * 0.8) ease;
  }
  .megamenu_panel .mm-col-body.is-open { opacity: 1; }
  .megamenu_panel .megamenu_col-head { cursor: pointer; position: relative; padding-right: 1.5rem; }
  .megamenu_panel .megamenu_col-head::after {
    content: "";
    position: absolute;
    right: 0.5rem;
    width: 7px;
    height: 7px;
    border-right: 1.5px solid rgba(255, 255, 255, 0.3);
    border-bottom: 1.5px solid rgba(255, 255, 255, 0.3);
    transform: rotate(45deg);
    transition: transform 0.25s var(--mm-open-ease), border-color 0.25s ease;
  }
  .megamenu_panel .megamenu_col.is-open > .megamenu_col-head::after {
    transform: rotate(-135deg);
    border-color: var(--mm-accent);
  }
  /* Vistas siempre desplegadas (Menta, Resources): su cabecera es solo un
     rótulo, así que no lleva chevron ni cursor de "clickeable". */
  .megamenu_panel [data-mm-flat] .megamenu_col-head {
    cursor: default;
    padding-right: 0;
  }
  .megamenu_panel [data-mm-flat] .megamenu_col-head::after {
    content: none;
  }
}

/* Valor medido en vivo: .trust-bar_tag-container tiene align-self:start
   dentro de .grid-0-5-1 (que en sí es align-items:center) — el tag "Numbers"
   queda arriba, no centrado con todo el bloque de stats. No estaba en
   ninguna hoja capturada como regla propia (el grid en sí no lo fuerza). */
.trust-bar_tag-container {
  align-self: start;
}

/* Animación de hover de los botones (texto e ícono suben y salen, el
   duplicado -2 entra desde abajo). El markup ya trae button-txt-2/
   icon-2 sincronizados por JS (ver public/js/site.js), pero no se pudo
   ubicar la regla/animación exacta en ningún CSS ni script capturado
   (revisé las 2 hojas del sitio, el custom code de sitio Y de la página
   Home, y el webflow.js compilado del sitio). Implementación propia que
   reproduce el efecto descrito: overflow:hidden + slide vertical. */
.button-txt-container,
.button-icon-container {
  overflow: hidden;
  position: relative;
}
/* El contenedor del ícono es flex item de `.button` y hereda `flex-shrink:1`:
 * al angostar la ventana el botón se comprimía y, como acá hay
 * `overflow:hidden` para la animación de hover, la flecha se recortaba en vez
 * de solo apretarse — medido con Playwright: 20px → 11px de ancho a 1120px,
 * es decir media flecha visible. `flex:none` la deja siempre completa (el
 * ancho lo cede el texto, que sí puede encogerse). */
.button-icon-container {
  flex: none;
}
.button-txt,
.button-icon-container .icon-embed-xsmall {
  transition: transform 0.32s cubic-bezier(0.65, 0, 0.35, 1);
}
.button-txt.is-2,
.button-icon-container .icon-embed-xsmall.is-2 {
  position: absolute;
  inset: 0 auto auto 0;
  transform: translateY(100%);
}
.button:hover .button-txt:not(.is-2),
.button-2:hover .button-txt:not(.is-2) {
  transform: translateY(-100%);
}
.button:hover .button-txt.is-2,
.button-2:hover .button-txt.is-2 {
  transform: translateY(0%);
}
.button:hover .button-icon-container .icon-embed-xsmall:not(.is-2),
.button-2:hover .button-icon-container .icon-embed-xsmall:not(.is-2) {
  transform: translateY(-100%);
}
.button:hover .button-icon-container .icon-embed-xsmall.is-2,
.button-2:hover .button-icon-container .icon-embed-xsmall.is-2 {
  transform: translateY(0%);
}

/* El ícono de cada item del panel del megamenú (navbar_dropdown-link-2)
   caía debajo del texto en vez de al costado — el grid-template-columns
   "max-content 1fr" de esa clase deja que la descripción larga empuje la
   columna del ícono. Override propio con flex para que quede como en la
   referencia (ícono a la derecha, alineado arriba). */
.navbar_dropdown-link-2 {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
}
.navbar_dropdown-link-2 .navbar_icon-wrapper {
  flex: none;
}

/* Hover de los links "secundarios" (footer, megamenú, dropdowns) marcados
   con data-gsap="hover-links": se desplazan unos px a la derecha al pasar
   el mouse. Valor medido en vivo con Playwright/getComputedStyle sobre un
   link del footer real: translateX(5.34px) — no reconstruido a ojo. */
[data-gsap="hover-links"] {
  transition: transform 0.25s ease;
}
[data-gsap="hover-links"]:hover {
  transform: translateX(5.34px);
}

/* Scroll Text Animation - Line Mask Style (custom code de la página Home,
   ver public/js/site.js). Esta parte CSS se me había quedado afuera en la
   primera pasada — el JS creaba los divs .line-mask pero sin position, por
   lo que no tapaban el texto como máscara (por eso "no se pintaba"). */
[data-gsap="scroll-text"] .line {
  position: relative;
}
[data-gsap="scroll-text"] .line-mask {
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  width: 100%;
  z-index: 2;
  pointer-events: none;
}

/* ----- Home Services accordion (custom code de página Home) ----- */
.services-accordion_media-item {
  transition: opacity 0.5s ease;
}
.services-accordion_media-item.is-active {
  opacity: 1;
}
.services-accordion_item:last-child {
  border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
.services-accordion_trigger {
  user-select: none;
  cursor: pointer;
}
.services-accordion_icon {
  transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}
.services-accordion_item.is-active .services-accordion_icon {
  transform: rotate(45deg);
}
.services-accordion_body {
  overflow: hidden;
  transition: height 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.services-accordion_link {
  width: fit-content;
}

/* ----- FAQ accordion: implementación propia (ver public/js/site.js) -----
   El original usa una interacción nativa de Webflow (IX2) no extraíble. */
.faq_question {
  cursor: pointer;
}
.faq_icon-wrapper {
  transition: transform 0.3s ease;
}
.faq_accordion.is-open .faq_icon-wrapper {
  transform: rotate(45deg);
}
.faq_answer {
  transition: height 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Ronda 13 (revisión Figma, node 6204:575): se probaron líneas punteadas
   verticales detrás del FAQ (2 rondas: primero acotadas a `.faq_content`,
   después a toda la altura de la sección) — el cliente no las quiso, revertido.
   Se dejan solo las horizontales (`dashed-line-h`, ya existentes desde antes
   de esta ronda, una por pregunta) sin líneas verticales. */

/* Grid de 4 cards "Why Menta" (.card-feature_row): el sistema de grid de 12
   columnas de Webflow ubica cada card con una regla propia por
   "#w-node-<uuid>-<pageId>" generada en el Designer — al recrear el sitio
   esos IDs de página cambiaron y ya no matchean nada, así que las 4 cards
   caen al auto-placement por defecto (1 columna angosta cada una, en vez de
   2x2). Override a un grid limpio de 2 columnas; el breakpoint de 991px de
   mentaexperts.webflow.css ya las apila a 1 columna, así que esto solo debe
   aplicar en desktop. */
@media screen and (min-width: 992px) {
  .card-feature_row {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Ronda 13 (revisión Figma): las 4 cards de Why Menta no deben ser todas del
   mismo ancho — el diseño (Figma node 6200:186) alterna una card angosta
   (~40%) con una ancha (~60%) por fila, invertido en la 2da fila. 5 columnas
   iguales + spans distintos por nth-child logra el ancho asimétrico por fila
   sin depender de "fr" por columna (que sería igual en ambas filas al
   compartir los mismos tracks) y sin tocar el DOM. Solo desktop, según pedido
   explícito del cliente. */
@media screen and (min-width: 992px) {
  .card-feature_row {
    grid-template-columns: repeat(5, 1fr);
  }
  .card-feature_row > *:nth-child(1) { grid-column: 1 / 3; }
  .card-feature_row > *:nth-child(2) { grid-column: 3 / 6; }
  .card-feature_row > *:nth-child(3) { grid-column: 1 / 4; }
  .card-feature_row > *:nth-child(4) { grid-column: 4 / 6; }
}

/* Ronda 13 (revisión Figma, node 6240:621): la grilla de 7 "Challenges" de
   what-we-do (.challenges-grid-container, 2 columnas x 4 filas, sin ninguna
   clase de borde propia en Webflow) necesita líneas punteadas marcadas
   separando el contenido — 1 vertical de borde a borde entre columnas y
   horizontales entre filas.
   La vertical es un hijo de grid con position:absolute (sale del flujo del
   grid, se posiciona relativo al contenedor con position:relative).
   Las horizontales NO pueden ser elementos de grid con grid-column:1/-1: un
   primer intento así rompía el layout — un grid item con AMBOS ejes
   (fila+columna) explícitos ocupa la fila completa y el algoritmo de
   auto-placement de CSS Grid evita colocar ahí las cards auto-posicionadas,
   empujándolas a filas implícitas nuevas (confirmado con getBoundingClientRect:
   aparecían 3 filas de 0px extra y las cards 3-7 se corrían todas hacia
   abajo). Se resuelve con un ::after por card (border-bottom con el mismo
   patrón punteado, vía nth-child para excluir la última card de cada
   columna) — no participa del layout de grid en absoluto. */
/* Corrección del cliente (2 rondas): 1) se probó que la vertical recorriera
   toda la sección (overlay hermano del contenido) — no gustó, se revirtió a
   estar acotada al propio grid (no debe llegar hasta el tope de la sección,
   solo cubrir el grid hacia abajo). 2) las horizontales deben ir centradas
   en el espacio (gap) entre filas, no pegadas al borde inferior de la card:
   `bottom` usa la mitad del gap real del grid (mismo var que
   `.challenges-grid-container` ya usa para su propio gap) en vez de 0. */
.challenges-grid-container {
  position: relative;
}
.solutions_v-line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
}
.challenge-card-container {
  position: relative;
}
.challenge-card-container:not(:nth-last-child(-n+2))::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(var(--_ui-styles---spacing-padding--space-xl) / -2);
  height: 1px;
  background-image: repeating-linear-gradient(
    90deg,
    rgba(255, 255, 255, 0.32) 0,
    rgba(255, 255, 255, 0.32) 8px,
    transparent 8px,
    transparent 16px
  );
}
/* Nota: `:not(:nth-last-child(-n+2))` (en vez de excluir por número fijo de
   card) excluye SIEMPRE a las últimas 2 cards del DOM — en un grid de 2
   columnas row-major eso es exactamente "la última de cada columna", sea cual
   sea el total (par o impar). Válido tanto para las 7 challenges fijas de
   este grid como para `.faq12_grid-list` más abajo, cuyo total depende del
   CMS y puede cambiar. */

/* Ronda 14: /support/faqs (.faq12_grid-list) pedido explícito del cliente
   con el mismo estilo de líneas que Solutions — reemplaza el borde propio de
   Webflow en cada card (`.collection-item-faqs { border: 1px solid ... }`,
   que dibujaba una grilla de recuadros) por el mismo patrón de líneas
   punteadas centradas en el gap + 1 vertical al medio, acotada al grid (no a
   toda la sección, mismo criterio ya corregido en Solutions). */
.faq12_grid-list {
  position: relative;
  column-gap: var(--_ui-styles---spacing-padding--space-xl);
  row-gap: var(--_ui-styles---spacing-padding--space-xl);
}
.faq12_v-line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
}
.collection-item-faqs {
  position: relative;
  border: none;
}
.collection-item-faqs:not(:nth-last-child(-n+2))::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(var(--_ui-styles---spacing-padding--space-xl) / -2);
  height: 1px;
  background-image: repeating-linear-gradient(
    90deg,
    rgba(255, 255, 255, 0.32) 0,
    rgba(255, 255, 255, 0.32) 8px,
    transparent 8px,
    transparent 16px
  );
}
@media screen and (max-width: 767px) {
  .faq12_v-line {
    display: none;
  }
  /* A ≤767px `.faq12_grid-list` colapsa a 1 columna (regla real de
     mentaexperts.webflow.css) — ahí solo el ítem verdaderamente último debe
     quedar sin línea, no los últimos 2 (esa exclusión es para 2 columnas). */
  .collection-item-faqs:nth-last-child(2)::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(var(--_ui-styles---spacing-padding--space-xl) / -2);
    height: 1px;
    background-image: repeating-linear-gradient(
      90deg,
      rgba(255, 255, 255, 0.32) 0,
      rgba(255, 255, 255, 0.32) 8px,
      transparent 8px,
      transparent 16px
    );
  }
}

/* Grid "Why Webflow" de about-us (.grid-5x3): mismo bug de node-IDs rotos
   que .card-feature_row/.cta-stats-grid, pero acá el auto-placement por
   defecto queda peor porque la grilla real es 5 columnas x 3 filas
   (3 cards arriba, línea vertical de separación en col 2 y 4 que atraviesa
   las 3 filas, línea horizontal de separación en la fila del medio bajo
   cada card de arriba, 3 cards abajo) — sin placement explícito, los
   divisores empujan las cards 4/5 a la fila de 1px (invisibles/aplastadas)
   y la card 6 queda sola. Se ubica cada hijo a mano según el orden real del
   markup. Solo desktop/tablet: el breakpoint de 767px de
   mentaexperts.webflow.css ya cambia esta grilla a 1 sola columna. */
@media screen and (min-width: 768px) {
  .grid-5x3 > *:nth-child(1) { grid-column: 1; grid-row: 1; }
  .grid-5x3 > *:nth-child(2) { grid-column: 2; grid-row: 1 / 4; }
  .grid-5x3 > *:nth-child(3) { grid-column: 3; grid-row: 1; }
  .grid-5x3 > *:nth-child(4) { grid-column: 4; grid-row: 1 / 4; }
  .grid-5x3 > *:nth-child(5) { grid-column: 5; grid-row: 1; }
  .grid-5x3 > *:nth-child(6) { grid-column: 1; grid-row: 2; }
  .grid-5x3 > *:nth-child(7) { grid-column: 3; grid-row: 2; }
  .grid-5x3 > *:nth-child(8) { grid-column: 5; grid-row: 2; }
  .grid-5x3 > *:nth-child(9) { grid-column: 1; grid-row: 3; }
  .grid-5x3 > *:nth-child(10) { grid-column: 3; grid-row: 3; }
  .grid-5x3 > *:nth-child(11) { grid-column: 5; grid-row: 3; }
}

/* Grid "What to expect" de contact (.grid-5x2): mismo bug, 5 columnas x 2
   filas (3 cards de proceso + 2 divisores verticales en la fila 1, footer
   de ancho completo con nota "No Strings Attached" en la fila 2). Sin
   placement explícito el footer cae en 1 de las 5 columnas (angosto) en vez
   de ocupar todo el ancho. */
@media screen and (min-width: 768px) {
  .grid-5x2 > *:nth-child(1) { grid-column: 1; grid-row: 1; }
  .grid-5x2 > *:nth-child(2) { grid-column: 2; grid-row: 1; }
  .grid-5x2 > *:nth-child(3) { grid-column: 3; grid-row: 1; }
  .grid-5x2 > *:nth-child(4) { grid-column: 4; grid-row: 1; }
  .grid-5x2 > *:nth-child(5) { grid-column: 5; grid-row: 1; }
  .grid-5x2 > *:nth-child(6) { grid-column: 1 / -1; grid-row: 2; }
}

/* Ronda 13 (revisión Figma, node 6261:2114): línea vertical continua (sólida,
   no punteada — a diferencia de las líneas de FAQ/Solutions) separando la
   imagen de "Not Seeing Your Industry Listed?" del texto/CTA a la derecha.
   Reutiliza `.line-vertical` (clase real de Webflow, ya usada en otras
   partes del sitio) + el mismo sistema de reveal-on-scroll `[data-line]` que
   el resto de líneas del sitio. `.layout1_content` ya colapsa a 1 columna
   ≤991px (regla real de mentaexperts.webflow.css), así que la línea solo
   debe existir en desktop — pedido explícito del cliente. */
.layout1_content {
  position: relative;
}
.layout1_v-line {
  display: none;
}
@media screen and (min-width: 992px) {
  .layout1_v-line {
    display: block;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
  }
}

/* Ronda 13 (revisión Figma, node 6293:3187): la línea vertical de
   "Challenges We Help You Solve" (industrias/[slug]) ya estaba en el markup
   (`.line-vertical-extended-container > [data-line="vertical"].line-vertical`,
   ubicada correctamente en la columna de 1px dedicada a la línea vertical de
   `.challenges_industries-content`, grid-template-columns: 1fr 1px 1fr) y ya
   tenía el mismo sistema de reveal-on-scroll que la horizontal — pero
   `.line-vertical-extended-container` no es una clase real de Webflow (0
   reglas en ningún CSS capturado) y quedaba sin altura: `.line-vertical` es
   height:100%, pero de un contenedor con height:auto eso resuelve a 0, así
   que la línea existía en el DOM pero era invisible. No hacía falta ningún
   cambio de markup, solo esta regla de altura. */
.line-vertical-extended-container {
  height: 100%;
}

/* Grid "Challenges We Help You Solve" de industrias (.challenges_industries-content):
   mismo bug de node-IDs rotos, 3 columnas x 3 filas (2 cards arriba, divisor
   vertical en col2 que atraviesa las 3 filas, 2 divisores horizontales en la
   fila del medio bajo cada card de arriba, 2 cards abajo). Las 19 industrias
   tienen siempre 4 challenges (confirmado contra Sanity), así que el
   placement fijo aplica siempre. */
@media screen and (min-width: 768px) {
  .challenges_industries-content > *:nth-child(1) { grid-column: 1; grid-row: 1; }
  .challenges_industries-content > *:nth-child(2) { grid-column: 2; grid-row: 1 / 4; }
  .challenges_industries-content > *:nth-child(3) { grid-column: 3; grid-row: 1; }
  .challenges_industries-content > *:nth-child(4) { grid-column: 1; grid-row: 2; }
  .challenges_industries-content > *:nth-child(5) { grid-column: 3; grid-row: 2; }
  .challenges_industries-content > *:nth-child(6) { grid-column: 1; grid-row: 3; }
  .challenges_industries-content > *:nth-child(7) { grid-column: 3; grid-row: 3; }
}

/* Portfolio: la etiqueta de industria no desbordaba por overflow de texto —
   la causa real es que ".portfolio-thumbnail" no tenía NINGUNA regla de
   ancho en ninguna hoja CSS (ni siquiera de Webflow), así que el <img> se
   pintaba a su ancho intrínseco (según el "width" pedido a la Image API de
   Sanity) en vez de llenar la columna, quedando más angosto que el resto
   de la card — por eso el texto de abajo (que sí ocupa el 100%) parecía
   "salirse" del borde derecho de la imagen.
   El grid asimétrico real (columnas 1-9/11-22, alturas variables por
   posición) SÍ existe: es un Embed de Webflow en el HTML de la página
   Portfolio/Home ("code-portfolio-grid-masonry", no capturado en ninguna
   hoja .css ni por la Data API) — portado 1:1 acá. */
:root {
  --portfolio-tall-img: 557px;
  --portfolio-short-img: 438px;
  --portfolio-mob-img: 380px;
}
.portfolio_collection-list {
  display: flex;
  flex-direction: column;
  gap: 32px;
}
.portfolio_collection-list .portfolio-thumbnail {
  height: var(--portfolio-mob-img);
  width: 100%;
  display: block;
  object-fit: cover;
}
@media screen and (min-width: 768px) {
  .portfolio_collection-list {
    display: grid;
    grid-template-columns: repeat(21, 1fr);
    grid-auto-rows: auto;
    column-gap: 0;
    row-gap: 0;
    gap: 0;
  }
  .portfolio_collection-list > .w-dyn-item:nth-child(4n+1) {
    grid-column: 1 / 10;
  }
  .portfolio_collection-list > .w-dyn-item:nth-child(4n+2) {
    grid-column: 11 / 22;
  }
  .portfolio_collection-list > .w-dyn-item:nth-child(4n+3) {
    grid-column: 1 / 12;
  }
  .portfolio_collection-list > .w-dyn-item:nth-child(4n+4) {
    grid-column: 13 / 22;
  }
  .portfolio_collection-list > .w-dyn-item:nth-child(4n+1) .portfolio-thumbnail,
  .portfolio_collection-list > .w-dyn-item:nth-child(4n+4) .portfolio-thumbnail {
    height: var(--portfolio-tall-img);
  }
  .portfolio_collection-list > .w-dyn-item:nth-child(4n+2) .portfolio-thumbnail,
  .portfolio_collection-list > .w-dyn-item:nth-child(4n+3) .portfolio-thumbnail {
    height: var(--portfolio-short-img);
  }
}

/* Hero de detalle de portfolio con video (Bunny): los videos son 16:9 nativos;
   con el aspect-ratio 3/2 heredado de .big-img-portfolio se recortaban los
   lados (object-fit: cover). Pedido del cliente 2026-07-27: mismo ancho, alto
   a 16:9 para ver el video completo. Scoped al elemento <video> — los
   proyectos que solo tienen foto conservan el 3/2 original de Webflow. */
video.big-img-portfolio {
  aspect-ratio: 16 / 9;
}

/* CTA "Get started" (.cta-stats-grid): mismo problema que .card-feature_row
   — el grid real es 1fr 3px 1fr / auto 3px auto (2x2 stats + cruz de
   separadores de 3px), pero depende de placement por nodo que no existe acá.
   Sin placement explícito, el auto-flow por fila mete los stats 3 y 4 en la
   fila angosta de 3px pensada para el separador horizontal. Se ubica cada
   hijo a mano según el orden real del markup (2 stats, línea vertical, 2
   stats, línea horizontal). */
.cta-stats-grid > *:nth-child(1) { grid-column: 1; grid-row: 1; }
.cta-stats-grid > *:nth-child(2) { grid-column: 2; grid-row: 1 / span 3; }
.cta-stats-grid > *:nth-child(3) { grid-column: 3; grid-row: 1; }
.cta-stats-grid > *:nth-child(4) { grid-column: 1; grid-row: 3; }
.cta-stats-grid > *:nth-child(5) { grid-column: 3; grid-row: 3; }
.cta-stats-grid > *:nth-child(6) { grid-column: 1 / -1; grid-row: 2; }

/* FAQ: fix de la Ronda 5 fue un color sólido de mejor esfuerzo (no se había
   encontrado la regla real todavía). Corregido 2026-07-20: la real es el
   patrón punteado del embed de arriba, no un color sólido. */
.dashed-line-h {
  height: var(--line-thickness);
  background-image: repeating-linear-gradient(
    90deg,
    var(--dash-color) 0,
    var(--dash-color) var(--dash-length),
    transparent var(--dash-length),
    transparent calc(var(--dash-length) + var(--gap-length))
  );
}

/* ----- Pulsing status dot (usado en trust-bar y section_problem) ----- */
.status-dot {
  --dot-size: 10px;
  position: relative;
  width: var(--dot-size);
  height: var(--dot-size);
  border-radius: 50%;
  background-color: var(--_primitives---colors--menta);
  flex-shrink: 0;
}
.status-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background-color: var(--_primitives---colors--menta);
  opacity: 0;
  animation: glow-pulse 2.5s ease-out infinite;
  will-change: transform, opacity;
}
@keyframes glow-pulse {
  0% { transform: scale(1); opacity: 0.6; }
  100% { transform: scale(2.4); opacity: 0; }
}

/* ----- Nota Ronda 7 sobre las líneas del mega menú -----
   Rondas 5-6 agregaron por error líneas VERTICALES entre columnas (mala
   interpretación del pedido). El pedido real siempre fue líneas
   HORIZONTALES separando cada servicio/industria DENTRO de cada columna.
   Causa real de por qué no se veían: el panel del megamenú (fullscreen) se
   había portado con clases obsoletas `.navbar_dropdown-link-2` /
   `.line-horizontal-2` (de una captura vieja del sitio) que NO tienen
   ninguna regla CSS en ningún archivo. El sitio publicado HOY reutiliza las
   mismas clases reales del dropdown compacto: `.navbar_dropdown-link` /
   `.line-horizontal` (con CSS real y funcional, confirmado con
   getComputedStyle contra mentaexperts.webflow.io). Corregido en
   Navbar.astro — ya no hace falta ningún CSS propio acá, las líneas
   funcionan solas con las clases reales. */

/* ----- Fondo espacial de section_cta ("Ready to stop leaving deals...") -----
   Embed real de Webflow encontrado en el export fresco de Home ("MENTA
   GRADIENT + NOISE + STARS BACKGROUND v2"), no capturado antes por la Data
   API. Mismo sistema que TestimonialMesh.astro (v3: mesh + gradiente) pero
   sin la malla en perspectiva — acá es solo gradiente radial + noise +
   estrellas. Portado 1:1 (posiciones/colores de cada estrella tal cual el
   embed). */
.menta-space-bg-v2 {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background: radial-gradient(
    ellipse at 15% 90%,
    #0b3f36 0%,
    #072320 30%,
    #041210 55%,
    #020807 80%,
    #010403 100%
  );
}
.menta-space-bg-v2::after {
  content: "";
  position: absolute;
  inset: -5%;
  width: 110%;
  height: 110%;
  opacity: 0.1;
  filter: url(#noiseFilter2);
  pointer-events: none;
}
/* Estrellas de los fondos espaciales. El markup lo genera StarField.astro y
   solo lleva la posición (única por estrella) + la opacidad; tamaño y color
   salen de acá vía data-attrs, para no repetir px y rgba() en el markup.
   Antes esto eran 125 <div> con style inline copiados en 11 archivos. */
.menta-star {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  width: 1px;
  height: 1px;
  background: #fff;
}
.menta-star[data-star-size="2"] {
  width: 2px;
  height: 2px;
}
/* Celeste propio de este fondo (no es un color de marca, no está en el design
   system): las estrellas grandes lo usan para separarse del blanco puro. */
.menta-star[data-star-tint="mint"] {
  background: rgb(200, 240, 230);
}

/* Fondo del hero v2 (páginas de detalle de portfolio). Embed real "MENTA
   BLACK + NOISE BACKGROUND (v4)": gradiente diagonal casi negro + noise,
   sin estrellas ni mesh — encontrado re-verificando contra el sitio
   publicado (el export estático de detail_portfolio-projects.html estaba
   desactualizado: usaba el hero v1 genérico con breadcrumb, cuando el
   template real ya usa este v2 con imagen grande del proyecto). */
.menta-dark-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background: linear-gradient(135deg, #010101 0%, #040404 30%, #0a0a0a 65%, #111 100%);
}
.menta-dark-bg::after {
  content: "";
  position: absolute;
  inset: -5%;
  width: 110%;
  height: 110%;
  opacity: 0.08;
  filter: url(#noiseFilter4);
  pointer-events: none;
}

/* Item activo del sidebar de contenido en detalle de portfolio (ver
   site.js: IntersectionObserver sobre [data-section]). Mismo tono de
   "activo" que ya usa el sitio real en otros lados (.navbar_dropdown-link.
   w--current), no un color inventado. */
[data-scroll-to].is-active {
  color: var(--_primitives---colors--menta);
}

/* Variante sin estrellas del fondo espacial (tarjetas de servicio en
   what-we-do y otras). Embed real "MENTA GRADIENT + NOISE BACKGROUND"
   (gradiente radial centrado a 70% 50% + noise, sin estrellas). */
.menta-space-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background: radial-gradient(
    ellipse at 70% 50%,
    #0a3d35 0%,
    #071f1b 40%,
    #030d0b 80%,
    #010504 100%
  );
}
.menta-space-bg::after {
  content: "";
  position: absolute;
  inset: -5%;
  width: 110%;
  height: 110%;
  opacity: 0.12;
  filter: url(#noiseFilter);
  pointer-events: none;
}

/* ----- Modal "Request a proposal" -----
   .contact-modal4_component es display:none por defecto en el CSS real
   (Webflow lo abre con una interacción nativa IX2 que no se captura por
   API). Ver public/js/site.js: togglea la clase .is-open.
   Ronda 6: el cliente pidió una entrada más lenta/sutil, deslizando de
   derecha a izquierda. Para poder animar (un toggle de display:none no
   dispara transiciones), se deja el componente siempre renderizado pero
   oculto con visibility/pointer-events, y se anima translateX del panel
   de contenido + opacity del overlay. La visibility se retrasa al cerrar
   (transition-delay) para que la salida alcance a animarse. */
.contact-modal4_component {
  display: flex;
  visibility: hidden;
  pointer-events: none;
  transition: visibility 0s linear 0.55s;
}
.contact-modal4_component.is-open {
  visibility: visible;
  pointer-events: auto;
  transition: visibility 0s linear 0s;
}
.contact-modal4_content-wrapper {
  transform: translateX(100%);
  transition: transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform;
}
.contact-modal4_component.is-open .contact-modal4_content-wrapper {
  transform: translateX(0);
}
.contact-modal4_background-overlay {
  opacity: 0;
  transition: opacity 0.55s ease;
}
.contact-modal4_component.is-open .contact-modal4_background-overlay {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .contact-modal4_content-wrapper,
  .contact-modal4_background-overlay {
    transition: none;
  }
}

/* ----- Breadcrumbs (páginas de detalle de servicios/industrias) -----
 * Mismo patrón de "Embed suelto no capturado por la API" ya documentado
 * varias veces en el playbook: .breadcrumb_list/.breadcrumb_item no tenían
 * NINGUNA regla en ningún CSS capturado, así que caían a bloque (cada item
 * se apilaba verticalmente en vez de una fila). CSS real recuperado del
 * <style> embebido en detail_services.html (export fresco), portado 1:1. */
.breadcrumb_list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  list-style: none;
  padding: 0;
  margin: 0;
  gap: 0;
}
.breadcrumb_item {
  display: flex;
  align-items: center;
}
.breadcrumb_item:not(:last-child)::after {
  content: "/";
  margin: 0 0.5rem;
  color: rgba(255, 255, 255, 0.8);
}
.breadcrumb_item,
.breadcrumb_item[aria-current="page"] {
  color: rgba(255, 255, 255, 0.8);
}
/* Hover de los breadcrumbs clickeables: mismo gesto que los links del footer
   ([data-gsap="hover-links"]: transform 0.25s ease, 5.34px medidos en vivo),
   pero hacia ARRIBA en vez de a la derecha (pedido del usuario). Va sobre
   .breadcrumb_link, que solo existe en los niveles enlazados — el último
   item (aria-current="page") es un <div> sin <a>, así que queda fuera solo. */
.breadcrumb_link {
  transition: transform 0.25s ease;
}
.breadcrumb_link:hover {
  transform: translateY(-5.34px);
}
@media (prefers-reduced-motion: reduce) {
  .breadcrumb_link {
    transition: none;
  }
  .breadcrumb_link:hover {
    transform: none;
  }
}

/* ----- Ancla de scroll para secciones con id (ej. /what-we-do#web-dev
 * enlazado desde el 3er nivel de breadcrumbs de servicios). El navbar es
 * fixed (min-height 4.5rem + margin-top 12px ≈ 84px); se deja un colchón
 * extra para que el título no quede pegado al borde. Patrón general: toda
 * sección que sea destino de un enlace con #ancla debe llevar esta clase
 * (o repetir esta regla) para no quedar oculta bajo el navbar. */
.service-big_card-wrapper {
  scroll-margin-top: 7rem;
}

/* ----- Sección "Recognition & Partnerships" de /portfolio (nueva sección,
 * sin equivalente en Webflow — pedido del cliente Ronda 13, viene del Figma
 * node 6293:3629 y todavía no existe en el sitio publicado, así que no hay
 * clases reales que portar; se construye con los tokens de tipografía/color
 * ya existentes en el sitio (heading-style-h3, text-color-gray, text-size-*,
 * tag-title/status-dot) y solo un puñado de clases propias para el layout de
 * 2 columnas, ya que no hay ningún componente reusable existente que calce. */
.recognition_row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--_ui-styles---spacing-padding--space-xl);
}
.recognition_left {
  flex: 0 0 auto;
  max-width: 26rem;
}
.recognition_right {
  flex: 1 1 0%;
  max-width: 40rem;
}
.recognition_list {
  margin-top: var(--_ui-styles---spacing-padding--space-lg);
}
.recognition_item {
  padding-top: var(--_ui-styles---spacing-padding--space-md);
  padding-bottom: var(--_ui-styles---spacing-padding--space-md);
  border-top: var(--_ui-styles---stroke--stroke-thin) solid var(--_primitives---opacity--white-40);
}
.recognition_item-top {
  display: flex;
  align-items: center;
  gap: var(--_ui-styles---spacing-padding--space-sm);
  margin-bottom: var(--_ui-styles---spacing-padding--space-xs);
}
.recognition_logo {
  width: 2.5rem;
  height: 2.5rem;
  object-fit: contain;
  flex: none;
}
@media screen and (max-width: 767px) {
  .recognition_row {
    flex-direction: column;
  }
  .recognition_left,
  .recognition_right {
    max-width: 100%;
  }
}

/* ----- Card de formulario inline en /contact (nueva sección, sin equivalente
 * en el export de Webflow — pedido del cliente 2026-07-21). Se monta sobre
 * el borde inferior del Hero con margin-top negativo. Este diseño no usa
 * bordes contorneados en ningún elemento (ni borde visible ni esquinas
 * redondeadas: border-radius: 0), así que no lleva `border` ni radio; el
 * fondo espacial (.embed-background > .menta-space-bg-v2, mismo patrón que
 * section_contact-info/about-us founder) se combina con el glass existente:
 * el overlay translúcido + backdrop-filter quedan encima de las estrellas. */
.section_contact-form-inline {
  position: relative;
  z-index: 3;
  margin-top: -7rem;
}
.contact-form-card {
  position: relative;
  overflow: hidden;
  background-color: rgba(255, 255, 255, 0.06);
  border-radius: 0;
  -webkit-backdrop-filter: blur(20px) saturate(1.8);
  backdrop-filter: blur(20px) saturate(1.8);
  padding: 3rem;
}
.contact-form-card > *:not(.embed-background) {
  position: relative;
  z-index: 1;
}
@media (max-width: 767px) {
  .section_contact-form-inline {
    margin-top: -3rem;
  }
  .contact-form-card {
    padding: 1.5rem;
  }
}

/* ==========================================================================
   Página /blog (listado) — diseño propio (Figma "Blogs | Default", nunca
   existió en Webflow, ver auditoría Fase 0 §8-D1). Reusa las clases del
   sistema (hero_bg-image-wrapper, hero_content, tag-title, heading-style-h5,
   text-size-*, text-color-*, .button, variables --_primitives--- etc.) donde
   aplican — ver CLAUDE.md "Reusar el design system": nunca se inventan
   tamaños/colores nuevos si ya existe un token que se acerque. Lo que queda
   acá abajo es SOLO estructura/layout específico de este componente nuevo
   (grid, dropdown, paginación) que no tiene equivalente existente. */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ----- Hero -----
   Altura fija (no hero_content min-height:100svh de las demás páginas):
   decisión de layout propia del diseño de Figma, sin equivalente existente
   que reusar — el resto de los valores de esta sección sí vienen del
   sistema (colores, tipografía vía clases en el .astro). */
.blog-hero {
  position: relative;
  overflow: hidden;
  background-color: var(--_primitives---colors--black-menta);
}
.blog-hero .hero_content {
  min-height: 34rem;
  max-height: none;
}
.blog-newsletter_form {
  display: flex;
  align-items: stretch;
  gap: 1rem;
  max-width: 34rem;
}
.blog-newsletter_field {
  flex: 1 0 0;
  border-bottom: var(--_ui-styles---stroke--stroke-thin) solid var(--_primitives---opacity--white-40);
}
.blog-newsletter_input {
  width: 100%;
  height: 100%;
  padding: 0.75rem 0;
  background: none;
  border: none;
}
.blog-newsletter_input::placeholder {
  color: var(--_primitives---opacity--white-40);
}
.blog-newsletter_input:focus {
  outline: none;
}
/* Reusa .button (misma clase que Button.astro) para heredar el estilo real
 * de botón del sistema — solo se agrega el estado disabled, que no tiene
 * token propio en ningún otro lado del sitio (es el único botón inerte). */
.blog-newsletter_submit:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

/* ----- Main: filtros + grid ----- */
.blog-main {
  position: relative;
  background-color: var(--_primitives---colors--black-menta);
  padding-bottom: 2rem;
}
.blog-filters {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  padding: 1.5rem 0;
  margin-bottom: 2rem;
  border-top: var(--_ui-styles---stroke--stroke-thin) solid var(--_primitives---opacity--white-40);
}

/* Barra de filtros sticky bajo el navbar fijo.
 * Solo desde 768px: por debajo la barra pasa a columna (ver el @media de
 * abajo) y mide 114-165px — pegada ocuparía casi un tercio del viewport
 * móvil, así que ahí se queda en el flujo.
 * `top` reutiliza --blog-nav-offset (6.5rem), el mismo despeje del navbar
 * flotante que ya usan la barra de progreso y la sidebar del artículo: deja
 * ~18px de aire bajo el navbar (que mide 86px hasta su borde inferior).
 * El fondo es obligatorio: sin él las cards se verían por debajo al pasar. */
@media screen and (min-width: 768px) {
  .blog-filters {
    position: sticky;
    top: var(--blog-nav-offset);
    z-index: 6;
    background-color: var(--_primitives---colors--black-menta);
  }
  /* Tapa la rendija entre el borde inferior del navbar y el tope de la barra
     (18px a >=1400px, 20px entre 768 y 1399): sin esto se veían pasar trozos
     de las cards por ese hueco. 1.25rem cubre el caso peor y lo que sobra
     queda detrás del navbar. Sin estar pegada es invisible: mismo color que
     el fondo de .blog-main, sobre el que se apoya. */
  .blog-filters::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    /* +stroke-thin para arrancar por ENCIMA del border-top de la barra: los
       % de `bottom` se resuelven contra la caja de padding, así que un 100%
       pelado dejaba el pseudo-elemento pintando sobre el borde y lo borraba. */
    bottom: calc(100% + var(--_ui-styles---stroke--stroke-thin));
    height: 1.25rem;
    background-color: var(--_primitives---colors--black-menta);
    pointer-events: none;
  }
}
.blog-filters_left,
.blog-filters_right {
  display: flex;
  align-items: center;
  gap: 2rem;
  flex-wrap: wrap;
}

.blog-dropdown {
  position: relative;
}
.blog-dropdown_toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: none;
  border: none;
  color: inherit;
  cursor: pointer;
}
.blog-dropdown_toggle svg {
  transition: transform 0.15s ease;
}
.blog-dropdown.is-open .blog-dropdown_toggle {
  color: var(--_primitives---colors--white);
}
.blog-dropdown.is-open .blog-dropdown_toggle svg {
  transform: rotate(180deg);
}
.blog-dropdown_panel {
  display: none;
  position: absolute;
  top: calc(100% + 0.75rem);
  left: 0;
  z-index: 5;
  min-width: 14rem;
  max-height: 18rem;
  overflow-y: auto;
  padding: 0.5rem;
  background-color: var(--_primitives---colors--black-darker);
  border: var(--_ui-styles---stroke--stroke-thin) solid var(--_primitives---opacity--white-15);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
.blog-dropdown_panel.is-right {
  left: auto;
  right: 0;
}
.blog-dropdown.is-open .blog-dropdown_panel {
  display: block;
}
.blog-dropdown_option {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  width: 100%;
  padding: 0.625rem 0.75rem;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
}
.blog-dropdown_option:hover,
.blog-dropdown_option.is-active {
  color: var(--_primitives---colors--white);
  background-color: var(--_primitives---opacity--white-5);
}
.blog-cat-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
/* SVG incrustado inline (set:html, ver getInlineIconSvg en sanity.ts) en vez
 * de <img src>: los SVG de Sanity no traen CORS headers, así que un <img>
 * referenciado por URL no puede recolorearse por CSS. El fondo/texto de Tags
 * al seleccionar usa el mismo tinte sutil que Category (regla compartida de
 * arriba) — el único indicador extra de "seleccionado" es el ícono, que pasa
 * de blanco (original del SVG) a verde de marca. */
.blog-tag-icon {
  display: inline-flex;
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}
.blog-tag-icon svg {
  display: block;
  width: 100%;
  height: 100%;
}
.blog-dropdown_option.blog-tag-option.is-active .blog-tag-icon path {
  fill: var(--_primitives---colors--menta);
}

.blog-search {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.blog-search_icon {
  display: flex;
  align-items: center;
  cursor: pointer;
}
.blog-search_input {
  width: 9rem;
  background: none;
  border: none;
}
.blog-search_input::placeholder {
  color: var(--_primitives---opacity--white-50);
}
.blog-search_input:focus {
  outline: none;
}

.blog-filters_active {
  display: flex;
  align-items: center;
  gap: 1.5rem;
}
.blog-filters_clear {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
}

.blog-results-line {
  display: flex;
  align-items: center;
  gap: 2rem;
  margin-bottom: 2rem;
}
.blog-results-line .line-horizontal {
  flex: 1 0 0;
  width: auto;
}
.blog-results-line p {
  white-space: nowrap;
}

/* ----- Grid de tarjetas ----- */
.blog-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2rem 1.5rem;
}
.blog-grid[hidden] {
  display: none;
}
.blog-card {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}
.blog-card[hidden] {
  display: none;
}
.blog-card_image {
  position: relative;
  display: block;
  aspect-ratio: 600 / 272;
  overflow: hidden;
  background-color: var(--_primitives---opacity--white-5);
}
.blog-card_img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.4s ease;
}
.blog-card:hover .blog-card_img {
  transform: scale(1.04);
}
.blog-card_cat {
  position: absolute;
  right: 1rem;
  bottom: 1rem;
  left: 1rem;
  display: inline-flex;
  align-self: flex-end;
  margin-left: auto;
  width: fit-content;
  padding: 0.25rem 0.75rem;
  background-color: var(--_primitives---opacity--white-10);
  border: var(--_ui-styles---stroke--stroke-thin) solid var(--_primitives---opacity--white-40);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  opacity: 0.8;
}
.blog-card_body {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.blog-card_meta {
  display: flex;
  align-items: center;
  gap: 1rem;
}
.blog-card_dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background-color: var(--_primitives---colors--white);
  flex-shrink: 0;
}
.blog-card_title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.blog-card:hover .blog-card_title {
  color: var(--_primitives---colors--menta);
}

.blog-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2rem;
  padding: 3rem 0;
}
.blog-empty[hidden] {
  display: none;
}
.blog-empty_illustration {
  width: 19.25rem;
  max-width: 100%;
  height: auto;
}
.blog-empty_copy {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
}

/* ----- Paginación ----- */
.blog-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.5rem 0;
  margin-top: 1rem;
  border-top: var(--_ui-styles---stroke--stroke-thin) solid var(--_primitives---opacity--white-40);
}
.blog-pagination_numbers {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.blog-pagination_numbers button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.8rem;
  height: 1.5rem;
  background: none;
  border: 1px solid transparent;
  border-radius: 4px;
  cursor: pointer;
}
.blog-pagination_numbers button.is-active {
  border-color: var(--_primitives---opacity--white-20);
  color: var(--_primitives---colors--white);
}
.blog-pagination_arrows {
  display: flex;
  align-items: center;
  gap: 2rem;
}
.blog-pagination_arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.5rem;
  background: none;
  border: var(--_ui-styles---stroke--stroke-thin) solid var(--_primitives---opacity--white-40);
  border-radius: 999px;
  color: var(--_primitives---colors--white);
  cursor: pointer;
}
.blog-pagination_arrow:disabled {
  opacity: 0.32;
  cursor: not-allowed;
}

@media (max-width: 991px) {
  .blog-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 767px) {
  .blog-hero .hero_content {
    min-height: 28rem;
  }
  .blog-newsletter_form {
    flex-direction: column;
    max-width: none;
  }
  .blog-newsletter_submit {
    width: 100%;
  }
  .blog-filters {
    flex-direction: column;
    align-items: flex-start;
  }
  .blog-grid {
    grid-template-columns: 1fr;
  }
  .blog-pagination {
    flex-wrap: wrap;
    gap: 1rem;
  }
}

/* ================= Blog article (/blog/[slug] + /es/blog/[slug]) =================
 * Layout/estructura de la plantilla de artículo. Solo reglas de layout,
 * bordes y fondos con primitivas ya existentes (--_primitives---*): la
 * tipografía/colores de texto se componen con las clases del design system
 * (heading-style-*, text-size-*, text-color-*) directo en el markup, no acá.
 * --blog-nav-offset ≈ alto del navbar flotante (min-height 4.5rem + su
 * margin-top): usado por la barra de progreso fija, la sidebar sticky y el
 * scroll-margin-top de los H2 (anclas del TOC). */
:root { --blog-nav-offset: 6.5rem; }

/* ----- Reading progress bar -----
 * Parte en el flujo normal, justo debajo del hero, y se pega bajo el navbar
 * fijo al hacer scroll (position:sticky). El navbar del sitio es position:fixed
 * flotante, así que este strip no queda cubierto: sticky lo fija en
 * --blog-nav-offset (~alto del navbar) mientras el artículo está en pantalla. */
.blog-progress {
  position: sticky;
  top: var(--blog-nav-offset);
  height: 3px;
  z-index: 40;
  background: var(--_primitives---opacity--white-10);
  pointer-events: none;
}
.blog-progress_bar {
  width: 0;
  height: 100%;
  background: var(--_primitives---colors--menta);
  transition: width 0.1s linear;
}

/* El hero contiene el glow menta (data-glow) y la imagen: relative + overflow
 * para acotarlos a la sección (que la imagen/glow no se salgan del hero). */
.blog-article_hero { position: relative; overflow: hidden; }
.blog-article_hero > .padding-global { position: relative; z-index: 2; }
/* Sin esto, el glow (.background-container, position:absolute; inset:0) de la
 * sección del cuerpo se posiciona respecto al viewport y se derrama ENCIMA del
 * hero (rect top:0), tapándolo con un lavado verde menta. position:relative lo
 * confina a su propia sección. */
.blog-article_main { position: relative; }
/* El glow del cuerpo llenaba toda la altura de la sección (miles de px) y se
 * "estiraba". Se acota a una franja baja fija y sutil (máx 30vh), anclada al
 * fondo de la sección. */
.blog-article_main > .background-container { top: auto; bottom: 0; height: 30vh; }
/* El glow del hero es una franja BAJA (no una banda alta): se acota a la parte
 * inferior, debajo de la imagen. Antes con height:55% la banda subía por detrás
 * del subtítulo/autor y creaba un rectángulo verde con borde duro. Con una
 * altura fija corta (< distancia al tope de la imagen) el glow solo se ve en el
 * espacio bajo la imagen y ya no toca el texto del hero. */
.blog-article_hero > .background-container { top: auto; bottom: 0; height: 18rem; }

/* ----- Barra superior del hero: back link + breadcrumbs (alineada izquierda) -----
 * Es lo primero del hero, así que aquí va el despeje del navbar fijo
 * (--blog-nav-offset) + un respiro estándar. El contenido centrado (hero-inner)
 * ya solo agrega su propio gap debajo de los breadcrumbs. */
.blog-article_hero-top {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1rem;
  padding-top: calc(var(--blog-nav-offset) + 2.5rem);
  text-align: left;
}
.blog-article_back {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  text-decoration: none;
  transition: color 0.2s ease;
}
.blog-article_back:hover { color: var(--_primitives---colors--menta); }
.blog-article_back svg { flex: none; }

/* ----- Hero (centrado, diseño 1b) ----- */
.blog-article_hero-inner {
  max-width: 67.5rem;
  margin: 0 auto;
  padding: 3.5rem 0 0;
  text-align: center;
}
.blog-article_meta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 2rem;
}
.blog-article_meta-cat { letter-spacing: 0.09em; text-transform: uppercase; }
.blog-article_meta-dot { width: 4px; height: 4px; border-radius: 100vw; background: currentColor; opacity: 0.35; }
.blog-article_hero-summary { max-width: 40rem; margin: 0 auto 2rem; text-align: center; }
.blog-article_author { display: flex; align-items: center; justify-content: center; gap: 0.75rem; }
.blog-article_author-avatar {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 100vw;
  object-fit: cover;
  flex: none;
  border: 1px solid var(--_primitives---opacity--white-40);
}
.blog-article_hero-image {
  position: relative;
  width: 100%;
  max-width: 100%;
  margin-top: 4rem;
  /* Espacio debajo de la imagen: el glow del hero nace en la base (bottom),
   * así queda visible DEBAJO de la imagen en vez de oculto tras ella. */
  margin-bottom: 5rem;
  aspect-ratio: 21 / 9;
  overflow: hidden;
}
.blog-article_hero-img { width: 100%; height: 100%; max-width: 100%; object-fit: cover; display: block; }

/* ----- Layout: rail izquierdo (TOC/share) + artículo CENTRADO en la página -----
 * 3 columnas [rail | artículo | gutter vacío] con el mismo ancho a cada lado,
 * así la columna de lectura queda centrada (no pegada a la derecha). El gutter
 * derecho vacío balancea el rail izquierdo. Suma = 15+4+42+4+15 = 80rem
 * (= container-large), así no desborda. */
.blog-article_layout {
  display: grid;
  grid-template-columns: 15rem minmax(0, 42rem) 15rem;
  gap: 4rem;
  justify-content: center;
  align-items: start;
}
/* La sidebar se pega un poco más abajo que la barra de progreso (que también es
 * sticky en --blog-nav-offset), para que el título del TOC no quede pegado a la
 * barra al hacer scroll. */
.blog-article_sidebar { position: sticky; top: calc(var(--blog-nav-offset) + 2.5rem); display: flex; flex-direction: column; gap: 2rem; }

/* ----- Table of contents ----- */
.blog-toc_header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: none;
  border: none;
  padding: 0 0 0.75rem;
  cursor: default;
}
.blog-toc_chevron { display: none; }
/* Desktop shows "Table of contents"; the mobile "On this page" label only
 * appears in the accordion (see the ≤767 block). */
.blog-toc_label-mobile { display: none; }
.blog-toc_list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  border-left: 1px solid var(--_primitives---opacity--white-10);
}
.blog-toc_link {
  display: block;
  padding-left: 1rem;
  margin-left: -1px;
  border-left: 2px solid transparent;
  text-decoration: none;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.blog-toc_link:hover { color: var(--_primitives---colors--white); }
.blog-toc_link.is-active {
  color: var(--_primitives---colors--menta);
  border-left-color: var(--_primitives---colors--menta);
}

/* ----- Share ----- */
.blog-share { display: flex; flex-direction: column; gap: 0.75rem; }
.blog-share.is-mobile { display: none; }
.blog-share_actions { display: flex; align-items: center; gap: 0.5rem; }
.blog-share_btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 100vw;
  border: 1px solid var(--_primitives---opacity--white-15);
  background: var(--_primitives---opacity--white-5);
  color: var(--text-color--gray, #9c9c9c);
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.blog-share_btn:hover { color: var(--_primitives---colors--white); border-color: var(--_primitives---colors--menta); }
.blog-share_copy-feedback {
  position: absolute;
  bottom: calc(100% + 0.4rem);
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  padding: 0.2rem 0.55rem;
  border-radius: 0.4rem;
  background: var(--_primitives---colors--black-darkest, #0d0d0d);
  border: 1px solid var(--_primitives---opacity--white-10);
  color: var(--_primitives---colors--menta);
}

/* El grupo de checkboxes de servicios del formulario pasó de <div> a
   <fieldset> por accesibilidad (ver ContactForm.astro). El navegador le pone
   borde, padding y margen propios: se anulan para que el layout quede igual
   que antes del cambio. */
.form_fieldset-reset {
  border: 0;
  margin: 0;
  padding: 0;
  min-inline-size: 0;
}
.form_fieldset-reset > * {
  /* <legend> es display:block por UA y rompe el flujo del wrapper si no se
     normaliza junto con el resto de los hijos. */
  max-width: 100%;
}

/* El 404 suma un enlace a contacto junto al botón de inicio: sin navbar ni
   footer (es una página bare, como en Webflow) era un callejón sin salida. */
.utility_actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}

/* ----- Foco visible en los disclosures -----
 * site.js convierte los triggers de los acordeones (.faq_question y
 * [data-accordion-trigger]) en role=button + tabindex=0. Sin un anillo de foco
 * propio, el usuario de teclado no tiene forma de saber dónde está parado: el
 * outline por defecto del navegador queda invisible sobre el fondo oscuro.
 * :focus-visible (no :focus) para que el click con mouse no lo dispare. */
.faq_question:focus-visible,
[data-accordion-trigger]:focus-visible {
  outline: 2px solid var(--_primitives---colors--menta);
  outline-offset: 4px;
  border-radius: 4px;
}

/* ----- Article body typography (rendered via set:html) ----- */
.blog-article_content > * + * { margin-top: 1.5rem; }
.blog-article_h2 { scroll-margin-top: var(--blog-nav-offset); margin-top: 3rem; }
.blog-article_h3 { scroll-margin-top: var(--blog-nav-offset); margin-top: 2rem; }
.blog-article_h4 { scroll-margin-top: var(--blog-nav-offset); margin-top: 1.75rem; }
.blog-article_p { line-height: 1.7; }

/* Código: los artículos técnicos traen bloques de código, que el schema no
 * soporta como tipo propio — llegan por htmlEmbed (ver tools/blog/
 * md_to_portable_text.mjs). Se estilan por descendencia con los mismos tokens
 * del resto del cuerpo. El bloque scrollea en horizontal para que una línea
 * larga no rompa el layout en móvil. */
.blog-article_content pre.blog-code {
  margin: 2rem 0;
  padding: 1.25rem 1.4rem;
  overflow-x: auto;
  border-radius: 0.5rem;
  background-color: var(--_primitives---colors--black-darkest, #0d0d0d);
  border: 1px solid var(--_primitives---opacity--white-10);
}
.blog-article_content pre.blog-code code {
  font-size: 0.875rem;
  line-height: 1.65;
  color: var(--_primitives---colors--neutral-lighter-body-text);
  white-space: pre;
}
/* Código dentro de un párrafo: se distingue sin cortar la lectura. */
.blog-article_content code {
  font-size: 0.9em;
  padding: 0.12em 0.35em;
  border-radius: 3px;
  background-color: var(--_primitives---opacity--white-5);
  color: var(--_primitives---colors--menta);
}
.blog-article_content pre.blog-code code {
  padding: 0;
  background: none;
}

/* Descargas al inicio del artículo (htmlEmbed, ver publish_qa_article.mjs). */
.blog-article_content .blog-downloads {
  margin: 0 0 2.5rem;
  padding: 1.25rem 1.4rem;
  border-radius: 0.5rem;
  border: 1px solid var(--_primitives---opacity--white-10);
  border-left: 3px solid var(--_primitives---colors--menta);
  background-color: var(--_primitives---opacity--white-5);
}
.blog-article_content .blog-downloads_title {
  margin: 0 0 0.75rem;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--_primitives---colors--menta);
}
.blog-article_content .blog-downloads ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.4rem;
}
.blog-article_content .blog-downloads li {
  margin: 0;
  font-size: 1rem;
}
.blog-article_content .blog-downloads a {
  color: var(--_primitives---colors--white);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--_primitives---opacity--white-30);
}
.blog-article_content .blog-downloads a:hover {
  color: var(--_primitives---colors--menta);
  text-decoration-color: var(--_primitives---colors--menta);
}

/* Tablas: llegan como HTML crudo dentro de un htmlEmbed (2 posts hoy), así que
 * no pasan por el mapa de componentes de Portable Text y no pueden recibir
 * clases del design system desde ahí. Se estilan por descendencia, reusando
 * los mismos tokens que el resto del cuerpo. El wrapper scrollea en horizontal
 * para que una tabla ancha no rompa el layout en móvil. */
.blog-article_content .w-richtext { overflow-x: auto; }
.blog-article_content table {
  width: 100%;
  border-collapse: collapse;
  font-size: 1rem;
  color: var(--_primitives---colors--neutral-lighter-body-text);
}
.blog-article_content th,
.blog-article_content td {
  padding: 0.75rem 1rem;
  text-align: left;
  border: 1px solid var(--_primitives---opacity--white-10);
}
.blog-article_content th {
  color: var(--_primitives---colors--white);
  background-color: var(--_primitives---opacity--white-5);
  font-weight: 600;
}
.blog-article_content ul, .blog-article_content ol { margin-top: 1.25rem; padding-left: 1.25rem; }
/* Las listas heredaban el tamaño base (16px) y se veían más chicas que los
 * párrafos (20px). Se igualan al cuerpo: mismo font-size (= text-size-medium),
 * interlineado y color gris de los párrafos. */
.blog-article_content li {
  margin-top: 0.5rem;
  font-size: 1.25rem;
  line-height: 1.7;
  color: var(--_primitives---colors--neutral-lighter-body-text);
}
.blog-article_quote {
  margin: 3rem 0;
  padding: 0.5rem 0 0.5rem 1.75rem;
  border-left: 3px solid var(--_primitives---colors--menta);
}
.blog-article_figure { margin: 2rem 0; }
.blog-article_img { width: 100%; height: auto; border-radius: 0.75rem; display: block; }

/* ----- Lazy video embed ----- */
.blog-video {
  position: relative;
  aspect-ratio: 16 / 9;
  margin: 2rem 0;
  border-radius: 0.75rem;
  overflow: hidden;
  background: var(--_primitives---colors--black-darkest, #0d0d0d);
}
/* Thumbnail dimmed so the menta play button reads on top (design 1b). */
.blog-video_thumb { width: 100%; height: 100%; object-fit: cover; opacity: 0.45; }
.blog-video_play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 5rem;
  height: 5rem;
  border: none;
  border-radius: 100vw;
  background: var(--_primitives---colors--menta);
  color: var(--_primitives---colors--black-darkest, #12100e);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 0 60px color-mix(in srgb, var(--_primitives---colors--menta) 50%, transparent);
  transition: transform 0.2s ease;
}
.blog-video:hover .blog-video_play { transform: scale(1.06); }
.blog-video_iframe { width: 100%; height: 100%; border: 0; display: block; }

/* ----- Tags ----- */
.blog-article_tags { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 3.5rem; }
.blog-article_tag {
  padding: 0.4rem 1rem;
  border: 1px solid var(--_primitives---opacity--white-20);
  border-radius: 100vw;
}

/* ----- Author bio ----- */
.blog-article_bio {
  display: flex;
  gap: 1.5rem;
  margin-top: 3rem;
  padding: 2rem 0;
  border-top: 1px solid var(--_primitives---opacity--white-15);
  border-bottom: 1px solid var(--_primitives---opacity--white-15);
}
.blog-article_bio-avatar { width: 4.5rem; height: 4.5rem; border-radius: 100vw; object-fit: cover; flex: none; }
.blog-article_bio-body { display: flex; flex-direction: column; gap: 0.5rem; }

/* Back link al final del artículo (después de la bio). */
.blog-article_back-end { margin-top: 2.5rem; }

/* ----- Keep Reading ----- */
.blog-related_head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 2.5rem;
  padding-top: 2rem;
  border-top: 1px solid var(--_primitives---opacity--white-40);
}
.blog-related_viewall {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  letter-spacing: 0.08em;
  text-decoration: none;
  flex: none;
  transition: color 0.2s ease;
}
.blog-related_viewall:hover { color: var(--_primitives---colors--menta); }

/* ----- Newsletter (2-col) ----- */
.blog-article_newsletter-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4rem;
  align-items: center;
}
.blog-article_newsletter-copy { display: flex; flex-direction: column; }

/* ----- Tablet: collapse to 1 column, sidebar no longer sticky ----- */
@media screen and (max-width: 991px) {
  /* minmax(0, 1fr) y NO "1fr" a secas: "1fr" equivale a minmax(auto, 1fr) y
   * ese `auto` impide que el track se achique por debajo del min-content de
   * su contenido. En los artículos con bloques de código el min-content de
   * .blog-article_body llegaba a 954px (medido a 390px de viewport), así que
   * el track crecía a 954 y el `justify-content: center` que hereda la regla
   * base centraba ese track sobredimensionado: todo el layout terminaba de
   * -282px a 672px y la página ganaba 282px de scroll horizontal.
   * Los <pre class="blog-code"> ya traen overflow-x:auto, así que con el
   * track acotado el código sigue accesible desplazándose dentro de su
   * propia caja, sin arrastrar a la página. Es el mismo patrón que la regla
   * base ya usa para la columna central: minmax(0, 42rem). */
  .blog-article_layout { grid-template-columns: minmax(0, 1fr); gap: 2.5rem; }
  .blog-article_sidebar { position: static; }
  .blog-article_newsletter-inner { grid-template-columns: 1fr; gap: 2rem; }
}

/* ----- Mobile (≤767px): TOC accordion above the article, share inline at the end ----- */
@media screen and (max-width: 767px) {
  /* Hero left-aligned on mobile (design 2a), tighter and 4:3 image. The navbar
   * clearance lives on the top bar (breadcrumbs); hero-inner only adds its gap. */
  .blog-article_hero-top { padding-top: calc(var(--blog-nav-offset) + 1.5rem); }
  .blog-article_hero-inner { text-align: left; padding-top: 2rem; }
  .blog-article_meta, .blog-article_author { justify-content: flex-start; }
  .blog-article_hero-summary { margin-left: 0; margin-right: 0; }
  .blog-article_hero-image { aspect-ratio: 4 / 3; margin-top: 2rem; }

  /* TOC label swaps to the accordion wording. */
  .blog-toc_label-desktop { display: none; }
  .blog-toc_label-mobile { display: inline; }

  /* Desktop share (in the sidebar) hides; the inline one at the end of the article shows. */
  .blog-share:not(.is-mobile) { display: none; }
  .blog-share.is-mobile { display: flex; flex-direction: row; align-items: center; gap: 1rem; margin-top: 3rem; }

  /* TOC becomes a collapsible "On this page" accordion, collapsed by default. */
  .blog-toc_header {
    cursor: pointer;
    border: 1px solid var(--_primitives---opacity--white-10);
    border-radius: 0.75rem;
    padding: 0.85rem 1rem;
  }
  .blog-toc_chevron {
    display: block;
    width: 8px;
    height: 8px;
    border-right: 2px solid var(--text-color--gray, #9c9c9c);
    border-bottom: 2px solid var(--text-color--gray, #9c9c9c);
    transform: rotate(45deg);
    transition: transform 0.2s ease;
  }
  .blog-toc.is-open .blog-toc_chevron { transform: rotate(-135deg); }
  .blog-toc_list {
    max-height: 0;
    overflow: hidden;
    border-left: none;
    padding-left: 1rem;
    transition: max-height 0.3s ease, margin-top 0.3s ease;
  }
  .blog-toc.is-open .blog-toc_list { max-height: 60vh; margin-top: 1rem; overflow: auto; }

  /* "Seguir leyendo" + el enlace "ver todos" comparten una fila flex con
   * justify-content:space-between, y el enlace lleva flex:none para que la
   * flecha no se parta. En móvil el título y el enlace no entran juntos en
   * 351px y el enlace se salía 16px, dando scroll horizontal en TODOS los
   * artículos (más visible en ES, donde la etiqueta es más larga). Con wrap
   * el enlace baja a su propia línea en vez de desbordar. */
  .blog-related_head {
    flex-wrap: wrap;
    gap: 0.75rem 1rem;
  }
}

/* ----- QA checklist (/qa-checklist, /es/checklist-qa) -----
 * El recuadro se compone entero con clases que ya existen
 * (.deliverables-content-card + .flex-horizontal.is-space_between), y el
 * cambio a menta al marcarlo lo hace site.js intercambiando .text-color-gray
 * por .text-color-menta en el ícono. Lo único que el design system no tiene
 * es el *comportamiento* de una card marcable, y es lo único que se declara
 * acá: ningún tamaño, color ni tipografía nuevos — el menta y el grosor de
 * borde salen de las variables ya definidas. */
.qa-item {
  cursor: pointer;
}
/* `flex: none` porque el ícono es un flex item y por defecto puede encogerse
   (flex-shrink: 1): con textos largos el checkbox se comprimía hasta 17px
   mientras otros quedaban en 32px — medidos 13 anchos distintos. El original
   de Webflow tenía exactamente lo mismo en `.check-icon`. No cambia el tamaño
   (sigue siendo el 2rem de .icon-embed-small), solo impide que se deforme. */
.qa-item [data-qa-icon] {
  flex: none;
  transition: color 0.2s ease;
}
/* Alternancia sutil de fondo entre ítems consecutivos, como el original
   (que alternaba dos tintes casi idénticos sobre el fondo de la página).
   Usa la escala de opacidad blanca que ya existe: el ítem base es white-5
   (de .deliverables-content-card) y el alterno sube a white-10. Sin valores
   nuevos, y `is-alternate` es la convención de modificador del design system
   (.button.is-alternate, .tag.is-alternate, .form_checkbox.is-alternate). */
.qa-item.is-alternate {
  background-color: var(--_primitives---opacity--white-10);
}
/* El foco real vive en el <input class="visually-hidden"> dentro del <label>,
   por eso :focus-within y no :focus-visible sobre la card. */
.qa-item:focus-within {
  outline: var(--_ui-styles---stroke--stroke-thin) solid var(--_primitives---colors--menta);
  outline-offset: 2px;
}

/* ----- Chips de servicios (ContactForm) -----
 * El diseño (Figma node 6399-865) muestra "Select services" como chips
 * rectangulares con borde fino en vez de checkboxes. El design system no
 * tiene un componente chip marcable, así que solo se declara acá el layout y
 * los estados; tamaños/colores salen de variables y clases existentes
 * (borde white-30, texto white-60, tipografía vía .text-size-small
 * + .text-weight-light en el markup). El checkbox nativo sigue en el DOM
 * con .visually-hidden — mismos `name`, FormData y validación intactos. */
.form_chips {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}
.form_chip {
  position: relative;
  cursor: pointer;
}
.form_chip-label {
  display: inline-flex;
  border: var(--_ui-styles---stroke--stroke-thin) solid var(--_primitives---opacity--white-30);
  padding: 0.5rem 1rem;
  color: var(--_primitives---opacity--white-60);
  transition: border-color 0.2s, color 0.2s, background-color 0.2s;
}
.form_chip:hover .form_chip-label {
  border-color: var(--_primitives---opacity--white-60);
  color: var(--_primitives---colors--white);
}
/* Fondo derivado de la variable menta existente (sin hex nuevo). */
.form_chip input:checked + .form_chip-label {
  border-color: var(--_primitives---colors--menta);
  color: var(--_primitives---colors--menta);
  background-color: color-mix(in srgb, var(--_primitives---colors--menta) 10%, transparent);
}
.form_chip input:focus-visible + .form_chip-label {
  outline: var(--_ui-styles---stroke--stroke-thin) solid var(--_primitives---colors--menta);
  outline-offset: 2px;
}

/* ----- Página Portfolio: mejoras de UI (pedido cliente 2026-07-28) -----
 * 1) Featured Work: tags en fila, contenedor 16:9, divisor entre proyectos.
 * 2) Hover foto→video (Bunny) en Featured Work y en el grid.
 * 3) Grid "Complete Portfolio" uniforme 16:9 + paginación de 6 en 6.
 * Todo scoped a [data-portfolio-list] / clases de la página Portfolio — la
 * Home comparte .portfolio_collection-list y conserva su masonry original. */

/* La fila de tags usa la clase Webflow que ya existía sin uso
 * (.collection-list-feature-projects-tags, flex + gap 12px); el gap sube a
 * 1rem (valor de la escala de espaciado, pedido del cliente: ~16px entre
 * tags) y se permite wrap para móvil. */
.collection-list-feature-projects-tags {
  gap: 1rem;
  flex-wrap: wrap;
}

/* Contenedor 16:9 para que el video de Bunny (16:9 nativo) calce sin
 * recortes; reemplaza el height: 80vh original. */
.featured-projects-item-container {
  height: auto;
  aspect-ratio: 16 / 9;
}

/* El divisor entre featured projects es la clase Webflow existente
 * .collection-featured-projects-item-container (border-bottom white-40 +
 * margin-bottom 80px), ahora aplicada en el markup. El último no lleva
 * línea: el divisor va solo ENTRE proyectos. */
.collection-featured-projects-item-container:last-child {
  border-bottom-style: none;
  margin-bottom: 0;
}

/* Hover foto→video: el <video> se apila sobre la foto con fade de opacidad.
 * site.js hace play/pause y togglea .is-video-active en el wrapper
 * [data-hover-video] (solo en dispositivos con hover real y sin
 * prefers-reduced-motion). preload="none" en el markup: no se descarga nada
 * hasta el primer hover. En Featured Work el <video> va ANTES del gradiente
 * (.featured-projects-item-back-layer) en el DOM para que los tags sigan
 * siendo legibles sobre el video. */
[data-hover-video] .portfolio-hover-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.5s ease;
  pointer-events: none;
}
[data-hover-video].is-video-active .portfolio-hover-video {
  opacity: 1;
}
.portfolio-thumbnail-media {
  position: relative;
  overflow: hidden;
}

/* Grid uniforme: todas las thumbnails 16:9 (antes heights fijos 557/438px
 * del masonry) y separación clara entre proyectos — el ritmo interno de la
 * card queda en ≤2rem y entre proyectos hay 4rem (agrupación por
 * proximidad). El margin-bottom de .portfolio_item se anula para que el
 * row-gap sea la única fuente de separación vertical. */
.portfolio_collection-list[data-portfolio-list] {
  display: grid;
  grid-template-columns: 1fr;
  gap: 3rem 1.5rem;
}
.portfolio_collection-list[data-portfolio-list] > .portfolio_item {
  margin-bottom: 0;
}
.portfolio_collection-list[data-portfolio-list] > .portfolio_item[hidden] {
  display: none;
}
.portfolio_collection-list[data-portfolio-list] > .w-dyn-item .portfolio-thumbnail {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
}
@media screen and (min-width: 768px) {
  .portfolio_collection-list[data-portfolio-list] {
    grid-template-columns: 1fr 1fr;
    gap: 4rem 1.5rem;
  }
  .portfolio_collection-list[data-portfolio-list] > .w-dyn-item {
    grid-column: auto;
  }
}

/* "What we do" (Home) y el bloque de imágenes de Contact: los <img> llevan
 * atributos width/height (2048x2048 en Home, 1536x1536 en Contact) para
 * reservar espacio y evitar CLS. Ese "height" entra al cascade como
 * presentational hint, y ".image-services-home" solo declara "width: 100%":
 * al no existir NINGUNA regla de autor que toque "height", el alto se
 * quedaba clavado en los px crudos del atributo. La imagen se pintaba
 * 514x2048 en vez de 514x514 —estirada ~4x en vertical— y el wrapper
 * cuadrado (aspect-ratio 4/4 + overflow:hidden) recortaba todo menos la
 * banda superior: de ahí el efecto de "zoom" y deformación.
 * El export de Webflow no traía esos atributos, por eso ahí el alto salía
 * natural. "height: auto" recupera la proporción sin perder la reserva de
 * espacio: el navegador sigue derivando el aspect-ratio de los atributos. */
.image-services-home {
  height: auto;
}

/* Our Story (About Us): la imagen iguala la altura de la columna de texto.
   Pedido del usuario 2026-08-10 (mejora aprobada, no paridad Webflow): el
   grid .layout3_content solo existe en esa sección, por eso se usa como
   scope — .layout2_lightbox-image también vive en ServiceDetailPage y no
   debe cambiar ahí. Solo desktop/tablet: en ≤767px el grid se apila a una
   columna y un flex-basis 0 colapsaría la imagen (ahí conserva su
   aspect-ratio 1 original). */
@media screen and (min-width: 768px) {
  .layout3_content {
    align-items: stretch;
  }

  .layout3_content .layout2_lightbox-image {
    aspect-ratio: auto;
    height: auto;
    flex: 1 1 0;
    min-height: 0;
  }
}

/* Logos de clientes en Reviews (Home): el sitio original los fuerza a blanco
   con un embed de custom code dentro de la card del CMS ("CMS Logos - Force
   White Color", ver export index.html) que no se había portado — por eso acá
   salían en su color original sobre fondo oscuro. Misma regla, mismo filtro. */
.logo-client-review {
  filter: brightness(0) invert(1);
}

/* ----- Selector de idioma del navbar (ícono de mundo + dropdown) -----
   Usa el mismo mecanismo que los otros dropdowns de la barra (w--open lo
   pone site.js), pero el panel es compacto y anclado bajo el ícono en vez
   del panel a todo lo ancho de .navbar5_dropdown-list.w--open. Todos los
   valores son tokens ya existentes: fondo/borde/radio calcados del
   .megamenu_root (black-darker + white-10 + 1.5rem→aquí .875rem, el radio
   de .megamenu_cat, más proporcionado para un panel chico) y padding con
   la escala --_ui-styles---spacing-padding--space-*. */
.navbar_lang-dropdown .navbar_dropdown-toggle {
  cursor: pointer;
}
/* .navbar_menu-dropdown fuerza position:static para que los paneles grandes
   se anclen a la barra completa; este panel chico sí se ancla a su toggle. */
.navbar_menu-dropdown.navbar_lang-dropdown {
  position: relative;
}
.navbar_lang-list.w--open {
  inset: 100% 0 auto auto;
  width: auto;
  min-width: 10rem;
  padding: var(--_ui-styles---spacing-padding--space-sm) var(--_ui-styles---spacing-padding--space-md);
  background-color: var(--_primitives---colors--black-darker);
  border: 1px solid var(--_primitives---opacity--white-10);
  border-radius: .875rem;
}

/* ----- Ícono "+" de los dropdowns del navbar -----
   Mismo gesto que los acordeones de FAQ (.faq_accordion.is-open
   .faq_icon-wrapper): el signo + gira 45° y se convierte en ×, con la MISMA
   transición medida allá (transform 0.3s ease). El estado lo marca el
   aria-expanded que ya pone site.js en el toggle, así no hace falta otra
   clase ni :has(). */
.dropdown-chevron {
  transition: transform 0.3s ease;
}
.navbar_dropdown-toggle[aria-expanded="true"] .dropdown-chevron {
  transform: rotate(45deg);
}

/* Apertura sutil del panel: aparece con un fundido y un desplazamiento de
   .5rem (el paso más chico de la escala de espaciado). Reusa la duración y
   la curva del megamenú —ya definidas arriba y ya neutralizadas bajo
   prefers-reduced-motion— en vez de introducir tiempos nuevos. */
@keyframes navbar-dropdown-in {
  from {
    opacity: 0;
    transform: translateY(-0.5rem);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.navbar5_dropdown-list.w--open {
  animation: navbar-dropdown-in var(--mm-view-duration) var(--mm-open-ease);
}

/* Las dos superficies de media de /portfolio (card de Featured y miniatura
   del grid) pasaron de <div> a <a> para poder abrir el proyecto en pestaña
   nueva. Un <a> es inline por defecto, y ambas clases dependen de ser un
   bloque (height 80vh en Featured, position:relative + overflow:hidden en
   la miniatura). El color/underline no hace falta resetearlos: ya lo cubre
   el "a { color: inherit; text-decoration: inherit }" del inicio de este
   archivo. */
a.featured-projects-item-container,
a.portfolio-thumbnail-media {
  display: block;
}

/* ----- "Related services" en móvil: título y subtítulo juntos -----
   La card es flex column con justify-content:space-between y min-height
   (560px en desktop, 320px en ≤767px). En desktop eso es el diseño: el
   título arriba y el bloque subtítulo+botón anclado abajo. En móvil la card
   es mucho más corta y ese reparto dejaba ~99px de aire entre el título y su
   subtítulo, que se leían como dos cosas sin relación.
   En ≤767px la card pasa a apilar desde arriba y a ajustarse a su contenido,
   y la separación queda en 1.25rem: exactamente lo que vale .margin-small en
   este breakpoint (mentaexperts.webflow.css, override de la escala a ≤767px),
   no un valor nuevo. */
@media screen and (max-width: 767px) {
  .related-service-card {
    justify-content: flex-start;
    min-height: 0;
  }
  .related-service-card > .margin-bottom.margin-xlarge {
    margin-bottom: 1.25rem;
  }
}

/* ================= Filtros del blog en móvil (≤767px) =================
   Dos problemas reportados por el usuario (2026-08-12):

   1) Orden: la barra apila .blog-filters_left (Categoría, Tags, buscador y
      "Clear all") y DESPUÉS .blog-filters_right ("The newest"), así que el
      botón de limpiar quedaba antes del selector de orden. Con
      `display: contents` en los dos grupos, sus hijos pasan a ser ítems
      directos de la barra y se pueden ordenar de verdad; el buscador ocupa
      su propia fila y quedan tres filas: [Categoría · Tags] / [buscador] /
      [The newest · Clear all]. En desktop no cambia nada: todo esto vive
      dentro del media query.

   2) El panel de "The newest" se abría fuera de la pantalla. Lo posiciona
      `.blog-dropdown_panel.is-right{right:0}` respecto de su toggle, que en
      móvil es angosto y está pegado a la izquierda: con min-width 14rem el
      panel crecía hacia la izquierda hasta x=-103px (medido) y no se leía.
      Anclar los paneles al toggle no escala —el de "Tags" empieza en x≈290 y
      se saldría por la derecha—, así que en móvil se anclan a la BARRA
      (.blog-dropdown pasa a position:static) y ocupan todo su ancho. */
@media screen and (max-width: 767px) {
  .blog-filters {
    position: relative;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem 1.5rem;
  }
  .blog-filters_left,
  .blog-filters_right {
    display: contents;
  }
  .blog-filters > .blog-dropdown {
    order: 1;
  }
  .blog-search {
    order: 2;
    flex-basis: 100%;
  }
  .blog-filters_right > .blog-dropdown {
    order: 3;
  }
  .blog-filters_active {
    order: 4;
    margin-left: auto;
  }
  .blog-dropdown {
    position: static;
  }
  .blog-dropdown_panel,
  .blog-dropdown_panel.is-right {
    left: 0;
    right: 0;
    min-width: 0;
  }
}

/* Red de seguridad contra desbordes en el cuerpo de los artículos.
   El artículo "Share buttons for different social media in Webflow" trae HTML
   pegado como TEXTO dentro de <p> (atributos y URLs largos tipo
   `href="https://www.facebook.com/sharer/sharer.php?u=&t="`). Son tokens sin
   espacios: el navegador no puede partirlos, así que el párrafo medía 501px
   dentro de una columna de 351px y la página entera ganaba 130px de scroll
   horizontal en móvil.
   `overflow-wrap: break-word` se hereda a todo el contenido y solo actúa
   cuando una palabra NO cabe de otro modo, así que el texto normal se
   compone igual. Va sin media query a propósito: es prevención para
   cualquier artículo futuro que pegue una URL larga o un snippet, en
   cualquier ancho. Los <pre class="blog-code"> no se ven afectados (usan
   white-space:pre y ya scrollean solos con overflow-x:auto). */
.blog-article_content {
  overflow-wrap: break-word;
}
