/* ==========================================================================
   Webker Theme (WordPress) — Design system de partida
   Mismos tokens que "Proyecto Base - HTML-CSS-JS" y "Proyecto Base - Astro"
   (mismo nombre de variable) para que las tres bases sean intercambiables a
   nivel de sistema. Todo esto son TOKENS Y ESTRUCTURA neutros, no una
   identidad visual — frontend-design/-pro los sustituye antes de entregar.
   ========================================================================== */

/* ═══════════════════════════════════════════════════════════════════════
   AVISO: EL CSS PROPIO DE UN PROYECTO NO VA EN ESTE ARCHIVO.

   main.css es el sistema de diseño de la BASE, y es el archivo que se
   sustituye entero cuando un proyecto de cliente se actualiza a una versión
   nueva de la plantilla. Todo lo que se escriba aquí de más desaparece en esa
   operación, sin error y sin aviso.

   Pasó: un proyecto guardaba aquí los componentes de su catálogo a medida y,
   al traer la base nueva, se perdieron trece clases de golpe. Sus fichas
   estuvieron días sin maquetar y nadie lo vio porque solo se revisó la
   portada.

   Lo que SÍ va aquí: sustituir los tokens del :root de abajo por la identidad
   del cliente. Eso es rellenar, no añadir.
   Lo que NO: componentes nuevos, secciones a medida, retoques de variantes.
   Eso va en una hoja propia del proyecto (por ejemplo assets/css/<cliente>.css)
   encolada después de esta. Ver tema-wordpress → "Actualizar un proyecto de
   cliente a una versión nueva de la base".
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  /* --- Color: cobre cepillado y tinta espresso, sobre lino --------------
     Sale de la imagen corporativa que usa la propia clienta: una placa de
     cobre cepillado con la marca grabada en una tinta casi negra. Esa pieza
     no tiene un solo tono frío, y es lo que Shunku enseña de sí misma fuera
     de la web — así que la paleta se deriva de ella y no de una referencia.

     Hubo un paso intermedio que conviene no repetir: se cambió solo el acento
     de arcilla a un cobre de la MISMA luminosidad y se dejó en los mismos
     sitios de siempre. El resultado fue un marrón plano que casi no se veía,
     rodeado de petróleo. El cobre no es un hex: es un metal, y lo que lo hace
     cobre es el brillo — la rampa entera de sombra a luz, no un tono suelto.

     Qué se conserva del trabajo anterior: el lino como suelo (evita el blanco
     de clínica), la estructura de anclas oscuras, y la regla de que ningún
     neutro es gris puro — antes tiraban al petróleo, ahora tiran al espresso.

     Cada color tiene UN papel en la portada, y es lo que la hace leerse como
     una sola pieza en vez de como bloques que no se conocen:
       cobre   — la marca y la miel (hero, banda de la miel, grupo de la miel)
       espresso— la persona y el cierre (Mirna, la franja final, el pie)
       lino    — el catálogo y las respuestas (manifiesto, tratamientos, FAQ)
     La menta que quedaba de la paleta de referencia se retiró: con todo lo
     demás en cobre, era la única zona fría de la página y se leía como una
     banda de otra web. --- */
  /* El lino se movió el 2026-09-15, medido y no a ojo. El anterior (#F8F3EE)
     tenía croma OKLCH 0.009 a luz 0.967: por debajo de ~0.012 un claro deja de
     leerse como blanco cálido y pasa a gris, y además estaba en tono 68
     (amarillo) con el cobre en 48, así que a su lado el contraste simultáneo
     lo enfriaba aún más. En una página sin cobre (Contacto) la web se leía
     "casi entera gris", y en el catálogo lino → arena se leía como gris →
     beige. Se compararon tres candidatas renderizadas sobre la portada, Sobre
     mí y Contacto: croma 0.013 en tono 58 cruza el umbral sin llegar a
     rosado; 0.017 ya competía con el cobre. Mismo contraste (taupe 5.94). */
  --color-bg:            #FBF2EC;  /* lino hacia el cobre: L .967 C .013 h 58 */
  --color-surface:       #FFFBF8;  /* blanco roto con la misma traza: nunca blanco puro */
  --color-surface-raised:#F2E6DB;
  --color-ink:           #241913;  /* la tinta de la placa */
  --color-muted:         #6B5A4F;  /* taupe con traza espresso — 5.9 sobre lino */
  --color-border:        #E6D6C8;
  /* Rampa de superficies para el ritmo de secciones (ver la skill
     frontend-design-pro -> references/ritmo-y-jerarquia.md). Estos dos NO se
     escriben a mano: salen del --color-primary, así que al sustituir la paleta
     por la del cliente el ritmo se recalcula solo y nunca queda desafinado
     respecto a su marca. Sustituirlos por un hex fijo solo si el cliente pide
     un tono concreto, y manteniéndolo en la misma familia.
     --color-border-tint es el borde de las tarjetas: comparte temperatura con
     el primary, para que un borde neutro cálido no se ensucie sobre un fondo
     teñido frío (o al revés). */
  --color-surface-tint:  color-mix(in srgb, var(--color-primary) 6%, var(--color-surface));
  --color-border-tint:   color-mix(in srgb, var(--color-primary) 14%, var(--color-border));
  /* Espresso y no marrón: casi negro, con la temperatura justa para que el
     cobre se lea como metal encendido a su lado. Un oscuro a media luz
     (L* 25-35) es lo que convierte cobre + oscuro en "todo marrón". */
  --color-primary:       #2A1D16;  /* espresso — anclas oscuras y titulares */
  --color-primary-hover: #1B120D;
  /* Cobre bruñido: la sombra de las esquinas de la placa. Es el ancla del
     grupo de la miel en el catálogo — oscuro para dar peso a media página,
     pero cobre y no espresso, porque todo lo que es miel es cobre. Crema
     encima: 8.1. */
  --color-cobre-oscuro:  #6B3820;
  /* La tinta del cobre va AQUÍ, antes del acento, y no con el resto de la
     rampa: la Guía de marca pinta las muestras en el orden de este bloque,
     y con la tinta detrás del acento la rampa bajaba y volvía a subir
     (cobre, tinta, medio, claro). Así se lee de oscuro a claro. */
  --color-cobre-tinta:   #8A4A28;
  --color-accent:        #BD7650;  /* cobre — el metal a media luz */
  --color-on-primary:    #F7EBE0;

  /* La rampa del cobre, de sombra a brillo. Cinco pasos claramente
     escalonados, y cada uno con UN papel — no hay dos casi iguales, que en la
     Guía de marca se leerían como un error:
       tinta  — cobre legible sobre claro (texto AA: 6.2 sobre lino) y la
                sombra del metal.
       cobre  — el acento, arriba. Iconos (3.2 sobre lino) y botón sobre banda
                oscura (tinta encima: 4.8).
       medio  — el cuerpo del metal.
       claro  — el brillo del metal y el cobre de leer SOBRE espresso (8.8).
       suave  — el cobre hecho superficie. */
  --color-cobre-medio:   #D59370;
  --color-cobre-claro:   #EDB894;
  --color-cobre-suave:   #F3E3D4;

  /* El material. Lo que en la placa hace el cepillado y la luz rasante: un
     barrido de sombra a brillo y vuelta, en diagonal. Va en botones al pasar
     el ratón, en la banda de la miel y en los filetes — nunca como fondo de
     un bloque de texto largo. */
  --metal-cobre: linear-gradient(115deg,
    var(--color-cobre-tinta) 0%, var(--color-accent) 24%, var(--color-cobre-medio) 42%,
    var(--color-cobre-claro) 54%, var(--color-cobre-medio) 66%, var(--color-accent) 84%,
    var(--color-cobre-tinta) 100%);
  /* El mismo metal SIN la sombra, para las superficies que llevan texto
     encima (botones, la banda de la miel). Su punto más oscuro es el cobre, y
     la tinta sobre el cobre da 4.8: con la sombra de --metal-cobre, las
     primeras letras de un botón caían a 2.6 y dejaban de leerse. */
  --metal-cobre-texto: linear-gradient(115deg,
    var(--color-accent) 0%, var(--color-cobre-medio) 30%, var(--color-cobre-claro) 50%,
    var(--color-cobre-medio) 70%, var(--color-accent) 100%);

  /* Tintes del mosaico de tratamientos. Muy lavados a propósito: el mosaico
     tiene que leerse como un solo tejido con variaciones de temperatura, no
     como bloques de colores distintos compitiendo entre sí. */
  --tile-lino:  #FBF2EC;  /* el mismo lino del suelo: sin costura con la intro */
  --tile-arena: #F2E8DD;  /* un 9% más oscura que el lino: se distingue, y es cálida */
  --tile-cobre: #F5E6D8;

  /* --- Tipografía: stacks de sistema, sustituir por la pareja elegida ---
     Sustituir aquí es suficiente y ES el sitio correcto: la sección "Colores y
     tipografía" del Personalizador viene cerrada de fábrica (ver el filtro
     webker_diseno_editable_por_cliente en inc/customizer.php), así que el tema
     no imprime ninguna variable de tipografía y manda esta línea.
     Si se sustituye por una webfont, declararla además con el filtro
     webker_fuente_tema() — es lo único que la encola desde Google Fonts.
     No siempre fue así — el Personalizador imponía system-ui en un <style>
     de prioridad 20, así que quien sustituía esta pareja no veía ningún
     cambio y no había nada que se lo explicara. Ver inc/customizer.php. */
  /* Pareja de la dirección "Latido". Marcellus es una romana de capital
     lapidaria: serena y con oficio, sin el aire de boda que arrastran las
     didonas. Mulish debajo aguanta párrafos largos sin competir.
     Se encolan desde functions.php con el filtro webker_fuente_tema(); si esa
     línea desaparece, aquí solo quedan los stacks de reserva. */
  --font-display: 'Marcellus', Georgia, 'Times New Roman', serif;
  --font-body:    'Mulish', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* --- Escala fluida ------------------------------------------------------
     Era fija en rem, y eso significa que un titular de hero mide lo mismo en
     un monitor que en un móvil de 375px: 52px ahí ocupaban media pantalla y
     partían el titular en cuatro líneas. Con clamp() la escala respira entre
     ~360px y ~1100px de ancho sin una sola media query, y bajan sobre todo
     los cuerpos grandes, que son los que se rompen; de --text-base para abajo
     apenas se mueven, porque el texto de lectura ya estaba bien.
     Es estructura, no identidad: al vestir un proyecto se deja tal cual.

     Los valores son EXACTAMENTE los mismos que en `Proyecto Base - Astro` y
     `Proyecto Base - HTML-CSS-JS`, no una versión parecida. Las tres bases
     comparten sistema de tokens a propósito, y una escala que diverja entre
     ellas rompe justo lo que hace que sean intercambiables. Si se toca aquí,
     hay que tocarla en las tres. */
  --text-xs:  0.75rem;
  --text-sm:  0.875rem;
  --text-base:clamp(1rem, 0.97rem + 0.15vw, 1.0625rem);
  --text-lg:  clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);
  --text-xl:  clamp(1.15rem, 1.05rem + 0.45vw, 1.25rem);
  --text-2xl: clamp(1.35rem, 1.15rem + 0.9vw, 1.5rem);
  --text-3xl: clamp(1.6rem, 1.25rem + 1.55vw, 2rem);
  --text-4xl: clamp(1.9rem, 1.45rem + 2vw, 2.5rem);
  --text-5xl: clamp(2.35rem, 1.6rem + 3.3vw, 3.25rem);

  /* Escala de espaciado completa a propósito (incluye 5/10/20, no solo
     4/6/8/12) — un var(--space-N) a un peldaño que no existe aquí inválida
     el shorthand ENTERO donde se usa sin ningún error visible (caso real:
     .card se quedó con padding:0 en producción por un var(--space-10) que
     no existía todavía). Antes de usar un --space-N nuevo, añadirlo aquí
     primero, nunca inventarlo sobre la marcha en un componente. */
  --space-1: 4px;  --space-2: 8px;  --space-3: 12px;
  --space-4: 16px; --space-5: 20px; --space-6: 24px;
  --space-8: 32px; --space-10: 40px; --space-12: 48px;
  --space-16: 64px; --space-20: 80px; --space-24: 96px;

  --radius-sm: 6px;
  --radius-md: 12px;
  --radius-lg: 20px;
  --radius-full: 999px;
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.06);
  --shadow-md: 0 8px 24px -8px rgba(0,0,0,0.12);
  --shadow-lg: 0 20px 45px -15px rgba(0,0,0,0.18);
  --shadow-glow: 0 0 0 1px color-mix(in srgb, var(--color-primary) 12%, transparent), 0 20px 50px -16px color-mix(in srgb, var(--color-primary) 45%, transparent);
  --duration-fast: 150ms;
  --duration-base: 250ms;
  --duration-slow: 500ms;
  --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  --container: 1180px;
}

/* --- Reset --- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* scroll-padding-top (de la base): la cabecera es sticky, y sin esto un ancla
   (las categorías del hub) o el foco al tabular quedaban debajo de ella
   (WCAG 2.4.11). */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 88px; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0s !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
}

/* --- Accesibilidad: foco visible y skip link (ver skill accesibilidad-web) --- */
:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}
/* Texto solo para lectores de pantalla. Lo necesita, por ejemplo, cada celda
   de la tabla comparativa de precios: una celda con solo un ✓ dibujado se
   leería como una celda vacía. clip-path y no display:none, que sacaría el
   texto del árbol de accesibilidad y lo dejaría igual de mudo. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0; padding: 0; margin: -1px;
}
.skip-link {
  position: absolute; top: -100%; left: var(--space-4);
  background: var(--color-primary); color: var(--color-on-primary);
  padding: var(--space-3) var(--space-6); border-radius: var(--radius-sm);
  z-index: 9999; transition: top var(--duration-fast) var(--ease-out);
}
.skip-link:focus { top: var(--space-4); }

body {
  min-height: 100dvh;
  font-family: var(--font-body);
  background: var(--color-bg);
  color: var(--color-ink);
  font-size: var(--text-base);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, picture, video, canvas, svg { display: block; max-width: 100%; height: auto; }
input, button, textarea, select { font: inherit; }
a { color: inherit; text-decoration: none; }

/* Enlaces dentro del texto: subrayados (base 2026-09-23). El reset de arriba
   les quita el subrayado y el color, y sin esto un enlace en mitad de una
   legal, de una respuesta del FAQ o de la descripción de un tratamiento no se
   distinguía del texto (accesibilidad-web, Fase 5: nunca el color como único
   indicador; aquí ni siquiera cambiaba). Solo el contenido que se escribe en
   el editor: menú, pie, botones y listas de navegación con clase no lo llevan.
   `.servicio-cuerpo .prosa` es la descripción de la ficha de Shunku. */
:is(.page-content, .servicio-cuerpo .prosa) :is(p, td, ul:not([class]) li, ol:not([class]) li) a:not(.btn),
.faq-item > div a:not(.btn) {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}
ul { list-style: none; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.01em;
  /* Reparte las palabras entre las líneas en vez de dejar una suelta al
     final: es la diferencia entre un titular maquetado y uno que cae donde
     cae. El navegador que no lo soporte simplemente lo ignora. */
  text-wrap: balance;
}

/* El cuerpo, en cambio, NUNCA con balance (es caro y no aporta): pretty solo
   evita la palabra huérfana en la última línea. Y la medida de línea se topa
   en ~68 caracteres: un párrafo a todo el ancho de un monitor no se lee. */
p, li { text-wrap: pretty; }
/* Con las clases que pintan de verdad las plantillas (base 2026-09-25): antes
   era `.prose p, .lead`, que no existen en el tema y el tope no se aplicaba
   en ninguna parte. Entradillas, respuestas del FAQ y el texto de las
   páginas genéricas y legales. (El FAQ de Shunku lo topa shunku.css a 72ch y
   gana; .prosa ya iba a 68ch.) */
.section-lead, .faq-item > div, .page-content p, .page-content li { max-width: 68ch; }

/* --- Layout --- */
.container { max-width: var(--container); margin-inline: auto; padding-inline: var(--space-6); }
.section { padding-block: var(--space-24); }
.section--surface { background: var(--color-surface); }
/* REGLA: dos secciones consecutivas NUNCA se distinguen solo por el salto de
   --color-bg a --color-surface. Aquí eso es un 1% y el ojo no lo percibe: se
   leen como un único bloque plano, y en cuanto aparece una sección con color
   de verdad esa parte parece de otra web. Si dos secciones seguidas deben
   diferenciarse, una lleva .section--tint.
   REGLA 2: no dejar más de ~40% de la altura de la página sin un punto de peso
   (.section--dark). Ver ritmo-y-jerarquia.md en la skill frontend-design-pro. */
.section--tint { background: var(--color-surface-tint); }

/* Pesos de sección: con el mismo padding en todas, todas hablan al mismo
   volumen y ninguna destaca. Escala de tres pasos: 64 / 96 / 128px.
   --tight para bloques que ya traen su propio aire dentro (una cita, un
   banner); --loose para las secciones protagonistas. */
.section--tight { padding-block: var(--space-16); }
.section--loose { padding-block: calc(var(--space-24) + var(--space-8)); }
/* .section--dark redefine sus propios tokens de contraste (--color-muted,
   --color-border) para todo lo que contenga — de fábrica esos tokens están
   pensados para fondo claro, e ilegibles sobre un color sólido oscuro
   (caso real: el texto de apoyo del contacto se volvía invisible al usar
   .section--dark con la paleta de un cliente). Así cualquier componente
   que use esos tokens dentro de esta sección se corrige solo. */
.section--dark :focus-visible { outline-color: var(--color-on-primary); } /* de la base: el anillo espresso no se veía sobre el fondo espresso */
.section--dark {
  background: var(--color-primary); color: var(--color-on-primary);
  --color-muted: color-mix(in srgb, var(--color-on-primary) 78%, transparent);
  --color-border: color-mix(in srgb, var(--color-on-primary) 25%, transparent);
}
.section--dark .eyebrow { color: color-mix(in srgb, var(--color-on-primary) 90%, transparent); }
/* El botón primario suele compartir color con el fondo de .section--dark
   (mismo --color-primary) y se funde con él — aquí se fuerza a usar el
   acento, que si la paleta está bien elegida siempre contrasta. */
.section--dark .btn-primary { background: var(--color-accent); color: var(--color-ink); }
.section--dark .btn-primary::before { background: var(--color-on-primary); }
.section-head { max-width: 640px; margin-bottom: var(--space-12); }
.section-head--center { margin-inline: auto; text-align: center; }
.eyebrow {
  font-size: var(--text-sm); font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--color-accent); margin-bottom: var(--space-3);
}
.section-title { font-size: var(--text-4xl); margin-bottom: var(--space-4); }
.section-lead { font-size: var(--text-lg); color: var(--color-muted); }

/* Texto en degradado — envolver la palabra a destacar dentro de un
   título en <span class="text-gradient">. Con la paleta neutra de
   partida el degradado es casi monocromo (a propósito); al sustituir
   los tokens de color por la identidad real, cobra vida solo. */
.text-gradient {
  background: linear-gradient(100deg, var(--color-primary), var(--color-accent));
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; color: transparent;
}

/* --- Botones --- */
.btn {
  position: relative; overflow: hidden; z-index: 0;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  padding: var(--space-3) var(--space-6);
  border-radius: var(--radius-full);
  font-weight: 600; font-size: var(--text-base);
  border: 1px solid transparent;
  transition: transform var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out), color var(--duration-base) var(--ease-out);
}
.btn-primary { background: var(--color-primary); color: var(--color-on-primary); }
.btn-primary::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--color-accent);
  transform: translateX(-101%); transition: transform var(--duration-base) var(--ease-out);
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: var(--shadow-glow); }
.btn-primary:hover::before { transform: translateX(0); }
/* Aquí había un barrido de relleno igual que el del botón primario. Se ha
   quitado por dos motivos, verificados en pantalla en un proyecto real:

   1) El texto pasaba a blanco (--color-on-primary) de golpe mientras el
      morado entraba barriendo desde la izquierda, así que durante 250 ms
      había texto blanco sobre el fondo claro de la página: las últimas
      letras desaparecían. Sobre .btn-primary no pasa, porque ahí el fondo ya
      es morado de partida — por eso el mismo efecto está bien en uno y mal
      en el otro.
   2) El rectángulo creciendo dentro de una píldora recortada deja un canto
      recto contra el borde curvo, y a mitad de camino se lee como una banda
      rara bajo el texto.

   Y hay una razón de jerarquía para no limitarse a arreglar el temporizado:
   un botón secundario que al pasar por encima se rellena de color sólido
   acaba siendo idéntico al primario, con lo que los dos compiten justo
   cuando el visitante está decidiendo. Ahora se afirma sin cambiar de
   categoría: borde y texto toman el color de marca, y el botón se levanta. */
.btn-secondary {
  background: transparent; border-color: var(--color-border); color: var(--color-ink);
  transition: transform var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out),
              color var(--duration-base) var(--ease-out),
              border-color var(--duration-base) var(--ease-out);
}
.btn-secondary:hover {
  color: var(--color-primary);
  border-color: var(--color-primary);
  transform: translateY(-2px);
  box-shadow: 0 8px 20px -10px color-mix(in srgb, var(--color-primary) 55%, transparent);
}

/* --- Estados de pulsacion ---
   Es fácil terminar una web entera sin un solo :active. En escritorio no se
   nota porque el hover ya da feedback, pero en móvil NO HAY HOVER: sin esto,
   cada botón y cada tarjeta se sienten muertos al tocarlos. El gesto es
   mínimo, solo que el elemento ceda bajo el dedo y vuelva.
   OJO con la cascada: cada :active va DESPUES del :hover de su componente. A
   igual especificidad gana la última regla, y al pulsar se esta también en
   hover, así que un :active declarado antes no hace nada. */
.btn:active { transform: translateY(0) scale(0.97); transition-duration: var(--duration-fast); }
.card:active, .area-card:active { transform: translateY(-2px) scale(0.992); transition-duration: var(--duration-fast); }

/* --- Página actual en el menú ---
   Marcar donde esta el visitante es el olvido más frecuente de una cabecera.
   En WordPress las clases las emite wp_nav_menu solo; en HTML/Astro hay que
   poner .is-current a mano en el enlace de la página que se esta viendo. */
.nav-list .is-current > a,
.nav-list a.is-current,
.nav-list .current-menu-item > a,
.nav-list .current_page_parent > a { color: var(--color-primary); }


/* Latido suave — clase de apoyo para el CTA que más importa destacar
   (p.ej. el primario del hero o de un CTA de cierre). Opt-in a propósito:
   añadir .cta-pulse solo al botón que de verdad debe llamar la atención,
   no a todos. Se pausa al hover. */
.cta-pulse { animation: cta-heartbeat 2.6s ease-in-out infinite; animation-delay: 1.2s; }
.cta-pulse:hover { animation-play-state: paused; }
@keyframes cta-heartbeat {
  0%, 40%, 100% { transform: scale(1); }
  10% { transform: scale(0.96); }
  20% { transform: scale(1.05); }
  30% { transform: scale(0.98); }
}
@media (prefers-reduced-motion: reduce) { .cta-pulse { animation: none; } }

/* --- Header / nav --- */
.header {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--color-bg) 90%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--duration-base) var(--ease-out);
}
.header.is-scrolled { border-bottom-color: var(--color-border); }
.header .container { display: flex; align-items: center; justify-content: space-between; padding-block: var(--space-4); }
.logo-text { font-family: var(--font-display); font-weight: 700; font-size: var(--text-lg); }
/* Un solo <nav> para escritorio y móvil (seo-tecnico →
   arquitectura-y-enlazado.md, ARQ-13), como en Proyecto-Base-WordPress: el
   botón no abre una copia de los enlaces, despliega este mismo <nav>
   (webker_nav_principal(), inc/secciones.php), y el .header-cta va dentro.
   Antes había un segundo menú para móvil (template-parts/header/menu-movil.php)
   con los mismos enlaces repetidos. .nav-panel es el ÚNICO hijo del <nav>: lo
   exige la animación de altura de móvil (grid-template-rows 0fr → 1fr). */
.nav-panel { display: flex; align-items: center; gap: var(--space-8); }
.nav-list { display: flex; gap: var(--space-8); }
.nav-list a { font-size: var(--text-sm); font-weight: 500; }
.nav-list a:hover { color: var(--color-accent); }
/* El teléfono dentro del panel, solo en móvil. */
.nav-tel { display: none; font-weight: 600; font-size: var(--text-lg); }
/* El botón del menú (webker_boton_menu()) va vacío, sin ☰: ese carácter no
   está en las fuentes del tema y salía el recuadro de glifo ausente. El
   icono son dos filetes del mismo grosor que las demás líneas de la
   identidad; font-size: 0 por si algún día vuelve a llevar texto. */
.nav-toggle {
  display: none; background: none; border: none; padding: 0;
  position: relative; width: 44px; height: 44px; font-size: 0; color: inherit;
}
.nav-toggle::before, .nav-toggle::after {
  content: ''; position: absolute; left: 50%; width: 22px; height: 1px;
  background: currentColor; transform: translateX(-50%);
  transition: transform var(--duration-base) var(--ease-out), opacity var(--duration-base) var(--ease-out);
}
.nav-toggle::before { top: 18px; }
.nav-toggle::after { top: 25px; }
/* Abierto, los dos filetes se cruzan: la misma pieza sirve de cerrar. */
.nav-toggle[aria-expanded="true"]::before { top: 21px; transform: translateX(-50%) rotate(45deg); }
.nav-toggle[aria-expanded="true"]::after { top: 21px; transform: translateX(-50%) rotate(-45deg); }

/* --- Submenús ---
   Las cuatro cabeceras piden `depth => 2` a wp_nav_menu, así que WordPress
   puede devolver un <ul class="sub-menu"> anidado en cuanto alguien cuelgue
   una página de otra en Apariencia → Menús. Sin estas reglas ese submenú se
   pintaba como una lista suelta empujando la cabecera hacia abajo: la
   jerarquía existía en el menú y no existía en la pantalla.

   Se abre con :hover y con :focus-within — lo segundo no es un extra, es lo
   que hace que el submenú sea alcanzable con el tabulador. Sin él, los hijos
   son inaccesibles con teclado aunque estén en el DOM.

   La transición la neutraliza el bloque global de prefers-reduced-motion del
   reset; no hace falta repetirlo aquí. En móvil (más abajo) los dos niveles
   se ven siempre dentro del panel. */
@media (min-width: 861px) {
  .nav-list > li { position: relative; }
  .nav-list .sub-menu {
    position: absolute; top: 100%; left: calc(var(--space-4) * -1);
    display: flex; flex-direction: column; gap: var(--space-3);
    min-width: 14rem;
    /* El padding superior hace de puente: el submenú arranca pegado al borde
       inferior del <li> (top:100%, sin margen), de modo que el ratón no
       atraviesa ningún hueco al bajar y el menú no se cierra a medio camino. */
    padding: var(--space-4);
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    opacity: 0; visibility: hidden; translate: 0 -6px;
    transition: opacity .18s ease, translate .18s ease, visibility .18s;
    z-index: 30;
  }
  .nav-list .menu-item-has-children:hover > .sub-menu,
  .nav-list .menu-item-has-children:focus-within > .sub-menu {
    opacity: 1; visibility: visible; translate: 0 0;
  }
  .nav-list .sub-menu a { white-space: nowrap; }
  /* «Ver todo sobre…» (inc/menus.php, base 1.4.0): la página madre, primera
     del panel y separada de las hijas, para que se lea como «la página
     entera» y no como una hija más. */
  .nav-list .menu-item-ver-todo { padding-bottom: var(--space-3); border-bottom: 1px solid var(--color-border); }
  /* Señal de que el elemento despliega: sin ella el visitante no sabe que hay
     nada debajo y el submenú solo lo descubre quien pase el ratón por encima
     por casualidad. */
  .nav-list .menu-item-has-children > a::after {
    content: ''; display: inline-block; margin-left: .4em;
    width: .38em; height: .38em;
    border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
    transform: translateY(-.15em) rotate(45deg);
  }
}

/* El CTA de la cabecera, en variante compacta en escritorio (base
   2026-09-25): con el padding del botón general domina la barra
   (frontend-design-pro → cabecera-y-navegacion.md). Por debajo de 860px va
   dentro del panel y recupera el tamaño normal. */
@media (min-width: 861px) {
  .header-cta { padding: var(--space-2) var(--space-5); font-size: var(--text-sm); }
}

@media (max-width: 860px) {
  .nav-toggle { display: block; }
  /* Panel desplegable bajo la cabecera (el .header es sticky o absolute:
     hace de contenedor del absolute). Se abre animando la altura sin medirla
     en JS, y visibility: hidden saca sus enlaces del orden de foco mientras
     está cerrado. El retardo de visibility solo va al CERRAR, para que la
     animación de cierre se vea entera. En la portada (cabecera flotante) es
     una capa a pantalla completa: shunku.css, «Menu movil sobre cabecera
     flotante». */
  .nav {
    position: absolute; top: 100%; left: 0; right: 0;
    display: grid; grid-template-rows: 0fr;
    visibility: hidden;
    background: var(--color-bg);
    border-top: 1px solid var(--color-border);
    transition: grid-template-rows var(--duration-base) var(--ease-out),
                visibility 0s linear var(--duration-base);
  }
  .nav.is-open {
    grid-template-rows: 1fr;
    visibility: visible;
    transition: grid-template-rows var(--duration-base) var(--ease-out), visibility 0s;
  }
  /* Sin padding en .nav-panel: con la fila a 0fr, el padding no se pliega.
     El aire va en la lista y en el botón. Y se desplaza por dentro (base
     caa3d46): el panel cuelga de la cabecera fija, así que lo que no cabe
     en la pantalla no se alcanza desplazando la página. */
  .nav-panel {
    min-height: 0; overflow: hidden;
    max-height: calc(100dvh - 4.5rem);
    flex-direction: column; align-items: stretch; gap: var(--space-4);
  }
  .nav.is-open .nav-panel { overflow-y: auto; overscroll-behavior: contain; }
  /* Con la altura topada, un flex en columna encoge a sus hijos para que
     quepan en vez de desbordar: el botón «Pedir cita» salía aplastado a la
     mitad. Que no encojan, y lo que sobre se desplaza. */
  .nav-panel > * { flex-shrink: 0; }
  .nav-panel > :first-child { margin-top: var(--space-6); }
  .nav-list, .nav-tel { margin-inline: var(--space-6); }
  .header-cta { margin: 0 var(--space-6) var(--space-6); justify-content: center; }
  /* Mismo aspecto que el panel de antes: lista en columna, texto pequeño, y
     los hijos siempre visibles y sangrados (en móvil no hay hover). */
  .nav-list { flex-direction: column; gap: var(--space-4); }
  .nav-list .sub-menu {
    display: flex; flex-direction: column; gap: var(--space-3);
    margin-top: var(--space-3); padding-left: var(--space-4);
    border-left: 1px solid var(--color-border);
  }
  .nav-list .sub-menu a { font-weight: 400; opacity: .85; }
  .nav-tel { display: block; }
}

/* --- Hero --- */
.hero {
  padding-block: var(--space-24); position: relative; overflow: hidden; isolation: isolate;
  background: radial-gradient(ellipse 90% 70% at 15% 0%, color-mix(in srgb, var(--color-accent) 10%, transparent), transparent 60%);
  background-size: 100% 100%;
}
.hero .container { display: grid; gap: var(--space-12); align-items: center; position: relative; z-index: 1; }
.hero-title { font-size: var(--text-5xl); margin-bottom: var(--space-6); }
.hero-sub { font-size: var(--text-lg); color: var(--color-muted); margin-bottom: var(--space-8); max-width: 52ch; }
.hero-actions { display: flex; gap: var(--space-4); flex-wrap: wrap; }
.hero-media {
  aspect-ratio: 4/3; background: var(--color-surface-raised); border-radius: var(--radius-lg);
  position: relative; overflow: hidden; box-shadow: var(--shadow-lg);
}
.hero-media img { width: 100%; height: 100%; object-fit: cover; }

/* Glows decorativos detrás del hero — aurora animada, sin depender de
   fotografía real. Con la paleta neutra de partida apenas se nota (a
   propósito); al aplicar la identidad de marca cobra presencia solo. */
.hero::before, .hero::after {
  content: ''; position: absolute; border-radius: 50%; filter: blur(80px);
  opacity: 0.35; z-index: -1; pointer-events: none;
  animation: hero-aurora-drift 14s var(--ease-out) infinite alternate;
}
.hero::after { width: 300px; height: 300px; background: var(--color-primary); bottom: -80px; right: 12%; animation-delay: -7s; }
/* En móvil la imagen va debajo del texto y un brillo de 380 px ocupa todo el
   ancho: se baja a la altura de la imagen. */
@media (max-width: 859px) { .hero::before { top: auto; bottom: 10%; } }
@keyframes hero-aurora-drift { 0% { transform: translate(0, 0) scale(1); } 100% { transform: translate(40px, 30px) scale(1.12); } }
@media (prefers-reduced-motion: reduce) { .hero::before, .hero::after { animation: none; } }

/* Cue de scroll — main.js lo inyecta como <a href="#siguiente-sección">
   con este marcado exacto; sin JS no aparece nada (progressive enhancement,
   no hace falta tocar hero.php). */
.hero-scroll-cue {
  position: absolute; left: 50%; bottom: var(--space-6); transform: translateX(-50%);
  display: none; flex-direction: column; align-items: center; gap: var(--space-2);
  color: var(--color-muted); opacity: 0.85;
  transition: opacity var(--duration-base) var(--ease-out), transform var(--duration-base) var(--ease-out);
}
.hero-scroll-cue:hover { opacity: 1; color: var(--color-primary); transform: translateX(-50%) translateY(-2px); }
.hero-scroll-cue-mouse {
  width: 24px; height: 38px; border: 2px solid currentColor; border-radius: var(--radius-full);
  display: flex; justify-content: center; padding-top: 6px;
}
.hero-scroll-cue-mouse::before {
  content: ''; width: 3px; height: 8px; border-radius: var(--radius-full); background: currentColor;
  animation: hero-scroll-cue-wheel 1.8s var(--ease-out) infinite;
}
@keyframes hero-scroll-cue-wheel { 0% { opacity: 1; transform: translateY(0); } 70%, 100% { opacity: 0; transform: translateY(10px); } }
@media (prefers-reduced-motion: reduce) { .hero-scroll-cue-mouse::before { animation: none; } }

/* La rejilla de dos columnas es de la variante "dividido", NO de todo hero:
   estaba en `.hero .container` y eso metía a la fuerza en la columna
   izquierda a las variantes de una sola columna (centrado, fondo, mosaico),
   que salían a media pantalla. El resto de maquetas de hero vive en
   assets/css/secciones.css. */
@media (min-width: 860px) {
  .hero--dividido .container { grid-template-columns: 1.1fr 0.9fr; }
  .hero-scroll-cue { display: flex; }
}

/* Enlace con flecha que avanza al pasar por encima. Vive aquí y no dentro del
   bloque de una variante porque lo usan variantes de secciones distintas
   (servicios en lista, áreas en columnas y áreas sobrias): metido en el bloque
   de una de ellas, podar esa sección dejaba a las otras sin estilo y sin
   ningún error que lo explicara. */
.enlace-flecha { display: inline-flex; align-items: center; gap: var(--space-2); margin-top: var(--space-4); font-weight: 600; font-size: var(--text-sm); }
.enlace-flecha span { transition: transform var(--duration-base) var(--ease-out); }
.enlace-flecha:hover span { transform: translateX(4px); }

/* --- Grids de tarjetas (servicios, portfolio, blog) --- */
.card-grid { display: grid; gap: var(--space-6); grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); counter-reset: card-index; }
.card {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; align-items: flex-start;
  background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); padding: var(--space-10) var(--space-8) var(--space-8);
  box-shadow: var(--shadow-sm);
  transition: transform var(--duration-base) var(--ease-spring), box-shadow var(--duration-base) var(--ease-out), border-color var(--duration-base) var(--ease-out);
}
.card::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: var(--color-primary); transform: scaleX(0); transform-origin: left;
  transition: transform var(--duration-base) var(--ease-out);
}
.card:hover { transform: translateY(-6px); box-shadow: var(--shadow-glow); border-color: transparent; }
.card:hover::before { transform: scaleX(1); }
.card img { border-radius: var(--radius-sm); margin-bottom: var(--space-4); }
.card h3 { font-size: var(--text-xl); margin-bottom: var(--space-3); line-height: 1.3; }
.card p { color: var(--color-muted); }

/* Icono del servicio (campo "icono" de la meta box) cuando no hay imagen
   destacada — se pinta al tamaño de la insignia numerada que sustituye, no al
   ancho completo de la tarjeta como haría cualquier .card img. */
.card-icono {
  width: 48px; height: 48px; object-fit: contain;
  margin-bottom: var(--space-6); border-radius: var(--radius-sm);
}

/* Insignia numerada cuando la tarjeta no tiene ni imagen destacada ni icono
   — evita dejarla sin ningún elemento visual.
   Un número editorial (01, 02...), no un icono real: no hace falta elegir
   un set de iconos por proyecto para que ya se vea intencionado. */
.card:not(:has(img))::after {
  counter-increment: card-index;
  /* decimal-leading-zero, no un '0' escrito delante: ese cero era LITERAL, así
     que a partir de la décima tarjeta la insignia ponía "010", "011"... Con el
     estilo de contador nativo, WordPress puede tener los servicios que haga
     falta y la numeración sigue bien. */
  content: counter(card-index, decimal-leading-zero); order: -1;
  display: flex; align-items: center; justify-content: center; line-height: 1; overflow: hidden;
  width: 48px; height: 48px; margin-bottom: var(--space-6); flex-shrink: 0;
  border-radius: var(--radius-sm); font-family: var(--font-display);
  font-size: 1.05rem; font-weight: 600; color: var(--color-on-primary);
  background: var(--color-primary);
}

/* --- Portfolio (CPT proyecto) --- */
.portfolio-item { display: block; border-radius: var(--radius-md); overflow: hidden; position: relative; }
.portfolio-item img { margin-bottom: 0; transition: transform var(--duration-base) var(--ease-out); }
.portfolio-item:hover img { transform: scale(1.04); }
.portfolio-item h3 { padding: var(--space-4); background: var(--color-surface); }

/* --- Testimonios --- */
.testimonial-grid { display: grid; gap: var(--space-6); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.testimonial { background: var(--color-surface-raised); border-radius: var(--radius-md); padding: var(--space-8); }
.section-cta { text-align: center; margin-top: var(--space-8); }
.testimonial-rating { color: var(--color-accent); margin-bottom: var(--space-3); letter-spacing: 2px; }
.testimonial-cita p { margin-bottom: var(--space-4); }
.testimonial-cita p:first-of-type::before { content: '\201C'; }
.testimonial-cita p:last-of-type::after { content: '\201D'; }
.testimonial-author { font-weight: 600; font-size: var(--text-sm); }
.testimonial-related { margin-top: var(--space-2); font-size: var(--text-sm); }

/* Estado sin testimonios todavía — front-page.php cae en un <p> suelto
   dentro de .testimonial-grid cuando el CPT está vacío; sin esto se ve
   como un aviso interno roto en vez de un hueco intencionado. */
.testimonial-grid > p {
  grid-column: 1 / -1; text-align: center; max-width: 46ch; margin-inline: auto;
  padding: var(--space-12) var(--space-8); border-radius: var(--radius-lg);
  border: 1px dashed var(--color-border); color: var(--color-muted);
  background: color-mix(in srgb, var(--color-surface-raised) 60%, transparent);
}

/* --- Bloque de cita destacada a color plano (mensaje diferencial, valor
   de marca) — usar en template-parts/filosofia.php o donde convenga. --- */
.quote-block {
  background: var(--color-primary); color: var(--color-on-primary);
  border-radius: var(--radius-lg); padding: var(--space-16) var(--space-12);
  position: relative; overflow: hidden;
}
.quote-block::before {
  content: ''; position: absolute; inset: -20%;
  background: radial-gradient(ellipse 50% 60% at 15% 20%, color-mix(in srgb, var(--color-accent) 35%, transparent), transparent 65%);
  animation: hero-aurora-drift 16s var(--ease-out) infinite alternate;
}
@media (prefers-reduced-motion: reduce) { .quote-block::before { animation: none; } }
.quote-block-text { font-family: var(--font-display); font-size: var(--text-3xl); max-width: 780px; position: relative; }
.quote-block-sub { margin-top: var(--space-6); max-width: 62ch; position: relative; color: color-mix(in srgb, var(--color-on-primary) 82%, transparent); }

/* --- Sección alterna imagen/texto (spotlight de un servicio o tema) --- */
.split-section { display: grid; gap: var(--space-12); align-items: center; }
.split-section__media {
  border-radius: var(--radius-lg); overflow: hidden; aspect-ratio: 4/5;
  background: var(--color-surface-raised); box-shadow: var(--shadow-md);
}
.split-section__media img { width: 100%; height: 100%; object-fit: cover; }
.split-section__eyebrow { margin-bottom: var(--space-3); }
.split-section__title { font-size: var(--text-3xl); margin-bottom: var(--space-4); }
.split-section__text { color: var(--color-muted); margin-bottom: var(--space-6); }
@media (min-width: 860px) {
  .split-section { grid-template-columns: 1fr 1fr; }
  .split-section--reverse .split-section__media { order: 2; }
}

/* --- Galería de proyecto (campo nativo opcional "galeria") --- */
.galeria-proyecto {
  display: grid; gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  margin-top: var(--space-8);
}
.galeria-proyecto img { width: 100%; height: auto; border-radius: var(--radius-md); }

/* --- FAQ --- */
.faq-list { max-width: 760px; margin-inline: auto; display: flex; flex-direction: column; gap: var(--space-3); }
.faq-item {
  background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); padding: var(--space-4) var(--space-6);
}
.faq-item summary { font-weight: 600; cursor: pointer; }
.faq-item div { margin-top: var(--space-3); color: var(--color-muted); }

/* --- Contacto (formulario real lo aporta el plugin SureForms) --- */
.contact-grid { display: grid; gap: var(--space-12); }
.contact-grid > *:first-child { align-self: start; }
/* Datos de contacto directos junto al formulario. El mailto se subrayaba
   solo en el CTA de cierre (.cta-final-email) y aquí no, así que sobre
   .section--dark quedaba idéntico al texto de al lado: un enlace que no
   parece un enlace. Mismo tratamiento en los dos sitios. */
.contact-info-list { margin-top: var(--space-6); font-size: var(--text-sm); }
.contact-info-list a { color: var(--color-muted); text-decoration: underline; text-underline-offset: 3px; }
.contact-info-list a:hover { color: var(--color-on-primary); }

.form-placeholder-notice {
  padding: var(--space-4); border: 1px dashed var(--color-border);
  border-radius: var(--radius-sm); font-size: var(--text-sm);
  /* Mezcla de tinta y superficie, no --color-muted: el aviso va dentro de
     .form-card (blanca) en una .section--dark, que redefine --color-muted
     para fondo oscuro, y salía gris claro sobre blanco (1,5:1, medido en el
     render el 2026-09-26). La tinta y la superficie no cambian. */
  color: color-mix(in srgb, var(--color-ink) 70%, var(--color-surface));
}
/* template-parts/contacto.php ya envuelve el formulario en .form-card,
   pero nunca tuvo estilos propios — sobre .section--dark los campos
   quedaban sueltos directamente sobre el color sólido. Aquí flota en una
   tarjeta clara, con sus propios tokens de contraste reseteados. */
.form-card {
  background: var(--color-surface); border-radius: var(--radius-lg);
  padding: var(--space-8); box-shadow: var(--shadow-lg); color: var(--color-ink);
}

@media (min-width: 860px) {
  .contact-grid { grid-template-columns: 1fr 1fr; }
}

/* --- CTA final ligero (template-parts/cta-final.php) — deliberadamente
   sin mapa ni formulario largo: mensaje + acción directa (WhatsApp,
   teléfono). El contacto completo con mapa+formulario vive en su propia
   página /contacto/ (template-parts/contacto.php); repetirlo también al
   cierre de cada página sobrecarga y no aporta. --- */
.cta-final-inner { max-width: 640px; text-align: center; margin-inline: auto; position: relative; z-index: 1; }
.cta-final-inner .eyebrow { justify-content: center; }
.cta-final-lead { font-size: var(--text-lg); margin-top: var(--space-4); color: var(--color-muted); }
.cta-final-actions { display: flex; gap: var(--space-4); flex-wrap: wrap; justify-content: center; margin-top: var(--space-8); }
/* Esta variante SÍ se rellena al pasar por encima, al revés que el botón
   secundario sobre fondo claro. No es una incoherencia: aquí el botón parte
   de fondo transparente sobre un bloque oscuro y su texto de hover es el
   color primario — sin rellenar quedaría color oscuro sobre fondo oscuro,
   ilegible.
   El relleno se hace con `background` y no con el ::before barrido que había
   antes: ese pseudo-elemento vivía en .btn-secondary y, al quitarlo de allí,
   esta regla se quedaba pintando el fondo de un ::before sin `content`, es
   decir, de un elemento que no existe. Es el efecto colateral clásico de
   borrar un pseudo-elemento del que cuelgan otras reglas, y aquí habría
   dejado el botón del cierre con el texto invisible al pasar el ratón. */
.btn-secondary--on-dark {
  background: transparent;
  border-color: color-mix(in srgb, var(--color-on-primary) 40%, transparent);
  color: var(--color-on-primary);
}
.btn-secondary--on-dark:hover {
  background: var(--color-on-primary);
  color: var(--color-primary);
  border-color: transparent;
}
.cta-final-email { margin-top: var(--space-6); font-size: var(--text-sm); }
.cta-final-email a { color: var(--color-muted); text-decoration: underline; text-underline-offset: 3px; }
.cta-final-email a:hover { color: var(--color-on-primary); }

/* --- Footer --- */
.footer { border-top: 1px solid var(--color-border); background: var(--color-surface); padding-block: var(--space-12) var(--space-6); }
.footer-top {
  display: grid; gap: var(--space-8);
  grid-template-columns: 2fr 1fr 1fr 1fr;
  padding-bottom: var(--space-8);
}
.footer-tagline { margin-top: var(--space-2); color: var(--color-muted); font-size: var(--text-sm); max-width: 32ch; }
/* footer.php imprime .footer-social solo si webker_redes_sociales_en_menus()
   (inc/json-ld.php) encuentra enlaces reales — sin redes enlazadas, este
   bloque simplemente no aparece, cero placeholders vacíos. */
.footer-social { display: flex; gap: var(--space-3); margin-top: var(--space-6); }
.footer-social a {
  display: flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: var(--radius-full);
  border: 1px solid var(--color-border); color: var(--color-muted);
  transition: transform var(--duration-base) var(--ease-spring), background var(--duration-base) var(--ease-out), color var(--duration-base) var(--ease-out), border-color var(--duration-base) var(--ease-out);
}
.footer-social a svg { width: 16px; height: 16px; }
.footer-social a:hover { color: var(--color-on-primary); border-color: transparent; transform: translateY(-3px) scale(1.06); background: var(--color-primary); }
/* h2 y no h3: el pie es una sección hermana del contenido principal, así que
   sus encabezados son de segundo nivel. Con h3, cualquier página cuyo contenido
   no tuviera ningún h2 —la de Contacto, sin ir más lejos— dejaba un salto
   h1 → h3 que un lector de pantalla percibe como un nivel que falta. */
.footer-col-titulo {
  font-size: var(--text-sm); text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--color-muted); margin-bottom: var(--space-3);
}
.footer-col ul { display: flex; flex-direction: column; gap: var(--space-2); }
.footer-menu, .footer-legal-links { display: flex; flex-direction: column; gap: var(--space-2); }
.footer-col a { font-size: var(--text-sm); }
.footer-col a:hover { color: var(--color-accent); }
.footer-bottom {
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-6);
  font-size: var(--text-sm); color: var(--color-muted);
}

@media (max-width: 760px) {
  .footer-top { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 480px) {
  .footer-top { grid-template-columns: 1fr; }
}

/* --- Páginas normales / legales (page.php, single.php, 404.php) --- */
.page-content { max-width: 720px; margin: 0 auto; padding: var(--space-12) var(--space-6); }
.breadcrumbs { font-size: var(--text-sm); color: var(--color-muted); margin-bottom: var(--space-6); }
.breadcrumbs a { color: var(--color-muted); text-decoration: underline; }
.page-content h1 { margin-bottom: var(--space-2); }
.page-content h2 { margin: var(--space-8) 0 var(--space-3); }
.page-content p, .page-content ul, .page-content table { margin-bottom: var(--space-3); }
.page-content table { width: 100%; border-collapse: collapse; }
.page-content th, .page-content td { text-align: left; padding: var(--space-2); border-bottom: 1px solid var(--color-border); }

/* Páginas legales: documento, no marca.
   Las tres legales llevan la plantilla "Página legal" (template-legal.php)
   asignada desde el editor, y solo entonces WordPress pone esta clase en el
   <body>. Se redefinen los DOS tokens de tipografía sobre el contenedor del
   contenido, no `font-family` a secas: así heredan igual titulares, listas y
   tablas (incluida la de cookies de Complianz, que sale dentro) sin un solo
   !important. Cabecera y pie se quedan con la tipografía del sitio a
   propósito — la página se lee como documento sin parecer de otra web.
   Ver skill tema-wordpress, Fase 6, y estructura-proyecto-web → Paso 3. */
.page-template-template-legal .page-content {
  --font-display: Arial, Helvetica, sans-serif;
  --font-body: Arial, Helvetica, sans-serif;
  font-family: var(--font-body);
}

/* --- Paginación estándar de WordPress (the_posts_pagination) --- */
.pagination, .nav-links { display: flex; gap: var(--space-2); justify-content: center; margin-top: var(--space-8); }
.page-numbers {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 40px; height: 40px; border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
}
.page-numbers.current { background: var(--color-primary); color: var(--color-on-primary); border-color: var(--color-primary); }

/* --- Reveal-on-scroll (opcional — ver skill animaciones-web). Añadir la
   clase .reveal a cualquier elemento para activarlo; sin la clase, no hace
   nada. Mismo patrón que las bases HTML-CSS-JS y Astro. --- */
/* El estado oculto va en :not(.is-visible) y el visible NO declara transform
   (base 2026-09-25): un «.reveal.is-visible { transform: translateY(0) }» pesa
   lo mismo que un «:hover» y va después, así que le ganaba y cualquier pieza
   con reveal que se moviera al pasar por encima se quedaba quieta. En Shunku
   no rompía nada porque shunku.css lo esquivaba pieza a pieza. */
.reveal:not(.is-visible) { opacity: 0; transform: translateY(24px); }
/* Con movimiento reducido, lo que lleva reveal se ve desde el primer pintado,
   sin esperar al JS: no hay entrada que animar. Mismo bloque en las tres
   bases. */
@media (prefers-reduced-motion: reduce) {
  .reveal:not(.is-visible) { opacity: 1; transform: none; }
}
.reveal {
  /* El retardo del escalonado vive en --reveal-delay y SOLO lo consume esta
     transición de entrada. Puesto como transition-delay suelto (o inline con
     style.transitionDelay) se queda pegado al elemento para siempre y lo
     heredan todas sus transiciones: la sexta tarjeta de una rejilla acabaría
     tardando medio segundo en responder al hover. Ver la skill
     animaciones-web. Uso: <div class="reveal" style="--reveal-delay:120ms"> */
  transition: opacity var(--duration-slow) var(--ease-out) var(--reveal-delay, 0ms),
              transform var(--duration-slow) var(--ease-out) var(--reveal-delay, 0ms);
}

/* Variante para titulares — "expansión de tracking" al entrar en pantalla
   en vez del translateY genérico. main.js la añade sola a .section-title/
   .quote-block-text (ver "Titulares de sección" en main.js); el H1 del
   hero se queda fuera a propósito, es lo primero que ve el visitante. */
.reveal-title {
  /* "Enfocar" con filter:blur, NO expandir letter-spacing. letter-spacing es
     una propiedad de layout: provoca reflujo en cada fotograma y, en un
     titular de dos líneas, las palabras se recolocan de línea a media
     animación. blur va compuesto en GPU y da el mismo gesto editorial sin
     tocar el layout. Ver la skill animaciones-web. */
  opacity: 0; filter: blur(7px); transform: none;
  transition: opacity var(--duration-slow) var(--ease-out) var(--reveal-delay, 0ms),
              filter var(--duration-slow) var(--ease-out) var(--reveal-delay, 0ms);
}
.reveal-title.is-visible { opacity: 1; filter: blur(0); }
@media (prefers-reduced-motion: reduce) { .reveal-title { filter: none; } }

/* --- Botón "volver arriba" (opcional, Personalizar → Botones flotantes) ---
   Píldora que se expande con una etiqueta al hover (inyectada por main.js,
   no hace falta tocar footer.php) — más reconocible que un círculo mudo. */
.scroll-top-btn {
  position: fixed; left: var(--space-6); bottom: var(--space-6);
  width: 48px; height: 48px; border-radius: var(--radius-full);
  display: flex; align-items: center; justify-content: center;
  background: var(--color-primary); color: var(--color-on-primary); overflow: hidden;
  border: none; box-shadow: var(--shadow-md); padding: 0;
  opacity: 0; visibility: hidden; transform: translateY(8px);
  transition: opacity var(--duration-base) var(--ease-out),
              transform var(--duration-base) var(--ease-spring),
              visibility var(--duration-base) var(--ease-out),
              width var(--duration-base) var(--ease-spring),
              background var(--duration-base) var(--ease-out),
              box-shadow var(--duration-base) var(--ease-out);
  z-index: 60;
}
.scroll-top-btn.is-visible { opacity: 1; visibility: visible; transform: translateY(0); }
.scroll-top-btn svg { flex-shrink: 0; transition: transform var(--duration-base) var(--ease-spring); }
.scroll-top-btn span {
  width: 0; overflow: hidden; white-space: nowrap; font-size: var(--text-sm); font-weight: 600;
  transition: width var(--duration-base) var(--ease-out), margin-left var(--duration-base) var(--ease-out);
}
.scroll-top-btn:hover { width: 132px; box-shadow: var(--shadow-glow); background: var(--color-accent); color: var(--color-ink); }
.scroll-top-btn:hover svg { transform: translateY(-1px); }
.scroll-top-btn:hover span { width: 52px; margin-left: var(--space-2); }

/* --- CTA fijo de WhatsApp (opcional, Personalizar → Botones flotantes) --- */
.whatsapp-cta {
  position: fixed; right: var(--space-6); bottom: var(--space-6);
  width: 56px; height: 56px; border-radius: var(--radius-full);
  display: flex; align-items: center; justify-content: center;
  background: #25D366; color: #FFFFFF;
  box-shadow: var(--shadow-md);
  transition: transform var(--duration-fast) var(--ease-out);
  z-index: 60;
}
.whatsapp-cta:hover { transform: translateY(-2px) scale(1.03); }

/* En pantallas estrechas, el botón "volver arriba" y el CTA de WhatsApp
   pueden convivir con el CTA fijo de móvil si lo hubiera — se dejan a los
   lados opuestos a propósito (scroll-top a la izquierda, WhatsApp a la
   derecha) para no solaparse nunca entre sí. */

/* --- Mapa de Google (opcional, Personalizar → Mapa de contacto) --- */
.contact-map {
  margin-top: var(--space-8);
  border-radius: var(--radius-md);
  overflow: hidden;
  border: 1px solid var(--color-border);
  aspect-ratio: 16 / 9; max-height: 320px;
}
.contact-map iframe { width: 100%; height: 100%; border: 0; display: block; }

/* La placa del mapa (webker_mapa_contacto con dirección). Oculta por
   defecto; solo aparece mientras Complianz tiene el mapa bloqueado, que es
   cuando mete .cmplz-blocked-content-container alrededor del iframe. Tapa
   la foto genérica de mapa que pone el plugin y esconde su botón, que queda
   descolocado: el consentimiento se da desde el botón de la placa. */
.contact-map { position: relative; }
.contact-map-placa { display: none; }
.contact-map:has(.cmplz-blocked-content-container) .contact-map-placa {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-3); padding: var(--space-6);
  text-align: center;
  background: var(--color-surface);
}
.contact-map:has(.cmplz-blocked-content-container) .cmplz-blocked-content-notice { display: none !important; }
.contact-map-placa p { margin: 0; }
.contact-map-placa-rotulo { font-size: var(--text-xs); letter-spacing: .14em; text-transform: uppercase; color: var(--color-muted); }
.contact-map-placa-direccion { font-family: var(--font-display); font-size: var(--text-2xl); line-height: 1.2; text-wrap: balance; }
.contact-map-placa-localidad { margin-top: calc(-1 * var(--space-2)) !important; }
.contact-map-placa-acciones { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: var(--space-3) var(--space-6); margin-top: var(--space-2); }
.contact-map-placa-enlace {
  display: inline-block; padding: var(--space-3) var(--space-6);
  border: 1px solid currentColor; text-decoration: none; font-weight: 600;
}
.contact-map-placa-ver {
  background: none; border: 0; padding: var(--space-2) 0; cursor: pointer;
  font: inherit; color: inherit; text-decoration: underline; text-underline-offset: .3em;
}
.contact-map-placa-nota { font-size: var(--text-sm); color: var(--color-muted); }

/* --- 404 --- */
.error-404-rejilla { display: grid; gap: var(--space-12); align-items: center; }
.error-404-texto { max-width: 36rem; }
.error-404-enlaces { list-style: none; margin: var(--space-6) 0 var(--space-8); padding: 0; border-top: 1px solid var(--color-border); }
.error-404-enlaces li { border-bottom: 1px solid var(--color-border); }
.error-404-enlaces a { display: block; padding: var(--space-3) 0; font-size: var(--text-lg); text-decoration: none; }
.error-404-placa {
  display: grid; place-items: center;
  aspect-ratio: 4 / 5; width: min(100%, 360px); justify-self: center;
  background: var(--color-surface); border: 1px solid var(--color-border);
  font-family: var(--font-display); font-size: clamp(4rem, 12vw, 7rem); line-height: 1;
}
@media (min-width: 860px) {
  .error-404-rejilla { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); }
}

/* --- Hueco de fotografia (template-parts/foto-hueco.php) ----------------
   Casi ningun proyecto tiene las fotos el dia que se ensena la primera
   version. Esto reserva la proporcion exacta que ocupara la foto real, para
   que al sustituirlo no se mueva nada de la maqueta.
   Se ve deliberadamente como un hueco pendiente y no como una imagen rota:
   el borde punteado y el texto dicen que foto falta.
   El color sale del --color-primary del proyecto, asi que se tine solo al
   sustituir la paleta y nunca desafina respecto a la marca del cliente. */
.foto-hueco {
  aspect-ratio: var(--foto-ratio, 4 / 3);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-3);
  border: 1px dashed color-mix(in srgb, var(--color-primary) 28%, transparent);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--color-primary) 5%, var(--color-surface));
  color: color-mix(in srgb, var(--color-primary) 72%, transparent);
  padding: var(--space-6);
  text-align: center;
}
.foto-hueco-icono { width: 34px; height: 34px; opacity: .75; }
.foto-hueco-texto {
  font-size: var(--text-sm); font-weight: 600;
  letter-spacing: .01em; max-width: 24ch; line-height: 1.4;
}

/* --- Aviso de montaje (webker_aviso_de_montaje, functions.php) ----------
   Notas dirigidas a QUIEN CONSTRUYE el sitio, nunca al visitante: solo se
   pintan mientras el modo en construccion esta activo. Se distinguen a
   proposito del resto del contenido, para que nadie las confunda con texto
   del cliente ni se quede una sin sustituir. */
.aviso-montaje {
  border: 1px dashed color-mix(in srgb, var(--color-primary) 35%, transparent);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--color-primary) 4%, var(--color-surface));
  color: var(--color-muted);
  padding: var(--space-4);
  font-size: var(--text-sm);
  margin: 0;
}

/* La flecha de «Ver todo sobre…», en los dos tamaños (inc/menus.php, base 1.4.0). */
.nav-list .menu-item-ver-todo > a { font-weight: 600; }
.nav-list .menu-item-ver-todo > a::after {
  content: ''; display: inline-block; margin-left: .45em;
  width: .4em; height: .4em;
  border-top: 1.5px solid currentColor; border-right: 1.5px solid currentColor;
  transform: translateY(-.1em) rotate(45deg);
}
