/* ==========================================================================
   vitaralink.com — v8 · Base, nav y portada con el sistema de diseño Vitaralink
   Tokens en css/v8-tokens.css (generado de tokens.json). Tema oscuro por defecto,
   claro con data-theme="light" en <html> (botón de sol) o en una sección.
   Las secciones de v7 se re-pintan en css/v8-sistema.css.
   ========================================================================== */

/* ---------- Base ---------- */
html {
  scroll-padding-top: 96px;
  /* La barra de scroll sigue al tema (color-scheme no va en <html>, ver v8-tokens.css) */
  scrollbar-color: var(--border-strong) var(--bg);
}

body {
  margin: 0;
  padding-top: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 16px;
  line-height: 24px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Cada bloque con tema propio pinta su fondo y su texto. Los canvas de los visuales
   también llevan data-theme ("auto"), pero son transparentes: se excluyen. */
[data-theme]:not(canvas) {
  background-color: var(--bg);
  color: var(--text);
}

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

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

.skip-link {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 200;
  padding: 12px 16px;
  border-radius: var(--radius-md);
  background: var(--action);
  color: var(--on-action);
  font: 600 14px/18px var(--font-sans);
  text-decoration: none;
  transform: translateY(-200%);
  transition: transform var(--duration-base) var(--ease-standard);
}

.skip-link:focus {
  transform: none;
}

/* Contenedor de Dovetail: 1512 máx., gutter 124 / 64 / 16 */
.contenedor,
.container {
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

@media (max-width: 1280px) {
  .contenedor,
  .container {
    padding: 0 var(--gutter-tablet);
  }
}

@media (max-width: 799px) {
  .contenedor,
  .container {
    padding: 0 var(--gutter-mobile);
  }
}

/* ---------- Iconos pixel de marca (sistema: PixelIcons) ----------
   Iconos en rejilla 7×7 con trazo de 1 celda: 14 · 21 · 28 px (celdas de 2 · 3 · 4 px).
   Flechas en 5×5 (la familia del CTA): siguen en --px-icon-* (10 · 15 · 20 px).
   Un solo path por icono, sin crispEdges: con crispEdges, al 125 % o 150 % unas celdas
   quedaban de 2 px y otras de 3 px y el icono se veía chueco. */
:root {
  --px-icono-sm: 14px;
  --px-icono-md: 21px;
  --px-icono-lg: 28px;
}

.px-i {
  display: block;
  flex: none;
  width: var(--px-icono-sm);
  height: var(--px-icono-sm);
  fill: currentColor;
  color: var(--action-icon);
  shape-rendering: geometricPrecision;
}

/* Flechas 5×5: su tamaño base de siempre. :where() deja la especificidad de .px-i, así las
   reglas de cada componente (botones, tarjetas) siguen mandando. */
.px-i:where(:has(> use[href^="#px-flecha"])) {
  width: var(--px-icon-sm);
  height: var(--px-icon-sm);
}

.px-i--md {
  width: var(--px-icono-md);
  height: var(--px-icono-md);
}

.px-i--lg {
  width: var(--px-icono-lg);
  height: var(--px-icono-lg);
}

/* Icono oficial de WhatsApp (trazo de assets/logos/whatsapp.svg) en cyan de acción. No es
   pixel: es una marca ajena y se usa tal cual. 1.1em para que se lea junto al texto. */
.wa-i {
  width: 1.1em;
  height: 1.1em;
  color: var(--action-icon);
  shape-rendering: geometricPrecision;
}

/* ---------- Botones (monocromos; el único cyan es la flecha pixel del primario) ---------- */
.boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 44px;
  padding: 12px 16px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  font: 600 14px/18px var(--font-sans);
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--duration-slow) var(--ease-standard), border-color var(--duration-slow) var(--ease-standard);
}

.boton--primario {
  background: var(--action);
  color: var(--on-action);
}

.boton--primario .flecha {
  width: 12px;
  height: 12px;
  color: var(--action-icon);
}

.boton--secundario {
  background: transparent;
  border-color: var(--button-outline);
  color: var(--text);
}

.boton--secundario .px-i {
  color: var(--text);
}

.boton--lg {
  min-height: 56px;
  padding: 16px 24px;
  gap: 12px;
  font-size: 18px;
  line-height: 24px;
}

.boton--lg .flecha {
  width: 14px;
  height: 14px;
}

@media (hover: hover) and (pointer: fine) {
  .boton--primario:hover {
    background: var(--action-hover);
  }

  .boton--secundario:hover {
    background: var(--ghost-hover);
  }
}

/* Solo icono: 44×44, icono de 15px en text; siempre con aria-label */
.boton-icono {
  display: inline-grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--duration-slow) var(--ease-standard);
}

.boton-icono .px-i {
  color: var(--text);
}

@media (hover: hover) and (pointer: fine) {
  .boton-icono:hover {
    background: var(--ghost-hover);
  }
}

.boton-icono:active {
  background: var(--ghost-active);
}

/* Link con subrayado animado (Dovetail): mismo color que el texto */
.enlace {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--link);
  font-weight: 500;
  text-decoration: none;
}

.enlace > span {
  position: relative;
}

.enlace > span::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-base) ease-out;
}

@media (hover: hover) and (pointer: fine) {
  .enlace:hover > span::after {
    transform: scaleX(1);
  }
}

/* ---------- Titular con keyword (patrón Dovetail) ----------
   Inter Display 600, line-height 1; cada línea es una fila flex alineada a la base.
   La keyword va en PP Mondwest a 1.25×, mismo color, con pixel bold. */
.titular {
  margin: 0;
  color: var(--text);
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1;
}

.titular .ln {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 0.2em;
}

/* Un renglón con visual no se parte: el visual solo en un renglón se encimaba con el de abajo */
.titular .ln:has(> .vx-inline) {
  flex-wrap: nowrap;
}

.kw,
.tecleo {
  color: inherit;
  font-family: var(--font-pixel-serif);
  font-weight: 400;
  font-style: normal;
  font-size: 1.25em;
  letter-spacing: 0.07em;
  text-shadow: 0.035em 0 0 currentColor, 0.07em 0 0 currentColor;
}

/* ---------- Keyword viva (js/v8-kw.js): .kw y .accent ----------
   Entrada "rampa ASCII": cada letra pasa por . : - = + * # % en cyan hasta llegar a la letra.
   Después, "interferencia": de vez en cuando una o dos letras son un símbolo cyan por 120 ms.
   El JS parte la palabra en letras solo mientras anima; en reposo el texto queda como estaba.
   Las letras ocultas son transparentes (no visibility: hidden), así siguen en el árbol accesible. */
@media screen {
  :is(.kw, .accent).kw--espera,
  .kw-ch--oculta {
    color: transparent;
  }
}

/* Hasta que el script toma la palabra (.kw--listo) no se ve: si no, el hero mostraba "ven.",
   la quitaba y luego hacía la rampa. Si el script no llega, aparece sola a los 4 s. */
@media screen and (prefers-reduced-motion: no-preference) and (forced-colors: none) {
  .js :is(.kw, .accent):not(.kw--listo) {
    opacity: 0;
    animation: kw-respaldo 1ms 4s forwards;
  }
}

@keyframes kw-respaldo {
  to {
    opacity: 1;
  }
}

/* Las letras (.kw-ch) son spans inline sin estilo propio: Mondwest trae kerning, y con
   inline-block o con algo posicionado dentro de cada letra la palabra crecía 10–20 px.
   Así mide igual que el texto (±0.1 px). Los símbolos van aparte, en una capa al final de
   la palabra, cada uno sobre la caja medida de su letra. */
.kw-capa {
  position: absolute;
  width: 0;
  height: 0;
  pointer-events: none;
}

/* Centrar el renglón en la caja de la letra anula el interlineado: el símbolo cae en la
   misma línea base que la letra. */
.kw-simbolo {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--highlight);
  white-space: nowrap;
}

/* display-l: H2 de sección (112 → 72 → 44) */
.titular--l {
  font-size: 112px;
  letter-spacing: -2.1px;
}

@media (max-width: 1280px) {
  .titular--l {
    font-size: 72px;
    letter-spacing: -1.4px;
  }
}

@media (max-width: 799px) {
  .titular--l {
    font-size: 44px;
    letter-spacing: -0.8px;
  }
}

/* Visual pixel dentro del titular (como "Punch [mano] above your headcount"): el dibujo mide
   ~1.5em, más que la letra. El lienzo (--vx) lleva márgenes negativos para no abrir la línea
   ni separar de más las palabras. Con data-llenar y data-cell="1" el dibujo ocupa su fracción
   exacta del lienzo y casi todas sus celdas originales: se distingue a cualquier tamaño. */
.vx-inline {
  --vx: 2.3em;
  --vx-mx: -0.36em;
  display: block;
  flex: none;
  width: var(--vx);
  aspect-ratio: 1 / 1;
  align-self: center;
  margin: calc((1em - var(--vx)) / 2) var(--vx-mx);
  image-rendering: pixelated;
}

/* Visual alto y angosto (signo de interrogación) */
.vx-inline--alto {
  --vx: 2.1em;
  --vx-mx: -0.5em;
}

/* ---------- Nav flotante ---------- */
.nav-zona {
  position: sticky;
  top: var(--nav-float-offset);
  z-index: 60;
  height: var(--nav-float-height);
  margin: var(--nav-float-offset) 0 calc(-1 * (var(--nav-float-height) + var(--nav-float-offset)));
  pointer-events: none;
}

/* Logo según el tema más cercano (variables heredadas) */
:root,
[data-theme="dark"] {
  --logo-d: block;
  --logo-l: none;
}

[data-theme="light"] {
  --logo-d: none;
  --logo-l: block;
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  height: var(--nav-float-height);
  padding: 0 8px 0 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-nav);
  color: var(--text);
  box-shadow: var(--shadow-md);
  pointer-events: auto;
  transition: background-color var(--duration-slow) var(--ease-standard);
}

.nav__marca {
  display: flex;
  flex: none;
  align-items: center;
  min-height: 44px;
}

.nav__logo {
  width: auto;
  height: 40px;
}

.nav__logo--d {
  display: var(--logo-d);
}

.nav__logo--l {
  display: var(--logo-l);
}

.nav__links {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-left: auto;
}

.nav__link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  color: var(--text);
  font: 500 15px/20px var(--font-sans);
  text-decoration: none;
  transition: background-color var(--duration-slow) var(--ease-standard);
}

@media (hover: hover) and (pointer: fine) {
  .nav__link:hover {
    background: var(--ghost-hover);
  }
}

.nav__link[aria-current="page"] {
  background: var(--ghost-active);
}

.nav__fin {
  display: flex;
  flex: none;
  align-items: center;
  gap: 8px;
}

.nav__cta {
  padding: 10px 16px;
}

.nav__cta .l-corto,
.nav__menu {
  display: none;
}

/* Icono del tema: sol en oscuro (pasa a claro), luna en claro (pasa a oscuro) */
.tema__luna {
  display: none;
}

[data-theme="light"] .tema__sol {
  display: none;
}

[data-theme="light"] .tema__luna {
  display: block;
}

/* Nav adaptable: js/v8-tema.js mide el espacio real de la barra y elige el modo más amplio
   que cabe (data-nav-modo en .nav-zona). Así, con la ventana a la mitad, los enlaces siguen a
   la vista mientras quepan, y la hamburguesa solo aparece cuando de verdad no hay lugar.
     completo → compacto (botón "Agendar", enlaces juntos) → isotipo (logo solo robot) → menu
     → menu-iso (menú con el logo en isotipo, para teléfonos angostos) */
.nav__marca,
.nav__links,
.nav__fin {
  flex-shrink: 0;
}

.nav__logo--iso {
  display: none;
}

.nav-zona[data-nav-modo="compacto"] .nav__link,
.nav-zona[data-nav-modo="isotipo"] .nav__link {
  padding: 10px 8px;
}

.nav-zona[data-nav-modo="compacto"] .nav__links,
.nav-zona[data-nav-modo="isotipo"] .nav__links {
  gap: 0;
}

.nav-zona[data-nav-modo="compacto"] .nav__cta .l-largo,
.nav-zona[data-nav-modo="isotipo"] .nav__cta .l-largo,
.nav-zona[data-nav-modo="menu"] .nav__cta .l-largo,
.nav-zona[data-nav-modo="menu-iso"] .nav__cta .l-largo {
  display: none;
}

.nav-zona[data-nav-modo="compacto"] .nav__cta .l-corto,
.nav-zona[data-nav-modo="isotipo"] .nav__cta .l-corto,
.nav-zona[data-nav-modo="menu"] .nav__cta .l-corto,
.nav-zona[data-nav-modo="menu-iso"] .nav__cta .l-corto {
  display: inline;
}

/* Isotipo: solo el robot (variante del sistema para espacios chicos) */
.nav-zona[data-nav-modo="isotipo"] .nav__logo:not(.nav__logo--iso),
.nav-zona[data-nav-modo="menu-iso"] .nav__logo:not(.nav__logo--iso) {
  display: none;
}

.nav-zona[data-nav-modo="isotipo"] .nav__logo--iso.nav__logo--d,
.nav-zona[data-nav-modo="menu-iso"] .nav__logo--iso.nav__logo--d {
  display: var(--logo-d);
}

.nav-zona[data-nav-modo="isotipo"] .nav__logo--iso.nav__logo--l,
.nav-zona[data-nav-modo="menu-iso"] .nav__logo--iso.nav__logo--l {
  display: var(--logo-l);
}

.nav__logo--iso {
  height: 40px;
}

.nav-zona[data-nav-modo="menu"] .nav__links,
.nav-zona[data-nav-modo="menu-iso"] .nav__links {
  display: none;
}

.nav-zona[data-nav-modo="menu"] .nav__menu,
.nav-zona[data-nav-modo="menu-iso"] .nav__menu {
  display: inline-grid;
}

/* Sin JavaScript: hamburguesa solo en pantallas chicas */
@media (max-width: 799px) {
  html:not(.js) .nav__links {
    display: none;
  }
}

/* Menú abierto: panel a pantalla completa en bg */
.nav-zona.is-abierto .nav__links {
  position: fixed;
  inset: 0;
  z-index: -1;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  margin: 0;
  padding: calc(var(--nav-float-height) + 2 * var(--nav-float-offset) + 16px) var(--gutter-tablet) 32px;
  background: var(--bg);
}

.nav-zona.is-abierto .nav__link {
  gap: 12px;
  padding: 14px 12px;
  font: 600 24px/32px var(--font-display);
}

.nav-zona.is-abierto .nav__link .px-i {
  width: var(--px-icono-md);
  height: var(--px-icono-md);
}

@media (max-width: 799px) {
  .nav {
    gap: 8px;
    padding: 0 4px 0 16px;
  }

  /* En celular, siempre solo el isotipo (sin el texto vitaralink.com), sin importar el modo */
  .nav__logo:not(.nav__logo--iso) {
    display: none;
  }

  .nav__logo--iso.nav__logo--d {
    display: var(--logo-d);
  }

  .nav__logo--iso.nav__logo--l {
    display: var(--logo-l);
  }

  .nav__logo--iso {
    height: 38px;
  }

  .nav__cta {
    padding: 10px 12px;
  }

  .nav-zona.is-abierto .nav__links {
    padding-left: var(--gutter-mobile);
    padding-right: var(--gutter-mobile);
  }
}

.icono-cerrar {
  display: none;
}

.nav-zona.is-abierto .icono-menu {
  display: none;
}

.nav-zona.is-abierto .icono-cerrar {
  display: block;
}

/* ---------- Portada (boceto: texto a la izquierda, ojo y selector a la derecha) ---------- */
.portada {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100svh;
  padding: calc(var(--nav-float-height) + var(--nav-float-offset) + 24px) 0 32px;
  overflow: clip;
}

.portada__rejilla {
  display: grid;
  gap: 24px;
  align-items: center;
}

.portada__texto {
  position: relative;
  z-index: 2;
}

/* H1: display-xl. La columna es la mitad del ancho, así que usa el paso de ≤1280 (96px) */
.portada__titulo {
  font-size: 60px;
  letter-spacing: -1px;
}

.portada__titulo .ln {
  flex-wrap: nowrap;
  white-space: nowrap;
}

@media (max-width: 360px) {
  .portada__titulo {
    font-size: 48px;
  }
}

/* ---------- Titular editor: "Tu [página|app|tienda]. / Tú vendes. / Nosotros la hacemos." ----------
   js/v8-titular.js escribe la palabra como en un editor (se selecciona, se borra y se teclea la
   siguiente) al ritmo del selector del ojo; "hacemos." es keyword (.kw). Los renglones no se
   parten y el más largo, "Nosotros la hacemos.", mide ~10.5em: el tamaño se limita al ancho de
   la columna (9cqi ≈ 95 %) y, en laptops bajas, al alto de la pantalla, para que la franja índice
   siga en la primera vista. */
.portada__texto {
  container-type: inline-size;
}

.portada__titulo.portada__titulo--editor {
  font-size: min(80px, 9cqi, 9.6svh);
  letter-spacing: -0.015em;
}

/* Columna angosta (celular): "hacemos." baja a su propio renglón y el titular crece, en vez de
   encoger los tres renglones para que quepa "Nosotros la hacemos." */
@container (max-width: 560px) {
  .portada__titulo.portada__titulo--editor {
    font-size: min(60px, 15cqi);
  }

  .portada__titulo--editor .ln {
    flex-wrap: wrap;
  }
}

/* La palabra tecleada usa la letra de .kw. El cursor va antes de la selección, como al
   seleccionar con Shift + ←; en reposo la selección está vacía. */
.tecleo__sel {
  background: var(--text);
  color: var(--bg);
}

.tecleo__cursor {
  display: inline-block;
  width: 0.085em;
  height: 0.74em;
  margin: 0 0.02em 0 0.04em;
  vertical-align: -0.03em;
  background: var(--highlight);
}

/* En reposo parpadea 4 veces y se queda fijo: nada se mueve solo más de 5 s */
.tecleo.is-quieto .tecleo__cursor {
  animation: tecleo-parpadeo 1.06s steps(1, end) 4;
}

@keyframes tecleo-parpadeo {
  50% {
    opacity: 0;
  }
}

@media (forced-colors: active) {
  .tecleo__sel {
    background: Highlight;
    color: HighlightText;
  }

  .tecleo__cursor {
    background: CanvasText;
  }
}

/* body-l: bajada del hero, text-muted, máx. 508px */
.portada__sub {
  max-width: var(--lede-max);
  margin: 24px 0 0;
  color: var(--text-muted);
  font: 400 20px/28px var(--font-display);
  letter-spacing: -0.25px;
}

.portada__acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-top: 32px;
}

/* WhatsApp junto al CTA: botón secundario del mismo alto, alineado en la misma fila */
.portada__wa {
  margin: 0;
}

.portada__wa[hidden] {
  display: none;
}

.portada__wa .wa-i {
  width: 22px;
  height: 22px;
  color: var(--action-icon);
}

.portada__escena {
  position: relative;
  z-index: 1;
  display: flex;
  justify-content: center;
  margin-top: 40px;
}

@media (min-width: 800px) {
  .portada__titulo {
    font-size: clamp(60px, 7.4vw, 96px);
    letter-spacing: -0.015em;
  }
}

@media (min-width: 1024px) {
  .portada {
    padding-bottom: 24px;
  }

  .portada__rejilla {
    grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
    gap: 48px;              /* aire entre la bajada y el selector de palabras */
  }

  .portada__escena {
    margin-top: 0;
  }
}

/* ---------- Franja índice (al pie de la portada) ---------- */
.portada__indice {
  position: relative;
  z-index: 2;
  margin-top: 48px;     /* aire para el portal del ojo, que baja más que el escenario */
}

.indice {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: none;
  margin: 0;
  animation: indice-entra 0.45s var(--ease-standard) 0.9s both;
}

@keyframes indice-entra {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}

/* Tarjetas como la StatCard del sistema: surface, borde de 1px, radio 8 y cuadrícula de 24px
   que sale de una esquina y se difumina en círculo (fondo-grid--esquina). La de en medio
   arranca en la esquina contraria para que no se vean clonadas.
   Cada una lleva el visual de su servicio, quieto (data-estatico): el animado ya está arriba,
   en el escenario. La del servicio activo muestra el giro con una barra de progreso al pie
   (js/v8-hero.js) y su borde se marca; con el mouse o el foco encima, la barra se completa
   suave y elige ese servicio. Todo con transiciones de 200–240 ms en color, transform y
   opacidad: nada destella ni salta. */
.indice__item {
  --grid-origen: 100% 0;
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 44px;
  padding: 16px;
  overflow: hidden;
  isolation: isolate;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text);
  text-decoration: none;
  transition: border-color 240ms var(--ease-standard);
}

.indice__item.is-activo {
  border-color: var(--border-strong);
}

.indice__item:nth-child(2) {
  --grid-origen: 0 100%;
}

/* fondo-grid--esquina (code/fondo-grid.css del sistema) */
.indice__item::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
  background-size: var(--grid-cell-card, 24px) var(--grid-cell-card, 24px);
  background-position: var(--grid-origen);
  -webkit-mask-image: radial-gradient(circle at var(--grid-origen), #000 0, rgba(0, 0, 0, 0.6) calc(var(--grid-alcance, 75%) * 0.45), transparent var(--grid-alcance, 75%));
  mask-image: radial-gradient(circle at var(--grid-origen), #000 0, rgba(0, 0, 0, 0.6) calc(var(--grid-alcance, 75%) * 0.45), transparent var(--grid-alcance, 75%));
}

.indice__texto,
.indice__visual,
.indice__item > .px-i {
  position: relative;
  z-index: 1;
}

/* Visual animado del servicio. El lienzo es más alto que el renglón de texto y lleva márgenes
   negativos: el dibujo (~65 % del lienzo con data-llenar) se ve grande sin agrandar la tarjeta.
   Fuera del servicio activo baja un poco de opacidad, así se lee cuál está en el escenario. */
.indice__visual {
  flex: none;
  width: 108px;
  height: 108px;
  margin: -30px -10px -30px -18px;
  opacity: 0.86;
  transform: scale(0.94);
  transition: opacity 240ms var(--ease-standard), transform 240ms var(--ease-standard);
}

.indice__visual canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.indice__item.is-activo .indice__visual {
  opacity: 1;
  transform: none;
}

/* Barra de progreso: una línea continua de 2 px al pie de la tarjeta activa; el relleno
   cyan se desliza con transform. Luz: la línea emite un resplandor cyan hacia arriba (sombra en
   dos capas) y su punta es más brillante, como el frente de un haz. La barra no recorta (la
   tarjeta ya tiene overflow: hidden), así el resplandor se ve dentro de la tarjeta.
   La de la tarjeta que deja de estar activa se funde. */
.indice__barra {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  height: 2px;
  pointer-events: none;
}

.indice__barra-relleno {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  background: var(--action-icon);
  box-shadow:
    0 0 6px 0 rgba(0, 184, 217, 0.85),
    0 -2px 18px 1px rgba(0, 184, 217, 0.45);
  opacity: 0;
  transform: translateX(-100%);
  transition: opacity 240ms var(--ease-standard);
}

/* Luz que sube de la línea por todo el tramo recorrido (degradado de luz, no un fondo) */
.indice__barra-relleno::before {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 26px;
  background: linear-gradient(to top, rgba(0, 184, 217, 0.26), rgba(0, 184, 217, 0.08) 45%, rgba(0, 184, 217, 0));
  pointer-events: none;
}

/* Punta: un punto casi blanco con halo, en el frente que avanza */
.indice__barra-relleno::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 0;
  width: 18px;
  height: 4px;
  margin-top: -2px;
  border-radius: 2px;
  background: linear-gradient(to right, rgba(141, 235, 250, 0), var(--cyan-50));
  box-shadow: 0 0 10px 3px rgba(0, 184, 217, 0.95), 0 -4px 26px 6px rgba(0, 184, 217, 0.5);
}

.indice__item.is-activo .indice__barra-relleno {
  opacity: 1;
}

.indice__item.is-activo > .px-i {
  transform: translateX(4px);
}

.indice__item:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

.indice__texto {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.indice__nombre {
  color: var(--text);
  font: 600 20px/24px var(--font-display);
  letter-spacing: -0.25px;
}

.indice__resultado {
  color: var(--text-muted);
  font-size: 14px;
  line-height: 20px;
}

.indice__item > .px-i {
  transition: transform var(--duration-base) var(--ease-standard);
}

@media (hover: hover) and (pointer: fine) {
  .indice__item:hover > .px-i {
    transform: translateX(4px);
  }
}

@media (min-width: 900px) {
  .indice {
    flex-direction: row;
    gap: 16px;
  }

  .indice__item {
    flex: 1 1 0;
    padding: 20px 24px;
  }
}

/* ---------- Escenario: ojo + luz + objeto + selector ----------
   Todo se mide en cqw (1cqw = 1 % del ancho del escenario). Proporción 5:6.
   El ojo está en (50, 103); el objeto flota encima y el selector de palabras queda a la
   izquierda del haz, entre el objeto y el portal. */
.escenario {
  position: relative;
  width: min(100%, 520px);
  aspect-ratio: 5 / 6;
  container-type: inline-size;
}

@media (min-width: 1024px) {
  .escenario {
    width: min(100%, calc((100svh - 96px - 40px) * 5 / 6));
  }
}

/* La luz va detrás del objeto: el visual conserva su color y su relleno tal cual,
   y el cono se ve salir de la pupila y abrirse por detrás de él. */
.escenario__luz {
  position: absolute;
  top: -34cqw;
  right: -18cqw;
  bottom: -4cqw;
  left: -18cqw;
  z-index: 3;
  overflow: hidden;
  pointer-events: none;
  /* Oscuro: la luz solo suma. Claro: la luz tiñe como un filtro (multiplica). */
  mix-blend-mode: screen;
}

[data-theme="light"] .escenario__luz {
  mix-blend-mode: multiply;
}

.escenario__luz canvas {
  position: absolute;
  top: 0;
  left: 0;
  image-rendering: pixelated;
}

/* Ojo v2 (portal extendido): lienzo panorámico 2:1 con el ojo al centro. El renderer ajusta
   el portal completo al lienzo: el medio ancho del ojo mide 0.1526 × el ancho del lienzo, así
   que 104.8cqw lo dejan en 16cqw. El centro cae en (50, 103). Está abierto desde el inicio. */
.ojo {
  position: absolute;
  top: 76.8cqw;
  left: -2.4cqw;
  z-index: 2;
  width: 104.8cqw;
  height: 52.4cqw;
  pointer-events: none;
}

.ojo canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* Objetos: cuadro de 112cqw centrado. Con data-llenar el mapa del visual llena el lienzo,
   así el sitio web va de 0 a 57cqw de alto, justo encima del selector y del portal. */
.escenario__objetos {
  position: absolute;
  top: -28cqw;
  left: -6cqw;
  z-index: 4;
  width: 112cqw;
  height: 112cqw;
  pointer-events: none;
}

/* Cambio de visual: deslizar en línea recta, sin arco. El anterior sale hacia un lado y se
   apaga en 300 ms; el nuevo entra del otro lado a los 220 ms, así nunca se enciman. Llega
   hacia los 640 ms, cuando la luz se abre con su destello. v8-hero.js pone --lado en el
   escenario: 1 = adelante (entra por la derecha), -1 = atrás (entra por la izquierda).
   --recorte ajusta el cuadro de cada visual para que los tres se vean del mismo tamaño (cuerpo
   del dibujo, sin chispas sueltas: ~60cqw de lado medio); negativo lo agranda. */
.objeto {
  --recorte: 0cqw;
  position: absolute;
  inset: var(--recorte);
  opacity: 0;
  perspective: 1100px;          /* para el giro del flote y la reacción al cursor */
  transform: translateX(calc(var(--lado, 1) * 14cqw));
}

.objeto[data-objeto="shopify"] {
  --recorte: 2.6cqw;            /* bolsa: cuerpo de 66 × 60cqw → 63 × 58, como el sitio web y la app */
}

/* App: el mapa es de 212 celdas (los otros, 189) y el celular es angosto, así que se veía
   más chica. Se agranda ~8 % hacia abajo: la punta del celular se queda donde estaba
   (−3.4cqw, a la par de la bolsa) para que el nav no la tape. */
.objeto[data-objeto="apps"] {
  --recorte: -4.5cqw;
  inset: calc(var(--recorte) + 2.5cqw) var(--recorte) calc(var(--recorte) - 2.5cqw);
}

.objeto.is-activo {
  opacity: 1;
  transform: none;
  transition: transform 0.7s cubic-bezier(0.16, 1, 0.3, 1) 0.22s, opacity 0.4s cubic-bezier(0, 0, 0.2, 1) 0.22s;
}

.objeto.is-saliendo {
  opacity: 0;
  transform: translateX(calc(var(--lado, 1) * -10cqw));
  transition: transform 0.3s cubic-bezier(0.4, 0, 1, 1), opacity 0.24s cubic-bezier(0.4, 0, 1, 1);
}

/* El flote lo mueve js/v8-hero.js: balanceo sobre su eje + reacción al cursor */
.objeto__flote {
  width: 100%;
  height: 100%;
  transform-origin: var(--arte-x, 50%) var(--arte-y, 50%);
  will-change: transform;
}

/* Sin image-rendering: pixelated. El objeto gira y flota: con vecino más cercano cada
   pixel saltaba de celda en celda (se veía temblar); con el filtrado normal se mueve suave. */
.objeto canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* Visual en capas (js/vx-data-<slug>-capas.js): los lienzos van encimados, de atrás hacia
   adelante, y js/v8-hero.js mueve cada uno por su lado. Quietos componen el visual original. */
.objeto__flote {
  position: relative;
}

.objeto__flote > .vx-capa {
  position: absolute;
  top: 0;
  left: 0;
  will-change: transform;
}

/* ---------- Selector de palabras (sistema: WordSelector) ----------
   JetBrains Mono 800 en MAYÚSCULAS, a la izquierda del haz. La activa es grande, con la
   flecha pixel en cyan; las demás miden 0.5 y se alejan en arco desvaneciéndose. El tamaño
   cambia con transform: scale (no con font-size), así el cambio va en la GPU y no salta.
   Medidas en em de la palabra activa (--tam). La lista mide 2.6em de alto (tres renglones). */
.selector {
  --tam: clamp(22px, 6.8cqw, 44px);
  --chica: 0.5;
  position: absolute;
  top: 71cqw;
  left: -3cqw;
  z-index: 5;
  font: 800 var(--tam) / 1 var(--font-mono);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

/* En móvil el escenario llega a la orilla del contenedor: la flecha se queda en el margen */
@media (max-width: 799px) {
  .selector {
    left: 0;
  }
}

.selector__lista {
  position: relative;
  width: 6.3em;                       /* flecha + icono + SHOPIFY (7 caracteres) */
  height: 2.6em;                       /* tres renglones: anterior, activa y siguiente */
  margin-top: -1.3em;
}

.selector__op {
  position: absolute;
  top: 50%;
  left: 0;
  height: 1em;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text);
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transform-origin: 0 50%;
  transform: translate(0, calc(-50% + 2.2em)) scale(var(--chica));
  opacity: 0;
  transition: transform var(--duration-shift) var(--ease-standard), opacity var(--duration-shift) var(--ease-standard);
}

.selector__op[data-d="0"]  { transform: translate(0.85em, -50%) scale(1); opacity: 1; cursor: default; }
.selector__op[data-d="1"]  { transform: translate(0.42em, calc(-50% + 0.86em)) scale(var(--chica)); opacity: 0.55; }
.selector__op[data-d="-1"] { transform: translate(0.42em, calc(-50% - 0.86em)) scale(var(--chica)); opacity: 0.55; }
/* Solo se ven tres palabras (una por servicio): las de la orilla existen para entrar y salir
   con movimiento, pero son invisibles, así nadie cree que hay más servicios */
.selector__op[data-d="2"]  { transform: translate(0.12em, calc(-50% + 1.48em)) scale(var(--chica)); opacity: 0; }
.selector__op[data-d="-2"] { transform: translate(0.12em, calc(-50% - 1.48em)) scale(var(--chica)); opacity: 0; }
.selector__op[data-d="3"]  { transform: translate(0, calc(-50% + 2.1em)) scale(var(--chica)); opacity: 0; }
.selector__op[data-d="-3"] { transform: translate(0, calc(-50% - 2.1em)) scale(var(--chica)); opacity: 0; }

/* Icono pixel del servicio junto a cada palabra (el mismo de la navegación). La elegida lo
   lleva en cyan (el color va en el icono, no en la palabra); las demás, en gris. Escala con la palabra (scale),
   así la activa lleva el icono grande. 0.64em = 28 px con la palabra a 44 px (celda de 4 px). */
.selector__op {
  display: flex;
  align-items: center;
  gap: 0.2em;
}

.selector__ico {
  width: 0.64em;
  height: 0.64em;
}

/* Solo la palabra elegida lleva el icono en cyan; las de arriba y abajo, en gris como su texto */
.selector__op .selector__ico {
  color: var(--text-muted);
  transition: color var(--duration-shift) var(--ease-standard);
}

.selector__op[data-d="0"] .selector__ico {
  color: var(--action-icon);
}

/* Al dar la vuelta, la palabra se coloca invisible en el borde sin cruzar la lista */
.selector__op.salta {
  transition: none;
}

.selector__op:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 6px;
}

/* Flecha pixel de la marca (la del CTA), en action-icon; entra a saltos de pixel */
.selector__flecha {
  position: absolute;
  top: 0;
  left: 0;
  width: 0.56em;
  height: 0.56em;
  margin-top: -0.3em;
  fill: var(--action-icon);
  pointer-events: none;
}

.selector__flecha.va {
  animation: selector-flecha 320ms var(--ease-pixel) both;
}

@keyframes selector-flecha {
  from {
    opacity: 0;
    transform: translateX(-0.4em);
  }
}

/* Entrada: el selector aparece con el primer visual */
.js .escenario:not(.is-listo) .selector {
  opacity: 0;
}

.escenario.is-listo .selector {
  opacity: 1;
  transition: opacity 0.6s var(--ease-standard);
}

/* Cambio de tema: fundido de 320 ms (js/v8-tema.js usa View Transitions) */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 320ms;
  animation-timing-function: var(--ease-standard);
}

/* ---------- Movimiento reducido ---------- */
@media (prefers-reduced-motion: reduce) {
  .objeto__flote,
  .indice,
  .selector__flecha.va {
    animation: none;
  }

  .objeto.is-activo,
  .objeto.is-saliendo,
  .selector__op,
  .escenario.is-listo .selector,
  .boton,
  .boton-icono,
  .nav,
  .enlace > span::after,
  .skip-link {
    transition-duration: 0.01ms;
    transition-delay: 0s;
  }
}
