/* ============================================================
   PROENERGY — SISTEMA DE DISEÑO (Fase 4)
   Hoja de estilos central. Toda decisión visual del sitio sale
   de estas variables. Si un valor no está aquí, no se usa.

   Requiere en el <head> de cada página (además de esta hoja):
   <link href="https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
   ============================================================ */

/* ------------ TIPOGRAFÍAS DE LA IDENTIDAD ------------ */
/* Sinkin Sans: misma fuente del material impreso (autoalojada) */
@font-face {
  font-family: 'Sinkin Sans';
  src: url('../Fonts/SinkinSans/SinkinSans-700Bold.woff2') format('woff2'),
       url('../Fonts/SinkinSans/SinkinSans-700Bold.otf') format('opentype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Sinkin Sans';
  src: url('../Fonts/SinkinSans/SinkinSans-800Black.woff2') format('woff2'),
       url('../Fonts/SinkinSans/SinkinSans-800Black.otf') format('opentype');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}

/* ------------ VARIABLES (tokens del sistema) ------------ */
:root {
  /* Color — paleta oficial PE_paleta-de-color */
  --pe-crema:   #F0EEE9;  /* fondo base */
  --pe-marino:  #151F2F;  /* secciones de contraste */
  --pe-teal:    #11363E;  /* secundario */
  --pe-naranja: #FE4306;  /* EXCLUSIVO CTA principal — máx. 1 por pantalla */
  --pe-naranja-hover: #d93800;
  --pe-carbon:  #292C2D;  /* texto sobre fondos claros */
  --pe-blanco:  #FFFFFF;
  --pe-whatsapp: #25D366; /* solo el botón flotante */

  /* Tipografía */
  --pe-font-head: 'Sinkin Sans', 'Arial Black', sans-serif;   /* titulares 700/800 */
  --pe-font-body: 'Instrument Sans', 'Segoe UI', sans-serif;  /* texto */
  --pe-font-num:  'JetBrains Mono', 'Consolas', monospace;    /* TODAS las cifras */

  /* Escala tipográfica — 6 niveles, sin excepciones */
  --pe-fs-display:  clamp(2.1rem, 6vw, 3.25rem);   /* 1. Hero */
  --pe-fs-title:    clamp(1.55rem, 4.5vw, 2.25rem);/* 2. Título de sección */
  --pe-fs-subtitle: clamp(1.15rem, 3vw, 1.4rem);   /* 3. Subtítulo / título de tarjeta */
  --pe-fs-lead:     clamp(1.05rem, 2.5vw, 1.2rem); /* 4. Texto destacado */
  --pe-fs-body:     1rem;                          /* 5. Texto normal */
  --pe-fs-small:    0.85rem;                       /* 6. Etiquetas / notas */
  /* Texto de botones (T19): ≥18.66px bold = "texto grande" WCAG, cuyo umbral
     AA es 3:1 — así el blanco sobre el naranja de marca #FE4306 (3.5:1)
     cumple sin alterar el color del impreso. No bajar de 1.17rem. */
  --pe-fs-btn:      1.17rem;

  /* Geometría — idéntica en todo el sitio */
  --pe-radius: 12px;                                /* esquinas (heredado del impreso) */
  --pe-radius-petalo: 44px 12px 44px 12px;          /* geometría del isotipo — EXCLUSIVA de tarjetas de servicio y destacadas */
  --pe-shadow: 0 1px 2px rgba(21, 31, 47, 0.05), 0 12px 32px rgba(21, 31, 47, 0.07); /* sombra en dos capas: contacto + difusa */
  --pe-shadow-hover: 0 2px 4px rgba(21, 31, 47, 0.06), 0 18px 44px rgba(21, 31, 47, 0.11);
  --pe-border-card: 1px solid rgba(21, 31, 47, 0.10);

  /* Ritmo */
  --pe-space-section: clamp(4rem, 9vw, 6.5rem);     /* respiración vertical de secciones */
  --pe-container: 1140px;                           /* ancho máximo uniforme */
  --pe-content: 820px;                              /* ancho máximo de texto corrido */
}

/* ------------ BASE ------------ */
.pe-body,
body.pe {
  background-color: var(--pe-crema);
  color: var(--pe-carbon);
  font-family: var(--pe-font-body);
  font-size: var(--pe-fs-body);
  line-height: 1.7;
  margin: 0;
}

/* ------------ ICONOS SVG INLINE (includes/iconos-svg.php) ------------ */
/* Réplica del render del webfont FA que sustituyen: tamaño por font-size
   del contexto (height=1em en el SVG) y color por currentColor; el
   vertical-align es el mismo que usaba FA. */
.pe-ico {
  display: inline-block;
  vertical-align: -0.125em;
}

/* ------------ ESCALA TIPOGRÁFICA ------------ */
.pe-display {
  font-family: var(--pe-font-head);
  font-weight: 800;
  font-size: var(--pe-fs-display);
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin: 0 0 1rem 0;
}

.pe-title {
  font-family: var(--pe-font-head);
  font-weight: 700;
  font-size: var(--pe-fs-title);
  line-height: 1.2;
  margin: 0 0 1rem 0;
}

.pe-subtitle {
  font-family: var(--pe-font-head);
  font-weight: 700;
  font-size: var(--pe-fs-subtitle);
  line-height: 1.3;
  margin: 0 0 0.6rem 0;
}

.pe-lead {
  font-family: var(--pe-font-body);
  font-size: var(--pe-fs-lead);
  line-height: 1.7;
  margin: 0 0 1rem 0;
}

.pe-text {
  font-family: var(--pe-font-body);
  font-size: var(--pe-fs-body);
  line-height: 1.7;
  margin: 0 0 1rem 0;
}

.pe-small {
  font-family: var(--pe-font-body);
  font-size: var(--pe-fs-small);
  line-height: 1.5;
}

/* TODAS las cifras del sitio: pesos, kWp, años, porcentajes */
.pe-num {
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ------------ CONTENEDORES Y RITMO ------------ */
.pe-container {
  max-width: var(--pe-container);
  margin: 0 auto;
  padding: 0 1.25rem;
}

/* Fix overflow horizontal de 4px por lado (T24) — una fila Bootstrap con
   gutter g-5 dentro de .pe-container aplica margen negativo de -1.5rem (24px)
   por lado, que rebasa el padding del contenedor (1.25rem = 20px) y saca 4px
   de cada lado: jaloneo horizontal en el teléfono, clipado sin barra visible
   en el resto del rango.
   El techo NO es un breakpoint de Bootstrap, se deriva de la caja: mientras el
   contenedor tenga menos de 4px de margen propio, el sobresaliente de 4px cae
   fuera del viewport. Margen del contenedor = (vw - 1140) / 2, así que el
   desborde vive por debajo de 1140 + 2*(24 - 20) = 1148px — medido: a 1147 el
   borde izquierdo de la fila queda en -0.50px y a 1148 en 0.00px.
   La primera versión de este fix (auditoría móvil) cortaba en 767.98px y dejaba
   768-1147.98 sin cubrir.
   Reducir SOLO el gutter horizontal a 2.5rem (margen -1.25rem = exactamente el
   padding del contenedor) elimina el desborde: en móvil las columnas ya están
   apiladas y no se nota, y de 768 a 1147.98 la separación entre columnas pasa
   de 48 a 40px. Arriba de 1148 el contenedor ya tiene margen de sobra y el
   gutter se queda en los 3rem del diseño aprobado. */
@media (max-width: 1147.98px) {
  .pe-container .row.g-5 { --bs-gutter-x: 2.5rem; }
}

.pe-content {
  max-width: var(--pe-content);
  margin: 0 auto;
}

.pe-section {
  padding: var(--pe-space-section) 0;
  background-color: var(--pe-crema);
  color: var(--pe-carbon);
}

/* Sección de contraste: marino con texto crema */
.pe-section--dark {
  background-color: var(--pe-marino);
  color: var(--pe-crema);
}

/* Ritmo: dos secciones claras contiguas comparten respiración — el corte
   visual lo da el cambio de color, no el aire. Las juntas con cambio de
   color conservan el padding completo. La respiración se reparte entre los
   dos lados de la junta: la sección superior recorta su padding inferior y la
   inferior su padding superior, para que el hueco lea como UNA respiración y
   no como dos paddings apilados. */
.pe-section:not(.pe-section--dark) + .pe-section:not(.pe-section--dark) {
  padding-top: calc(var(--pe-space-section) * 0.2);
}
.pe-section:not(.pe-section--dark):has(+ .pe-section:not(.pe-section--dark)) {
  padding-bottom: calc(var(--pe-space-section) * 0.5);
}

/* Excepción puntual: junta clara-clara que necesita el aire completo */
.pe-section--full-gap {
  padding-top: var(--pe-space-section) !important;
}

/* Cuadrícula sutil heredada de los one-pagers (solo sobre marino) */
.pe-grid-pattern {
  background-image:
    linear-gradient(rgba(240, 238, 233, 0.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(240, 238, 233, 0.055) 1px, transparent 1px);
  background-size: 36px 36px;
}

/* ------------ ETIQUETA DE SECCIÓN (kicker) ------------ */
.pe-tag {
  display: inline-block;
  font-family: var(--pe-font-body);
  font-weight: 600;
  font-size: var(--pe-fs-small);
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--pe-teal);
  margin-bottom: 0.9rem;
}

.pe-section--dark .pe-tag {
  color: var(--pe-crema);
  opacity: 0.7;
}

/* ------------ BOTONES (solo estos dos) ------------ */
.pe-btn {
  display: inline-block;
  font-family: var(--pe-font-head);
  font-weight: 700;
  font-size: var(--pe-fs-btn);
  text-decoration: none;
  text-align: center;
  padding: 0.95rem 1.9rem;
  border-radius: var(--pe-radius);
  border: 2px solid transparent;
  cursor: pointer;
  transition: background-color 0.25s ease, color 0.25s ease, transform 0.15s ease;
}

.pe-btn:hover,
.pe-btn:focus {
  transform: translateY(-2px);
}

/* Primario: naranja. REGLA DURA: máx. un elemento naranja por pantalla. */
.pe-btn--primary {
  background-color: var(--pe-naranja);
  color: var(--pe-blanco);
}

.pe-btn--primary:hover,
.pe-btn--primary:focus {
  background-color: var(--pe-naranja-hover);
  color: var(--pe-blanco);
}

/* Secundario: contorno. Toma el color del fondo donde vive. */
.pe-btn--secondary {
  background-color: transparent;
  border-color: var(--pe-marino);
  color: var(--pe-marino);
}

.pe-btn--secondary:hover,
.pe-btn--secondary:focus {
  background-color: var(--pe-marino);
  color: var(--pe-crema);
}

.pe-section--dark .pe-btn--secondary {
  border-color: var(--pe-crema);
  color: var(--pe-crema);
}

.pe-section--dark .pe-btn--secondary:hover,
.pe-section--dark .pe-btn--secondary:focus {
  background-color: var(--pe-crema);
  color: var(--pe-marino);
}

.pe-btn i {
  margin-right: 0.5rem;
}

.pe-btn svg {
  margin-right: 0.5rem;
  vertical-align: -0.2em;
}

@media (max-width: 576px) {
  .pe-btn {
    display: block;
    width: 100%;
    max-width: 420px;
    margin-left: auto;
    margin-right: auto;
  }
}

/* ------------ ENLACE-CTA (.pe-link-cta) — la vía secundaria en texto ------------
   Tercer nivel de llamada a la acción, por debajo del botón de contorno:
   para el segundo camino que SÍ debe estar a la vista pero NO debe pesar como
   botón (§6 — un naranja por viewport, y dos botones lado a lado empatan el
   siguiente paso en lugar de jerarquizarlo). No sustituye a .pe-btn--secondary:
   ése sigue siendo el segundo camino cuando compite de tú a tú.

   Toma el color de su fondo con el mismo criterio que .pe-btn--secondary:
   teal sobre crema, crema sobre superficies oscuras (el teal se pierde contra
   el marino). El subrayado va por text-decoration con offset propio para poder
   adelgazarlo y despegarlo de la línea base; en navegadores sin soporte de
   text-underline-offset queda un subrayado normal — degradación limpia.
   La flecha (→) vive en el copy (clave de idioma), no en el CSS: así el
   traductor decide si la frase la lleva. El anillo de foco lo da la regla
   global de :focus-visible (T19), incluida su rama crema sobre oscuro. ------------ */
.pe-link-cta {
  display: inline-block;
  font-family: var(--pe-font-body);
  font-weight: 600;
  font-size: var(--pe-fs-body);
  letter-spacing: 0.01em;
  /* área táctil de ~44px sin separar el subrayado del texto */
  padding: 0.55rem 0.25rem;
  color: var(--pe-teal);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  text-decoration-color: rgba(17, 54, 62, 0.40);
  transition: color 0.25s ease, text-decoration-color 0.25s ease;
}

.pe-link-cta:hover,
.pe-link-cta:focus {
  color: var(--pe-teal);
  text-decoration-color: currentColor;
}

/* Sobre superficies oscuras (secciones marino, panel marino y los heros de
   foto con velo, que no son .pe-section--dark y van por clase de página —
   misma lista que el foco visible y el CTA pegajoso). */
.pe-section--dark .pe-link-cta,
.pe-card--marino .pe-link-cta,
.home-hero .pe-link-cta,
.svc-hero .pe-link-cta,
.sol-hero .pe-link-cta,
.ps-hero .pe-link-cta,
.ele-hero .pe-link-cta,
.rsc-hero .pe-link-cta,
.bess-hero .pe-link-cta,
.calc-hero .pe-link-cta {
  color: var(--pe-crema);
  text-decoration-color: rgba(240, 238, 233, 0.50);
}

.pe-section--dark .pe-link-cta:hover,
.pe-section--dark .pe-link-cta:focus,
.pe-card--marino .pe-link-cta:hover,
.pe-card--marino .pe-link-cta:focus,
.home-hero .pe-link-cta:hover,
.home-hero .pe-link-cta:focus,
.svc-hero .pe-link-cta:hover,
.svc-hero .pe-link-cta:focus,
.sol-hero .pe-link-cta:hover,
.sol-hero .pe-link-cta:focus,
.ps-hero .pe-link-cta:hover,
.ps-hero .pe-link-cta:focus,
.ele-hero .pe-link-cta:hover,
.ele-hero .pe-link-cta:focus,
.rsc-hero .pe-link-cta:hover,
.rsc-hero .pe-link-cta:focus,
.bess-hero .pe-link-cta:hover,
.bess-hero .pe-link-cta:focus,
.calc-hero .pe-link-cta:hover,
.calc-hero .pe-link-cta:focus {
  color: var(--pe-crema);
  text-decoration-color: currentColor;
}

/* ============================================================
   ACCESIBILIDAD — FOCO VISIBLE (T19)
   Anillo de foco SOLO para navegación por teclado (:focus-visible):
   el clic/tap no lo pinta. :where() deja la especificidad en cero,
   así cualquier regla de componente posterior lo afina sin pelear.
   Teal sobre fondos claros; sobre superficies oscuras pasa a crema
   (el teal se pierde: 11363E ≈ 151F2F — misma regla que botones e
   isotipo). Los heros de foto con velo van por clase de página
   (ninguno es .pe-section--dark; misma lista que el CTA pegajoso).
   ============================================================ */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--pe-teal);
  outline-offset: 2px;
}

.pe-section--dark :focus-visible,
.pe footer :focus-visible,
.pe-card--marino :focus-visible,
.pe-step--highlight :focus-visible,
.pe-diag-response :focus-visible,
.pe-sticky-cta :focus-visible,
.pe-lightbox :focus-visible,
.home-hero :focus-visible,
.svc-hero :focus-visible,
.sol-hero :focus-visible,
.ps-hero :focus-visible,
.ele-hero :focus-visible,
.rsc-hero :focus-visible,
.bess-hero :focus-visible,
.calc-hero :focus-visible,
.calc-results :focus-visible,
.calc-mt-panel :focus-visible,
.marsa-hero :focus-visible,
.marsa-cta :focus-visible {
  outline-color: var(--pe-crema);
}

/* Botón flotante de WhatsApp: vive sobre fondo variable (crema o marino
   según el scroll) → anillo doble: blanco pegado + halo teal, visible
   sobre cualquiera de los dos. */
.whatsapp-float:focus-visible {
  outline: 2px solid var(--pe-blanco);
  outline-offset: 2px;
  box-shadow: 0 0 0 7px rgba(17, 54, 62, 0.55);
}

/* ------------ TARJETA — una familia base (borde 1px + sombra en dos capas +
   hover de elevación). Variante pétalo+ficha (--pe-radius-petalo) EXCLUSIVA de
   tarjetas de servicio y tarjetas destacadas. Panel marino: máximo UNA tarjeta
   por página, para destacar. ------------ */
.pe-card {
  background-color: var(--pe-blanco);
  border: var(--pe-border-card);
  border-radius: var(--pe-radius);
  box-shadow: var(--pe-shadow);
  padding: 1.75rem 1.5rem;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

@media (hover: hover) {
  .pe-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--pe-shadow-hover);
  }
}

.pe-section--dark .pe-card {
  background-color: var(--pe-teal);
  color: var(--pe-crema);
  border: 1px solid rgba(240, 238, 233, 0.12);
  box-shadow: none;
}

/* ---- Variante pétalo + ficha técnica (SOLO tarjetas de servicio) ---- */
.pe-card--servicio {
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
  border-radius: var(--pe-radius-petalo);
}

.pe-card-servicio-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 28px 26px 20px;
}

.pe-card-servicio-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 18px 6px 18px 6px; /* eco del pétalo a escala */
  background-color: rgba(17, 54, 62, 0.08);
  color: var(--pe-teal);
  margin-bottom: 0.9rem;
}

.pe-card--servicio .pe-btn {
  border-radius: 16px 6px 16px 6px; /* eco del pétalo, solo en estas tarjetas */
  margin-top: auto;
}

/* Franja técnica inferior */
.pe-card-ficha {
  background-color: var(--pe-crema);
  border-top: 1px solid rgba(21, 31, 47, 0.08);
  padding: 11px 26px 13px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--pe-teal);
}

/* Panel marino — máximo UNA tarjeta por página */
.pe-card--marino {
  background-color: var(--pe-marino);
  background-size: 24px 24px; /* retícula pe-grid-pattern más fina dentro de la tarjeta */
  color: var(--pe-crema);
}

.pe-card--marino .pe-card-servicio-icon {
  background-color: rgba(240, 238, 233, 0.10);
  color: var(--pe-crema);
}

.pe-card--marino .pe-card-ficha {
  background-color: rgba(240, 238, 233, 0.07);
  border-top-color: rgba(240, 238, 233, 0.12);
  color: rgba(240, 238, 233, 0.85);
}

.pe-card--marino .pe-btn--secondary {
  border-color: var(--pe-crema);
  color: var(--pe-crema);
}

.pe-card--marino .pe-btn--secondary:hover,
.pe-card--marino .pe-btn--secondary:focus {
  background-color: var(--pe-crema);
  color: var(--pe-marino);
}

/* ---- Banda de arte en la cabeza de la tarjeta de servicio (.pe-card--arte)
   Reutiliza el idioma estructural de .pe-card--proyecto (arte arriba, cuerpo
   al centro, ficha al pie). El pétalo NO se toca: el overflow:hidden de
   .pe-card--servicio recorta la banda con el radio 44/12, así que el marcador
   de "esto es una línea de servicio" se ve DENTRO del arte.

   La imagen arriba pasa a ser vocabulario COMPARTIDO entre servicio y
   proyecto (decisión de Ricardo, 28-jul-2026): el separador entre las dos
   familias sigue siendo el pétalo, como ya decía el comentario de abajo.

   El nombre es --arte y no --lamina por una razón que YA NO EXISTE: cuando
   esto nació (T27), .pe-card--lamina era la lámina de plano de T21. T36 la
   purgó, así que el nombre está libre — pero renombrar ahora tocaría ocho
   tarjetas publicadas para no ganar nada. Se queda --arte. ---- */
.pe-card-servicio-arte {
  position: relative;
  display: block;
  flex-shrink: 0;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background-color: var(--pe-marino); /* color de reposo mientras carga */
}

.pe-card-servicio-arte img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Con banda, el icono de 44px sobra: dos marcadores apilados se leen como
   relleno. En las tarjetas montadas el <svg> se retiró del HTML, así que esta
   regla es la red: si alguien añade banda a una tarjeta que aún trae icono,
   no salen los dos. El aire que dejaba el icono lo recupera el cuerpo. */
.pe-card--arte .pe-card-servicio-icon { display: none; }
.pe-card--arte .pe-card-servicio-body { padding-top: 22px; }

/* Declaración §3 — una línea al pie de la cuadrícula, no un sello por lámina.
   Además de declarar que las imágenes son ilustrativas, redirige a dónde SÍ
   vive la evidencia (el portafolio). Viaja SIEMPRE con las tarjetas: donde
   haya banda de arte, tiene que haber línea. */
.pe-aviso-ilustrativo {
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--pe-teal);
  opacity: 0.7;
  text-align: center;
  margin: 1.75rem auto 0;
  max-width: 60ch;
}

.pe-section--dark .pe-aviso-ilustrativo {
  color: var(--pe-crema);
  opacity: 0.6;
}

/* ---- Tarjeta de proyecto (portafolio) — radio base 12px, SIN pétalo:
   el pétalo significa servicio, no proyecto. Foto arriba, cuerpo al
   centro y ficha técnica al pie; alturas igualadas vía h-100. ---- */
.pe-card--proyecto {
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
}

.pe-card-proyecto-foto {
  border-radius: 0; /* la esquina la recorta la tarjeta (overflow hidden) */
  height: 200px;
  flex-shrink: 0;
}

@media (max-width: 991px) {
  .pe-card-proyecto-foto { height: 180px; }
}

.pe-card-proyecto-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 22px 26px 18px;
}

.pe-card-proyecto-body .pe-subtitle {
  font-size: 1.05rem;
  line-height: 1.35;
  margin-bottom: 0.5rem;
}

/* Etiqueta mono sobre el nombre (solo la tarjeta destacada la usa) */
.pe-card-proyecto-tag {
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.85;
  margin: 0 0 0.5rem 0;
}

.pe-card--proyecto .pe-btn {
  margin-top: auto;
  align-self: flex-start;
}

/* ---- Tarjeta inmersiva (.pe-card--inmersiva) — T29 ------------------
   La imagen ES la tarjeta: el arte ocupa toda la caja y el texto vive
   encima sobre un degradado marino. Aprobada por Ricardo (28-jul-2026)
   para las 3 tarjetas de "¿Qué tipo de trabajos realizamos?" de
   servicios/infraestructura-electrica, en sustitución de la lámina de
   plano de T21. (Aquella lámina sobrevivió en peak-shaving hasta T35,
   que la cambió por .pe-card--perfil; hoy no queda ninguna publicada.)

   Radio base 12px, SIN pétalo: igual que .pe-card--proyecto, el pétalo
   significa "línea de servicio" y estas tres no lo son.

   El arte es ILUSTRATIVO: la cuadrícula que la use tiene que llevar la
   línea .pe-aviso-ilustrativo al pie (§3), como las de T27.

   Por qué anula el hover de .pe-card: la tarjeta no enlaza a ningún
   lado, y una caja que se levanta al pasar el ratón promete un clic que
   no existe. Mismo criterio (y misma solución) que .mini-calc. ---- */
.pe-card--inmersiva {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 360px;
  padding: 0;
  overflow: hidden;
  border: 0;
}

@media (hover: hover) {
  .pe-card--inmersiva:hover { transform: none; box-shadow: var(--pe-shadow); }
}

.pe-card-inmersiva-foto { position: absolute; inset: 0; }

.pe-card-inmersiva-foto picture,
.pe-card-inmersiva-foto img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Dos degradados sobre el mismo elemento, y cada uno resuelve un texto:

   · El de ABAJO (to top) da contraste al cuerpo. Calibrado contra el arte
     más claro de los tres, la mesa de dibujo.

   · El de ARRIBA (to bottom) existe SOLO por el código mono, y se midió,
     no se estimó: con el velo de una sola pasada que tenía esto al
     principio, el código de la tarjeta de media tensión caía sobre el
     cielo y daba 2.99:1 — por debajo del 4.5 que pide AA para texto
     pequeño (T19). Se apaga al 26% del alto para no ensuciar el centro
     de la imagen, que es donde está el equipo que se quiere mostrar.

   Si entra arte nuevo con una zona clara arriba, hay que volver a medir
   ese código: es el punto frágil de este componente. */
.pe-card-inmersiva-velo {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(
      to bottom,
      rgba(21, 31, 47, 0.80),
      rgba(21, 31, 47, 0) 26%
    ),
    linear-gradient(
      to top,
      rgba(21, 31, 47, 0.96) 34%,
      rgba(21, 31, 47, 0.62) 62%,
      rgba(21, 31, 47, 0.30)
    );
}

.pe-card-inmersiva-code {
  position: absolute;
  top: 14px;
  left: 16px;
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--pe-crema);
  opacity: 0.9;
}

.pe-card-inmersiva-body {
  position: relative;
  padding: 1.5rem 1.4rem 1.3rem;
  color: var(--pe-crema);
}

.pe-card-inmersiva-body .pe-subtitle {
  color: var(--pe-crema);
  margin-bottom: 0.5rem;
}

.pe-card-inmersiva-body p {
  font-size: 0.95rem;
  line-height: 1.6;
  opacity: 0.85;
  margin: 0 0 0.9rem;
}

/* Las tarjetas de una fila se leen como una fila (§2.3). Como el cuerpo va
   anclado ABAJO, una descripción que envuelve una línea de más empuja su
   título una línea más arriba que el de sus vecinas: medido, el título de
   media tensión caía 24px por encima de los otros dos a 1280 en INGLÉS
   (en español las tres envuelven igual y el defecto no se ve — por eso hay
   que barrer en los dos idiomas y no en uno).
   La descripción reserva entonces el alto del peor caso. Va por rango
   porque el ancho de columna cambia: de 576px son 2 por fila, de 992px son
   3; por debajo de 576 se apilan y no hay fila que igualar, así que ahí no
   se reserva nada y el teléfono no carga con espacio muerto.
   Precio en español: hasta una línea de aire bajo la descripción. Se paga
   a cambio del renglón de títulos. */
@media (min-width: 576px) {
  .pe-card-inmersiva-body p:not(.pe-subtitle) { min-height: 9.6em; } /* 6 líneas */
}
@media (min-width: 768px) {
  .pe-card-inmersiva-body p:not(.pe-subtitle) { min-height: 6.4em; } /* 4 líneas */
}

/* Igualar la descripción no bastaba: entre 576 y 767px la columna mide 204px
   y los campos mono envuelven a dos líneas en unas tarjetas y a una en otras
   —medido, en ESPAÑOL la primera iba a 40px y la segunda a 17px, y ahí se
   colaba otra vez un desfase de 23px en los títulos—. De 768px en adelante
   caben en una línea siempre, en los dos idiomas, así que la reserva se acota
   a ese tramo en vez de dejar aire donde no hace falta. */
@media (min-width: 576px) and (max-width: 767.98px) {
  .pe-card-inmersiva-campos { min-height: 4em; } /* 2 líneas + hueco */
}

/* Campos mono al pie: el resto de la firma técnica que sobrevive a la
   lámina. Mismo teal luminoso que la placa — el #11363E de marca no es
   legible sobre el marino del velo. */
.pe-card-inmersiva-campos {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 10px;
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.1em;
  color: #4fd1c5;
}

/* ---- Tarjeta de perfil (.pe-card--perfil) — T35 ---------------------
   Arte arriba, texto sobre crema abajo, franja ficha al pie. Aprobada por
   Ricardo (30-jul-2026) para las 3 tarjetas de "Para quién es" de
   servicios/peak-shaving, en sustitución de la lámina de plano de T21 —
   que con esto sale de TODAS las páginas publicadas.

   POR QUÉ ES UNA FAMILIA NUEVA Y NO UNA DE LAS TRES QUE YA HABÍA.
   La estructura (arte arriba, cuerpo al centro, ficha al pie) es la de
   .pe-card--proyecto, pero §6 la reserva al portafolio. La banda de arte
   de T27 (.pe-card--arte) haría el mismo trabajo, pero está atada a
   .pe-card--servicio, o sea al PÉTALO, y §6 lo reserva a las cinco
   líneas de servicio. Estas tres tarjetas no son una línea de servicio
   ni un proyecto: describen A QUIÉN le sirve el servicio. Reusar
   cualquiera de las dos habría desgastado su marcador, que es
   exactamente lo que §6 protege.

   Se eligió sobre la tarjeta inmersiva de T29 en una comparativa de tres
   direcciones (_verificacion-no-subir/peakshaving-comparativa.php).

   Radio base 12px, SIN pétalo. El arte es ILUSTRATIVO: la cuadrícula que
   la use lleva la línea .pe-aviso-ilustrativo al pie (§3).

   Anula el hover de .pe-card, y es una decisión, no un olvido: la
   tarjeta no enlaza a ningún lado y una caja que se levanta al pasar el
   ratón promete un clic que no existe. Es el mismo criterio ya escrito
   para .pe-card--inmersiva y .mini-calc. La lámina a la que sustituye sí
   se levantaba, así que esto CAMBIA respecto de lo publicado. ---- */
.pe-card--perfil {
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
}

@media (hover: hover) {
  .pe-card--perfil:hover { transform: none; box-shadow: var(--pe-shadow); }
}

.pe-card-perfil-arte {
  position: relative;
  display: block;
  flex-shrink: 0;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background-color: var(--pe-marino); /* color de reposo mientras carga */
}

.pe-card-perfil-arte picture,
.pe-card-perfil-arte img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Velo superior para el código mono. Existe por una MEDICIÓN, no por
   estilo: con el código sobre el arte crudo y sólo un text-shadow daba
   1.94:1 sobre los tubos iluminados de la nave y 3.99:1 sobre el cielo
   del crepúsculo, las dos por debajo del 4.5 que pide AA para texto
   pequeño (T19). Con el velo: 6.97 / 11.03 / 8.26:1.
   Se apaga al 40% de la banda para no ensuciar el arte, que es lo que
   esta tarjeta viene a mostrar. Arte nuevo = volver a medir con
   _verificacion-no-subir/contraste-inmersiva.mjs. */
.pe-card-perfil-arte::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(21, 31, 47, 0.80), rgba(21, 31, 47, 0) 40%);
}

.pe-card-perfil-code {
  position: absolute;
  top: 10px;
  left: 12px;
  z-index: 1;
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--pe-crema);
}

.pe-card-perfil-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 22px 26px 18px;
}

.pe-card-perfil-body .pe-subtitle {
  font-size: 1.05rem;
  line-height: 1.35;
  margin-bottom: 0.5rem;
}

.pe-card-perfil-body p:not(.pe-subtitle) {
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--pe-carbon);
  opacity: 0.8;
  margin: 0;
}

/* Las tarjetas de una fila se leen como una fila (§2.3), y aquí hacen
   falta DOS reservas porque hay dos cosas que envuelven distinto:

   · la descripción, que en inglés no rompe igual que en español;
   · la franja ficha, que lleva dos cadenas mono de largo desigual.

   Sin la segunda los tres pies quedan a alturas distintas dentro de
   tarjetas del mismo alto. El valor es MEDIDO: la franja de dos líneas
   da 66px de caja, o sea 6em a su font-size de 11px (box-sizing:
   border-box, padding incluido) — por eso no sirve una reserva menor
   que los 44px que ya mide la de una línea.
   Por debajo de 768px las tarjetas se apilan: no hay fila que igualar y
   no se reserva nada, así que el teléfono no carga con espacio muerto. */
@media (min-width: 768px) {
  .pe-card-perfil-body p:not(.pe-subtitle) { min-height: 6.4em; } /* 4 líneas */
  .pe-card--perfil .pe-card-ficha { min-height: 6em; }            /* 2 líneas */
}

/* Entre 768 y 991px la columna mide ~228px y todo envuelve una línea más:
   la descripción llega a 6 y la ficha a 3. Mismo criterio que la reserva
   propia que .pe-card-inmersiva-campos necesita en su tramo estrecho. */
@media (min-width: 768px) and (max-width: 991.98px) {
  .pe-card-perfil-body p:not(.pe-subtitle) { min-height: 9.6em; } /* 6 líneas */
  .pe-card--perfil .pe-card-ficha { min-height: 8.8em; }          /* 3 líneas */
}

/* ---- Banda de credenciales (.pe-credenciales) — T29 -----------------
   Tres avales leídos como UN solo instrumento, no como tres tarjetas:
   filetes verticales entre reglas marino. Aprobada por Ricardo
   (28-jul-2026) para "Trabajo que puedes verificar" de
   servicios/infraestructura-electrica, en sustitución de la placa de
   acero de T21.

   Emparenta a propósito con .pe-cinta-datos del index (T3), que es el
   otro lugar del sitio donde tres hechos se presentan juntos.

   NO lleva imagen, y no es una preferencia: sus campos van rotulados
   con REGIÓN y el bloque se ofrece como prueba de obra. §3 exige
   fotografía real de obra ProEnergy en toda pieza rotulada con cliente,
   sitio o cifra — así que aquí no entra arte generado, ni ilustrativo.
   Si alguna vez se le pone imagen, deja de cumplir §3. ---- */
.pe-credenciales {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 2px solid var(--pe-marino);
  border-bottom: 2px solid var(--pe-marino);
}

.pe-credenciales-item { padding: 1.7rem 1.5rem; }

.pe-credenciales-item + .pe-credenciales-item {
  border-left: 1px solid rgba(21, 31, 47, 0.13);
}

.pe-credenciales-code {
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--pe-teal);
  margin-bottom: 0.6rem;
}

.pe-credenciales-title {
  font-family: var(--pe-font-head);
  font-weight: 700;
  font-size: 1.05rem;
  line-height: 1.25;
  color: var(--pe-marino);
  margin: 0 0 0.6rem;
}

.pe-credenciales-text {
  font-family: var(--pe-font-body);
  font-size: 0.92rem;
  line-height: 1.6;
  color: var(--pe-carbon);
  opacity: 0.82;
  margin: 0 0 0.8rem;
}

.pe-credenciales-val {
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.1em;
  color: var(--pe-teal);
  margin: 0;
}

/* En teléfono la banda se apila y los filetes pasan a horizontales: tres
   columnas de 125px no son una fila, son tres textos rotos. */
@media (max-width: 767.98px) {
  .pe-credenciales { grid-template-columns: 1fr; }
  .pe-credenciales-item + .pe-credenciales-item {
    border-left: 0;
    border-top: 1px solid rgba(21, 31, 47, 0.13);
  }
}

/* ------------ CHIP (borde naranja, heredado del impreso) ------------ */
.pe-chip {
  display: inline-block;
  font-family: var(--pe-font-body);
  font-weight: 600;
  font-size: var(--pe-fs-small);
  color: var(--pe-carbon);
  border: 1.5px solid var(--pe-naranja);
  border-radius: var(--pe-radius);
  padding: 0.4rem 0.9rem;
  margin: 0.2rem 0.25rem 0.2rem 0;
}

.pe-section--dark .pe-chip {
  color: var(--pe-crema);
}

/* ------------ FOTO CON VELO A MARINO ------------ */
.pe-photo {
  position: relative;
  border-radius: var(--pe-radius);
  overflow: hidden;
  display: block;
}

.pe-photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.pe-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(21, 31, 47, 0.65), rgba(21, 31, 47, 0.08) 55%);
  pointer-events: none;
}

/* Variante hero: velo completo para poner texto encima */
.pe-photo--hero::after {
  background: linear-gradient(rgba(21, 31, 47, 0.78), rgba(21, 31, 47, 0.78));
}

/* ------------ ACORDEÓN (FAQ) — sobre marcado de Bootstrap ------------ */
.pe-accordion .accordion-item {
  background-color: var(--pe-blanco);
  border: var(--pe-border-card);
  border-radius: var(--pe-radius) !important;
  margin-bottom: 0.75rem;
  box-shadow: var(--pe-shadow);
  overflow: hidden;
}

.pe-accordion .accordion-button {
  background-color: var(--pe-blanco);
  color: var(--pe-marino);
  font-family: var(--pe-font-head);
  font-weight: 700;
  font-size: var(--pe-fs-body);
  padding: 1.1rem 1.25rem;
  box-shadow: none;
}

.pe-accordion .accordion-button:not(.collapsed) {
  background-color: var(--pe-teal);
  color: var(--pe-crema);
}

.pe-accordion .accordion-button:focus {
  box-shadow: none; /* fuera el ring azul Bootstrap (también en clic) */
}

/* T19: el teclado sí necesita anillo. Interior (offset negativo) porque
   .accordion-item recorta con overflow:hidden; crema cuando la cabecera
   expandida pinta fondo teal. */
.pe-accordion .accordion-button:focus-visible {
  outline: 2px solid var(--pe-teal);
  outline-offset: -2px;
}

.pe-accordion .accordion-button:not(.collapsed):focus-visible {
  outline-color: var(--pe-crema);
}

.pe-accordion .accordion-button:not(.collapsed)::after {
  filter: brightness(0) invert(1);
}

.pe-accordion .accordion-body {
  font-family: var(--pe-font-body);
  color: var(--pe-carbon);
  font-size: var(--pe-fs-body);
  line-height: 1.75;
  padding: 1.1rem 1.25rem;
}

/* ------------ GARANTÍA DE POR VIDA (diferenciador) ------------ */
/* Recuadro destacado: fondo blanco con la barra lateral naranja del sistema */
.pe-warranty-life {
  background-color: var(--pe-blanco);
  border-left: 5px solid var(--pe-naranja);
  border-radius: var(--pe-radius);
  box-shadow: var(--pe-shadow);
  padding: 1rem 1.25rem;
  margin-top: 0.9rem;
}

/* ------------ PASOS NUMERADOS ------------ */
.pe-step {
  display: flex;
  align-items: flex-start;
  gap: 1.1rem;
  padding: 1.3rem 1.25rem;
  border-radius: var(--pe-radius);
  margin-bottom: 0.9rem;
}

.pe-step-number {
  flex-shrink: 0;
  width: 46px;
  height: 46px;
  border-radius: var(--pe-radius);
  background-color: var(--pe-teal);
  color: var(--pe-crema);
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 1.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.pe-step--highlight {
  background-color: var(--pe-teal);
  box-shadow: var(--pe-shadow);
}

.pe-step--highlight .pe-step-number {
  background-color: var(--pe-crema);
  color: var(--pe-teal);
}

/* ------------ CIFRAS GRANDES (barra de credibilidad, specs) ------------ */
.pe-stat {
  text-align: center;
}

.pe-stat .pe-stat-value {
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: clamp(1.6rem, 5vw, 2.4rem);
  line-height: 1.15;
}

.pe-stat .pe-stat-label {
  font-family: var(--pe-font-body);
  font-size: var(--pe-fs-small);
  opacity: 0.75;
  margin-top: 0.3rem;
}

/* ------------ BASE PARA PÁGINAS HEREDADAS ------------ */
/* Con class="pe" en el <body>, las páginas del desarrollador
   original adoptan las tipografías y colores del sistema sin
   reescribir todo su marcado. */
.pe h1, .pe h2, .pe h3, .pe h4, .pe h5, .pe h6 {
  font-family: var(--pe-font-head);
  font-weight: 700;
}

.pe footer {
  background-color: var(--pe-marino);
  color: var(--pe-crema);
  padding: 3.5rem 1.5rem;
}

.pe footer p {
  margin: 0;
}

.pe-footer-inner {
  max-width: 860px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2rem;
}

.pe-footer-offices {
  width: 100%;
}

.pe-footer-offices-label {
  font-family: var(--pe-font-num);
  font-size: 0.67rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(240, 238, 233, 0.38);
  display: block;
  text-align: center;
  margin-bottom: 1.25rem;
}

.pe-footer-offices-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.25rem 3rem;
  max-width: 720px;
  margin: 0 auto;
}

.pe-footer-office-name {
  font-family: var(--pe-font-num);
  font-size: 0.67rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(240, 238, 233, 0.48);
  display: block;
  margin-bottom: 0.35rem;
}

.pe-footer-office-addr {
  font-style: normal;
  font-size: 0.82rem;
  color: rgba(240, 238, 233, 0.72);
  line-height: 1.55;
  margin: 0;
}

.pe-footer-office-link {
  color: inherit;
  text-decoration: none;
  text-underline-offset: 2px;
  transition: text-decoration-color 0.2s ease;
}

.pe-footer-office-link:hover,
.pe-footer-office-link:focus-visible {
  text-decoration: underline;
  text-decoration-color: rgba(240, 238, 233, 0.5);
}

.pe-footer-copy {
  font-size: 0.78rem;
  color: rgba(240, 238, 233, 0.32);
}

@media (max-width: 640px) {
  .pe-footer-offices-grid {
    grid-template-columns: 1fr;
    gap: 1.25rem;
    text-align: center;
  }
}

/* Fix auditoría móvil — el botón flotante de WhatsApp (fixed, ~70px de alto
   en móvil) tapaba el final del copyright al llegar abajo. Damos aire
   inferior en móvil para que la línea de créditos libre el botón. */
@media (max-width: 576px) {
  .pe footer { padding-bottom: 5.5rem; }
}

.pe .text-primary {
  color: var(--pe-teal) !important;
}

.pe .bg-light {
  background-color: var(--pe-crema) !important;
}

/* ------------ BOTÓN FLOTANTE DE WHATSAPP ------------ */
.whatsapp-float {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 9000;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background-color: var(--pe-whatsapp);
  color: var(--pe-blanco);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  box-shadow: var(--pe-shadow);
  text-decoration: none;
  transition: transform 0.2s ease;
}

.whatsapp-float:hover,
.whatsapp-float:focus {
  color: var(--pe-blanco);
  transform: scale(1.08);
}

@media (max-width: 576px) {
  .whatsapp-float {
    width: 56px;
    height: 56px;
    font-size: 1.8rem;
    right: 14px;
    bottom: 14px;
  }
}

/* ============================================================
   CTA PEGAJOSO MÓVIL (.pe-sticky-cta) — T15
   Barra fija inferior SOLO en móvil (≤576px, la misma frontera que
   el sistema ya trata como "móvil": .pe-btn full-width, footer con
   clearance, float encogido). Aparece tras el 60% de scroll cuando
   pe-sticky-cta.js añade body.pe-sticky-on. Es EL naranja de su
   viewport: mientras está activa, todo otro .pe-btn--primary se
   degrada a contorno y el float de WhatsApp se oculta (ambos van al
   mismo diagnóstico). Sin JS: nunca aparece (queda el float como
   fallback). El naranja es el botón interior, no la banda: barra
   marino + un único CTA naranja, coherente con la doctrina.
   ============================================================ */
.pe-sticky-cta {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9400; /* sobre el float (9000), bajo el lightbox (9500) */
  display: none; /* solo se activa en móvil (media query de abajo) */
  padding: 0.7rem 0.9rem calc(0.7rem + env(safe-area-inset-bottom, 0px));
  background-color: var(--pe-marino);
  box-shadow: 0 -6px 24px rgba(21, 31, 47, 0.18);
  transform: translateY(115%);
  transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none; /* inerte mientras está fuera de pantalla */
}
.pe-sticky-cta__link {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  width: 100%;
  padding: 0.85rem 1.5rem;
  font-family: var(--pe-font-head);
  font-weight: 700;
  font-size: var(--pe-fs-btn);
  text-align: center;
  text-decoration: none;
  color: var(--pe-blanco);
  background-color: var(--pe-naranja);
  border-radius: var(--pe-radius);
  transition: background-color 0.25s ease;
}
.pe-sticky-cta__link:hover,
.pe-sticky-cta__link:focus {
  color: var(--pe-blanco);
  background-color: var(--pe-naranja-hover);
}

@media (max-width: 576px) {
  .pe-sticky-cta { display: block; }
  body.pe-sticky-on .pe-sticky-cta {
    transform: translateY(0);
    pointer-events: auto;
  }
  /* La barra es EL naranja del viewport: apaga cualquier otro primario.
     Cubre también :hover/:focus para que el tap-focus no lo re-pinte. */
  body.pe-sticky-on .pe-btn--primary,
  body.pe-sticky-on .pe-btn--primary:hover,
  body.pe-sticky-on .pe-btn--primary:focus {
    background-color: transparent;
    border-color: var(--pe-marino);
    color: var(--pe-marino);
  }
  /* Sobre superficies oscuras/teal el contorno marino sería ilegible:
     se degrada en crema (mismo criterio que .pe-section--dark). Incluye
     la franja teal del diagnóstico y los heros de foto con velo oscuro
     (clases por página; ninguno es .pe-section--dark). Salvavidas: en la
     práctica el hero está a scroll 0% y la barra sólo aparece tras 60%,
     así que no coinciden en viewport — pero así queda legible si lo hacen. */
  body.pe-sticky-on .pe-section--dark .pe-btn--primary,
  body.pe-sticky-on .pe-diag-response .pe-btn--primary,
  body.pe-sticky-on .home-hero .pe-btn--primary,
  body.pe-sticky-on .svc-hero .pe-btn--primary,
  body.pe-sticky-on .sol-hero .pe-btn--primary,
  body.pe-sticky-on .ps-hero .pe-btn--primary,
  body.pe-sticky-on .ele-hero .pe-btn--primary,
  body.pe-sticky-on .rsc-hero .pe-btn--primary,
  body.pe-sticky-on .bess-hero .pe-btn--primary {
    border-color: var(--pe-crema);
    color: var(--pe-crema);
  }
  /* Redundante con la barra (mismo destino): ocultar el float. */
  body.pe-sticky-on .whatsapp-float {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
  }
  /* Clearance: la barra (full-width + safe-area) es más alta que el
     float; ampliamos el aire inferior del footer mientras está activa. */
  body.pe-sticky-on footer { padding-bottom: 7.5rem; }
}

@media (prefers-reduced-motion: reduce) {
  .pe-sticky-cta { transition: none; }
}

/* ------------ CIFRAS DE CREDIBILIDAD SOBRE FONDO CLARO ------------ */
/* Sobre fondo crema, los valores numéricos de .pe-stat se muestran en teal */
.pe-section .pe-stat .pe-stat-value {
  color: var(--pe-teal);
}

/* ------------ BADGE DE PASO DESTACADO — va con .pe-step ------------ */
.step-badge {
  display: inline-block;
  font-family: var(--pe-font-body);
  font-weight: 700;
  font-size: 0.75rem;
  letter-spacing: 1px;
  text-transform: uppercase;
  background-color: var(--pe-crema);
  color: var(--pe-teal);
  padding: 0.3rem 0.8rem;
  border-radius: var(--pe-radius);
  margin-bottom: 0.6rem;
}

/* ------------ FICHA DE INGENIERÍA (filas numeradas estilo reporte técnico) ------------
   NO es una tarjeta: sin fondo, sin sombra, sin radio — vive sobre el crema. */
.pe-ficha {
  max-width: var(--pe-content);
  margin: 0 auto;
  border-top: 2px solid var(--pe-marino);
  border-bottom: 2px solid var(--pe-marino);
}

.pe-ficha-row {
  display: grid;
  grid-template-columns: 48px 130px 1fr;
  gap: 16px;
  align-items: baseline;
  padding: 1.1rem 0;
}

.pe-ficha-row + .pe-ficha-row {
  border-top: 1px solid rgba(21, 31, 47, 0.12);
}

@media (hover: hover) {
  .pe-ficha-row:hover { background-color: rgba(17, 54, 62, 0.03); }
}

.pe-ficha-num {
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 11px;
  color: var(--pe-carbon);
  opacity: 0.45;
}

.pe-ficha-cifra {
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: clamp(1.25rem, 2vw, 1.5rem);
  color: var(--pe-teal);
  white-space: nowrap;
}

.pe-ficha-texto {
  font-family: var(--pe-font-body);
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--pe-carbon);
  margin: 0;
}

.pe-ficha-texto strong {
  font-weight: 700;
  color: var(--pe-marino);
}

/* Móvil: dos niveles — número + cifra en línea, texto debajo */
@media (max-width: 576px) {
  .pe-ficha-row {
    grid-template-columns: 48px 1fr;
    row-gap: 0.4rem;
  }
  .pe-ficha-texto { grid-column: 1 / -1; }
}

/* ------------ PANEL DE DESPACHO (contacto) ------------
   Dos oficinas lado a lado: código watermark, teléfono tel:, WhatsApp y
   dirección a Maps. Mismo lenguaje de reporte técnico que .pe-ficha:
   mono, hairlines, sin adorno decorativo. */
.pe-despacho {
  max-width: var(--pe-content);
  margin: 0 auto;
  background-color: var(--pe-blanco);
  border: var(--pe-border-card);
  border-radius: var(--pe-radius);
  box-shadow: var(--pe-shadow);
  overflow: hidden;
}

/* Barra superior: disponibilidad, sin promesa de tiempo exacto */
.pe-despacho-bar {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 12px 22px;
  background-color: var(--pe-marino);
  color: var(--pe-crema);
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.pe-despacho-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: var(--pe-whatsapp);
  box-shadow: 0 0 0 0 rgba(37, 211, 102, 0.45);
  animation: pe-despacho-pulse 2.4s ease-out infinite;
  flex-shrink: 0;
}

@keyframes pe-despacho-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(37, 211, 102, 0.45); }
  70%  { box-shadow: 0 0 0 7px rgba(37, 211, 102, 0); }
  100% { box-shadow: 0 0 0 0 rgba(37, 211, 102, 0); }
}

/* Dos módulos de oficina */
.pe-despacho-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.pe-despacho-office {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 2.1rem 1.8rem 1.9rem;
  transition: background-color 0.25s ease;
}

.pe-despacho-office + .pe-despacho-office {
  border-left: 1px solid rgba(21, 31, 47, 0.10); /* hairline vertical */
}

@media (hover: hover) {
  .pe-despacho-office:hover { background-color: rgba(17, 54, 62, 0.03); }
}

/* Código de oficina en mono grande y tenue de fondo (decorativo) */
.pe-despacho-code {
  position: absolute;
  top: -0.28em;
  right: 0.12em;
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 5.5rem;
  line-height: 1;
  letter-spacing: -0.02em;
  color: rgba(17, 54, 62, 0.05);
  pointer-events: none;
  user-select: none;
}

/* Estado (small-caps) */
.pe-despacho-estado {
  position: relative;
  display: block;
  font-family: var(--pe-font-body);
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--pe-carbon);
  opacity: 0.6;
  margin-bottom: 0.55rem;
}

/* Teléfono en mono 700 grande, enlace tel: */
.pe-despacho-tel {
  position: relative;
  display: inline-block;
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: clamp(1.15rem, 2.4vw, 1.45rem);
  color: var(--pe-teal);
  text-decoration: none;
  margin-bottom: 1.1rem;
  transition: color 0.2s ease;
}

.pe-despacho-tel:hover,
.pe-despacho-tel:focus { color: var(--pe-marino); }

/* Botón WhatsApp secundario compacto */
.pe-despacho-wa {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 0.6rem 1.15rem;
  font-size: 0.9rem;
  margin-bottom: 1.3rem;
}

/* Dirección como enlace a Maps con pin SVG de línea */
.pe-despacho-dir {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-family: var(--pe-font-body);
  font-size: 0.82rem;
  line-height: 1.55;
  color: rgba(41, 44, 45, 0.72);
  text-decoration: none;
  transition: color 0.2s ease;
}

.pe-despacho-dir svg {
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--pe-teal);
}

.pe-despacho-dir:hover,
.pe-despacho-dir:focus {
  color: var(--pe-teal);
  text-decoration: underline;
}

/* Móvil: módulos apilados con hairline horizontal */
@media (max-width: 575.98px) {
  .pe-despacho-grid { grid-template-columns: 1fr; }
  .pe-despacho-office + .pe-despacho-office {
    border-left: none;
    border-top: 1px solid rgba(21, 31, 47, 0.10);
  }
  .pe-despacho-code { font-size: 4.5rem; }
}

@media (prefers-reduced-motion: reduce) {
  .pe-despacho-dot { animation: none; }
}

/* Banda de foto bajo el panel — alineada al ancho del panel/encabezado */
.pe-despacho-banda {
  position: relative;
  max-width: var(--pe-content);
  margin: 2.6rem auto 0;
  border-radius: var(--pe-radius);
  overflow: hidden;
  box-shadow: var(--pe-shadow);
}

/* La foto pasó a <picture> (WebP con respaldo PNG). `display: contents` deja al
   <img> como hijo directo de la banda, así que la geometría queda EXACTAMENTE
   como antes del cambio: sin caja intermedia en línea que meta el hueco de
   línea base bajo la foto. Mismo recurso que ya usan .pe-lb-stage y
   .pe-anotada-lienzo por el mismo motivo. */
.pe-despacho-banda picture { display: contents; }

.pe-despacho-banda img {
  display: block;
  width: 100%;
  height: clamp(220px, 34vw, 360px);
  object-fit: cover;
  object-position: center;
  transform-origin: 40% 60%;
}

/* Callout de obra sobre la banda (mismo lenguaje que .pe-obra del index).
   Solo desktop: en móvil el recorte cover mueve el elemento anotado. */
.pe-despacho-anot {
  display: none;
}

@media (min-width: 768px) {
  .pe-despacho-anot {
    display: block;
    position: absolute;
    left: 42%;
    bottom: 26%;
    pointer-events: none;
  }
  .pe-despacho-anot-dot {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 16px;
    height: 16px;
    margin: 0 0 -8px -8px;
    border: 1.5px solid var(--pe-crema);
    border-radius: 50%;
    box-shadow: 0 0 0 3px rgba(21, 31, 47, 0.35);
  }
  .pe-despacho-anot-line {
    position: absolute;
    left: 0;
    bottom: 8px;
    width: 1.2px;
    height: 30px;
    background: rgba(240, 238, 233, 0.8);
  }
  .pe-despacho-anot-label {
    position: absolute;
    left: -6px;
    bottom: 40px;
    white-space: nowrap;
    font-family: var(--pe-font-num);
    font-weight: 700;
    font-size: 10px;
    letter-spacing: 0.07em;
    color: var(--pe-crema);
    background: rgba(21, 31, 47, 0.82);
    border: 1px solid rgba(240, 238, 233, 0.25);
    padding: 4px 9px;
    border-radius: 4px;
  }
}

/* ---- Animaciones de entrada (T7): progressive enhancement.
   Base = estado final visible. .is-armed (solo JS + sin reduced-motion,
   aplicado antes del paint) fija el estado inicial; .is-in lo revela. ---- */
.pe-despacho.is-armed .pe-despacho-bar { clip-path: inset(0 100% 0 0); }
.pe-despacho.is-armed.is-in .pe-despacho-bar {
  clip-path: inset(0 0 0 0);
  transition: clip-path 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

/* Los módulos entran después de que la barra empiece a dibujarse */
.pe-despacho.is-armed .pe-despacho-office {
  opacity: 0;
  transform: translateY(14px);
}
.pe-despacho.is-armed.is-in .pe-despacho-office {
  opacity: 1;
  transform: none;
  transition: opacity 0.7s ease 0.35s, transform 0.7s cubic-bezier(0.16, 1, 0.3, 1) 0.35s;
}
.pe-despacho.is-armed.is-in .pe-despacho-office + .pe-despacho-office {
  transition-delay: 0.55s;
}

.pe-despacho.is-armed .pe-despacho-code { opacity: 0; }
.pe-despacho.is-armed.is-in .pe-despacho-code {
  opacity: 1;
  transition: opacity 0.9s ease 0.75s;
}

/* Ken Burns de la banda. Corre en todos los anchos desde el 28-jul-2026
   (decisión de Ricardo): antes estaba limitado a ≥768px "por batería", pero
   es un solo zoom de 16s que termina (forwards), no un loop infinito. Con
   prefers-reduced-motion no arranca — el JS no pone .is-armed. */
.pe-despacho-banda.is-armed.is-in img {
  animation: pe-despacho-kenburns 16s linear forwards;
}

/* El callout sí es solo de escritorio: en móvil está display:none porque el
   recorte cover mueve el elemento que la anotación señala (ver arriba). */
@media (min-width: 768px) {
  .pe-despacho-banda.is-armed .pe-despacho-anot {
    opacity: 0;
    transform: translateY(6px);
  }
  .pe-despacho-banda.is-armed.is-in .pe-despacho-anot {
    opacity: 1;
    transform: none;
    transition: opacity 0.7s ease 0.6s, transform 0.7s ease 0.6s;
  }
}

@keyframes pe-despacho-kenburns {
  from { transform: scale(1); }
  to   { transform: scale(1.06); }
}

/* ------------ CAJA DE URGENCIA (siempre sobre marino) ------------ */
.pe-urgency-box {
  border-left: 4px solid var(--pe-teal);
  background-color: rgba(17, 54, 62, 0.5);
  border-radius: 0 var(--pe-radius) var(--pe-radius) 0;
  padding: 1.25rem 1.5rem;
  margin: 1.75rem auto;
  max-width: var(--pe-content);
  text-align: left;
}
.pe-urgency-box p {
  margin: 0;
  color: var(--pe-crema);
  font-size: var(--pe-fs-body);
  line-height: 1.7;
  opacity: 0.92;
}

/* ------------ FORMULARIO HUBSPOT (embed de la sección de contacto) ------------
   HubSpot renderiza el form en un iframe del mismo origen. Desde index.php
   (onFormReady) se inyecta esta hoja al iframe y su <body> recibe el id
   hubspot-form-inicio, de modo que estas reglas aplican dentro del iframe
   con especificidad de contenedor. !important solo donde HubSpot escribe
   estilos inline (ancho de inputs). */

#hubspot-form-inicio .hs-form fieldset {
  max-width: none;
}

#hubspot-form-inicio .hs-form-field {
  margin-bottom: 1.25rem;
}

#hubspot-form-inicio .hs-form-field > label {
  display: block;
  font-family: var(--pe-font-body);
  font-weight: 600;
  font-size: var(--pe-fs-small);
  color: var(--pe-carbon);
  margin-bottom: 0.4rem;
}

#hubspot-form-inicio input.hs-input:not([type="checkbox"]):not([type="radio"]),
#hubspot-form-inicio select.hs-input,
#hubspot-form-inicio textarea.hs-input {
  width: 100% !important; /* HubSpot fija anchos inline (95%/100%) */
  font-family: var(--pe-font-body);
  font-size: var(--pe-fs-body);
  color: var(--pe-carbon);
  background-color: var(--pe-blanco);
  border: 1.5px solid rgba(21, 31, 47, 0.18);
  border-radius: var(--pe-radius);
  padding: 0.8rem 1rem;
  line-height: 1.4;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

#hubspot-form-inicio .hs-input::placeholder {
  color: var(--pe-carbon);
  opacity: 0.45;
}

#hubspot-form-inicio input.hs-input:not([type="checkbox"]):not([type="radio"]):focus,
#hubspot-form-inicio select.hs-input:focus,
#hubspot-form-inicio textarea.hs-input:focus {
  outline: none;
  border-color: var(--pe-teal);
  box-shadow: 0 0 0 3px rgba(17, 54, 62, 0.12);
}

/* Radios y checkboxes: lista limpia, marca en teal */
#hubspot-form-inicio .inputs-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

#hubspot-form-inicio .inputs-list li {
  margin-bottom: 0.4rem;
}

#hubspot-form-inicio .inputs-list label {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--pe-font-body);
  font-weight: 400;
  font-size: var(--pe-fs-body);
  color: var(--pe-carbon);
  cursor: pointer;
  margin-bottom: 0;
}

#hubspot-form-inicio input.hs-input[type="radio"],
#hubspot-form-inicio input.hs-input[type="checkbox"] {
  width: 1.05rem;
  height: 1.05rem;
  margin: 0;
  accent-color: var(--pe-teal);
  cursor: pointer;
}

/* Errores de validación: rojo sobrio, legible */
#hubspot-form-inicio .hs-error-msgs {
  list-style: none;
  margin: 0.4rem 0 0 0;
  padding: 0;
}

#hubspot-form-inicio .hs-error-msg,
#hubspot-form-inicio .hs-error-msgs label,
#hubspot-form-inicio .hs_error_rollup label {
  font-family: var(--pe-font-body);
  font-size: var(--pe-fs-small);
  font-weight: 500;
  color: #B3402A;
}

#hubspot-form-inicio input.hs-input.invalid.error,
#hubspot-form-inicio select.hs-input.invalid.error,
#hubspot-form-inicio textarea.hs-input.invalid.error {
  border-color: #B3402A;
}

/* Botón de envío: réplica exacta de .pe-btn--primary
   (único naranja permitido en la pantalla de contacto) */
#hubspot-form-inicio .hs-button {
  display: inline-block;
  font-family: var(--pe-font-head);
  font-weight: 700;
  font-size: var(--pe-fs-btn);
  text-decoration: none;
  text-align: center;
  padding: 0.95rem 1.9rem;
  border-radius: var(--pe-radius);
  border: 2px solid transparent;
  cursor: pointer;
  background-color: var(--pe-naranja);
  color: var(--pe-blanco);
  transition: background-color 0.25s ease, color 0.25s ease, transform 0.15s ease;
}

#hubspot-form-inicio .hs-button:hover,
#hubspot-form-inicio .hs-button:focus {
  background-color: var(--pe-naranja-hover);
  color: var(--pe-blanco);
  transform: translateY(-2px);
  outline: none;
}

/* T19: la regla de arriba apaga el outline también para teclado;
   aquí se restituye solo para :focus-visible (misma especificidad,
   gana por orden). */
#hubspot-form-inicio .hs-button:focus-visible {
  outline: 2px solid var(--pe-teal);
  outline-offset: 2px;
}

#hubspot-form-inicio .hs-submit,
#hubspot-form-inicio .hs-submit .actions {
  text-align: center;
  margin-top: 0.5rem;
}

@media (max-width: 576px) {
  #hubspot-form-inicio .hs-button {
    display: block;
    width: 100%;
    max-width: 420px;
    margin-left: auto;
    margin-right: auto;
  }
}

/* Mensaje de éxito tras el envío. Sin padding superior: el aire sobre el mensaje
   lo gobierna el margin-bottom del sello (.pe-form-seal), que siempre se revela
   encima al enviar; así el gap isotipo→"gracias" vive en un solo lugar. */
#hubspot-form-inicio .submitted-message {
  font-family: var(--pe-font-body);
  font-size: var(--pe-fs-lead);
  line-height: 1.6;
  color: var(--pe-teal);
  text-align: center;
  padding: 0 0 1.25rem;
}

/* ------------ TESTIMONIO PLACEHOLDER ------------ */
.pe-testimonial-placeholder {
  border: 2px solid rgba(21, 31, 47, 0.18);
  border-radius: var(--pe-radius);
  padding: 1.5rem 1.75rem;
  margin: 2.5rem auto 0 auto;
  max-width: var(--pe-content);
  background-color: rgba(21, 31, 47, 0.03);
  text-align: left;
}
.pe-testimonial-placeholder .pe-testimonial-quote {
  font-style: italic;
  font-size: var(--pe-fs-lead);
  line-height: 1.8;
  color: var(--pe-carbon);
  opacity: 0.35;
  margin: 0 0 0.5rem 0;
}
.pe-testimonial-placeholder .pe-testimonial-attr {
  font-size: var(--pe-fs-small);
  color: var(--pe-carbon);
  opacity: 0.3;
  margin: 0;
}
/* Variante sobre sección oscura */
.pe-section--dark .pe-testimonial-placeholder {
  border-color: rgba(240, 238, 233, 0.2);
  background-color: rgba(240, 238, 233, 0.06);
}
.pe-section--dark .pe-testimonial-placeholder .pe-testimonial-quote {
  color: var(--pe-crema);
}
.pe-section--dark .pe-testimonial-placeholder .pe-testimonial-attr {
  color: var(--pe-crema);
}

/* ------------ BLOQUE QUIÉNES SOMOS ------------ */
.qs-stats {
  display: flex;
  gap: 2.5rem;
  flex-wrap: wrap;
  margin: 1.5rem 0 1.25rem;
}
.qs-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.2rem;
}
.qs-stat-num {
  font-family: var(--pe-font-num);
  font-size: clamp(1.6rem, 5vw, 2.4rem);
  font-weight: 700;
  color: var(--pe-teal);
  line-height: 1;
  margin: 0;
}
.qs-stat-label {
  font-size: var(--pe-fs-small);
  color: var(--pe-carbon);
  opacity: 0.7;
  margin: 0;
  letter-spacing: 0.02em;
}
.qs-human {
  font-size: var(--pe-fs-small);
  color: var(--pe-marino);
  font-weight: 500;
  opacity: 0.8;
  margin-bottom: 1.75rem;
  max-width: 46ch;
}
@media (max-width: 991.98px) {
  .qs-stats { gap: 1.75rem; }
  .qs-stat-num { font-size: 1.9rem; }
}

/* ============================================================
   ISOTIPO ANIMADO — componente reutilizable (isotipo PE, 4 petalos)
   ------------------------------------------------------------
   Uso:
     <?php $iso_class='pe-isotipo-anim--once'; $iso_size='140px';
           include 'includes/isotipo-svg.php'; ?>
   - Hereda color con `color:` (fill=currentColor): teal, crema o marino.
   - Modos (clase en el wrapper .pe-isotipo):
       .pe-isotipo-anim--once  -> ensambla una sola vez (paginas)
       .pe-isotipo-anim--loop  -> ensambla (lento), respira (rapido), desensambla y repite (cargas)
   - Sin animacion / prefers-reduced-motion: isotipo estatico completo.
   - Ejes de entrada en unidades del viewBox (386x501): ~46u/eje ≈ 18px
     de recorrido diagonal a 140px de render; escala con el tamaño.
   ============================================================ */
.pe-isotipo {
  display: inline-block;
  line-height: 0;
  color: var(--pe-teal);            /* color por defecto; se sobreescribe por contexto */
  --iso-shift: 46px;                /* recorrido por eje (unidades del viewBox) */
  --iso-dx-lower: calc(-1 * var(--iso-shift));  /* inferiores: entran desde abajo-izquierda */
  --iso-dy-lower: var(--iso-shift);
  --iso-dx-upper: var(--iso-shift);             /* superiores: entran desde arriba-derecha */
  --iso-dy-upper: calc(-1 * var(--iso-shift));
}
.pe-isotipo svg { display: block; width: auto; height: 100%; overflow: visible; }

/* Sobre marino el teal se pierde (11363E ≈ 151F2F): el isotipo pasa a crema,
   igual que los botones/etiquetas del sistema cambian sobre fondo oscuro. */
.pe-section--dark .pe-isotipo { color: var(--pe-crema); }

/* Estado base = ENSAMBLADO. Asi reduced-motion, sin-JS o fallo de CSS
   muestran el isotipo completo; el estado desplazado vive solo en el 0%. */
.pe-iso__petal {
  transform-box: view-box;          /* origen relativo al viewBox... */
  transform-origin: center;         /* ...= centro del isotipo (comun a los 4) */
  opacity: 1;
  transform: translate(0, 0) scale(1);
}
/* Direccion de entrada por grupo (para el modo --once) */
.pe-iso__petal--1, .pe-iso__petal--2 { --iso-dx: var(--iso-dx-lower); --iso-dy: var(--iso-dy-lower); }
.pe-iso__petal--3, .pe-iso__petal--4 { --iso-dx: var(--iso-dx-upper); --iso-dy: var(--iso-dy-upper); }

@media (prefers-reduced-motion: no-preference) {
  @keyframes pe-iso-enter {
    0%   { opacity: 0; transform: translate(var(--iso-dx), var(--iso-dy)) scale(0.96); }
    100% { opacity: 1; transform: translate(0, 0) scale(1); }
  }

  /* --- MODO --once: entra una vez, stagger via animation-delay (1a iteracion) --- */
  .pe-isotipo-anim--once .pe-iso__petal {
    animation: pe-iso-enter 650ms cubic-bezier(0.16, 1, 0.3, 1) both;
  }
  .pe-isotipo-anim--once .pe-iso__petal--1 { animation-delay: 0ms;   }
  .pe-isotipo-anim--once .pe-iso__petal--2 { animation-delay: 110ms; }
  .pe-isotipo-anim--once .pe-iso__petal--3 { animation-delay: 220ms; }
  .pe-isotipo-anim--once .pe-iso__petal--4 { animation-delay: 330ms; }

  /* --- MODO --loop: stagger HORNEADO en los keyframes (no en delay), asi
         cada iteracion re-escalona en lockstep. Un timeline por petalo. --- */
  /* Ritmo reformado (jul 2026): ENSAMBLE lento y gradual (0→32% del ciclo, antes
     0→13%) para una entrada calmada; RESPIRACION mas rapida (44→62%, dips cada 6%
     en vez de 12%) para vida sin lentitud; luego hold y desensamble. Stagger
     horneado se conserva (+2.2% por petalo en ensamble/hold/desensamble). */
  @keyframes pe-iso-loop-1 {
    0.0% { opacity: 0; transform: translate(var(--iso-dx-lower), var(--iso-dy-lower)) scale(0.96); }
    32.0% { opacity: 1; transform: translate(0, 0) scale(1); }
    44.0% { opacity: 0.92; transform: translate(0, 0) scale(1); }
    50.0% { opacity: 1.0; transform: translate(0, 0) scale(1); }
    56.0% { opacity: 0.92; transform: translate(0, 0) scale(1); }
    62.0% { opacity: 1.0; transform: translate(0, 0) scale(1); }
    70.0% { opacity: 1; transform: translate(0, 0) scale(1); }
    82.0% { opacity: 0; transform: translate(var(--iso-dx-lower), var(--iso-dy-lower)) scale(0.96); }
    100.0% { opacity: 0; transform: translate(var(--iso-dx-lower), var(--iso-dy-lower)) scale(0.96); }
  }
  @keyframes pe-iso-loop-2 {
    0.0% { opacity: 0; transform: translate(var(--iso-dx-lower), var(--iso-dy-lower)) scale(0.96); }
    2.2% { opacity: 0; transform: translate(var(--iso-dx-lower), var(--iso-dy-lower)) scale(0.96); }
    34.2% { opacity: 1; transform: translate(0, 0) scale(1); }
    44.0% { opacity: 0.92; transform: translate(0, 0) scale(1); }
    50.0% { opacity: 1.0; transform: translate(0, 0) scale(1); }
    56.0% { opacity: 0.92; transform: translate(0, 0) scale(1); }
    62.0% { opacity: 1.0; transform: translate(0, 0) scale(1); }
    72.2% { opacity: 1; transform: translate(0, 0) scale(1); }
    84.2% { opacity: 0; transform: translate(var(--iso-dx-lower), var(--iso-dy-lower)) scale(0.96); }
    100.0% { opacity: 0; transform: translate(var(--iso-dx-lower), var(--iso-dy-lower)) scale(0.96); }
  }
  @keyframes pe-iso-loop-3 {
    0.0% { opacity: 0; transform: translate(var(--iso-dx-upper), var(--iso-dy-upper)) scale(0.96); }
    4.4% { opacity: 0; transform: translate(var(--iso-dx-upper), var(--iso-dy-upper)) scale(0.96); }
    36.4% { opacity: 1; transform: translate(0, 0) scale(1); }
    44.0% { opacity: 0.92; transform: translate(0, 0) scale(1); }
    50.0% { opacity: 1.0; transform: translate(0, 0) scale(1); }
    56.0% { opacity: 0.92; transform: translate(0, 0) scale(1); }
    62.0% { opacity: 1.0; transform: translate(0, 0) scale(1); }
    74.4% { opacity: 1; transform: translate(0, 0) scale(1); }
    86.4% { opacity: 0; transform: translate(var(--iso-dx-upper), var(--iso-dy-upper)) scale(0.96); }
    100.0% { opacity: 0; transform: translate(var(--iso-dx-upper), var(--iso-dy-upper)) scale(0.96); }
  }
  @keyframes pe-iso-loop-4 {
    0.0% { opacity: 0; transform: translate(var(--iso-dx-upper), var(--iso-dy-upper)) scale(0.96); }
    6.6% { opacity: 0; transform: translate(var(--iso-dx-upper), var(--iso-dy-upper)) scale(0.96); }
    38.6% { opacity: 1; transform: translate(0, 0) scale(1); }
    44.0% { opacity: 0.92; transform: translate(0, 0) scale(1); }
    50.0% { opacity: 1.0; transform: translate(0, 0) scale(1); }
    56.0% { opacity: 0.92; transform: translate(0, 0) scale(1); }
    62.0% { opacity: 1.0; transform: translate(0, 0) scale(1); }
    76.6% { opacity: 1; transform: translate(0, 0) scale(1); }
    88.6% { opacity: 0; transform: translate(var(--iso-dx-upper), var(--iso-dy-upper)) scale(0.96); }
    100.0% { opacity: 0; transform: translate(var(--iso-dx-upper), var(--iso-dy-upper)) scale(0.96); }
  }
  .pe-isotipo-anim--loop .pe-iso__petal {
    animation-duration: 5000ms;
    /* ease-out estandar (no el expo del --once): reparte el movimiento del
       ensamble con una deceleracion limpia en vez de concentrarlo al inicio
       → entrada mas calmada y gradual. */
    animation-timing-function: cubic-bezier(0, 0, 0.58, 1);
    animation-iteration-count: infinite;
  }
  .pe-isotipo-anim--loop .pe-iso__petal--1 { animation-name: pe-iso-loop-1; }
  .pe-isotipo-anim--loop .pe-iso__petal--2 { animation-name: pe-iso-loop-2; }
  .pe-isotipo-anim--loop .pe-iso__petal--3 { animation-name: pe-iso-loop-3; }
  .pe-isotipo-anim--loop .pe-iso__petal--4 { animation-name: pe-iso-loop-4; }
}

/* SELLO DE ENVÍO — isotipo --once revelado al enviarse el form de HubSpot con
   éxito (callback onFormSubmitted en index.php). Vive OCULTO en el HTML: mejora
   progresiva — sin JS el form degrada al "gracias" nativo de HubSpot sin sello;
   onFormSubmitted quita [hidden] y el --once ensambla una vez (reduced-motion:
   isotipo estático completo). Sobre la tarjeta blanca el isotipo va TEAL: gana a
   .pe-section--dark .pe-isotipo (que lo pondría crema, invisible sobre blanco). */
.pe-form-seal { text-align: center; margin-bottom: 1rem; }
.pe-form-seal[hidden] { display: none; }
.pe-section--dark .pe-form-seal .pe-isotipo,
.pe-form-seal .pe-isotipo { color: var(--pe-teal); }


/* ============================================================
   DIAGNÓSTICO INTERACTIVO (.pe-diagnostico)
   Reemplaza las tarjetas de "dolores" por una lista seleccionable.
   Cada fila es un <label> con checkbox nativo (a11y + no-JS). Al marcar
   ≥1, JS revela la franja teal de respuesta con CTA a WhatsApp cuyo texto
   incluye los dolores marcados. Sin JS: lista estática + CTA fijo (.pe-diag-nojs).
   Progressive enhancement: el contenido final vive en el HTML.
   ============================================================ */
.pe-diagnostico {
  max-width: 720px;
  margin: 0 auto;
}
.pe-diagnostico-lead {
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: var(--pe-fs-small);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--pe-teal);
  margin-bottom: 1.25rem;
}

/* Lista de dolores */
.pe-diag-list {
  border: 0;
  margin: 0;
  padding: 0;
}
.pe-diag-row {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: 1.05rem 1.25rem;
  background: var(--pe-blanco);
  border: var(--pe-border-card);
  border-radius: var(--pe-radius);
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
}
.pe-diag-row + .pe-diag-row {
  margin-top: 0.75rem;
}
@media (hover: hover) {
  .pe-diag-row:hover {
    border-color: rgba(17, 54, 62, 0.35);
    box-shadow: var(--pe-shadow);
  }
}
.pe-diag-row:has(.pe-diag-check:checked) {
  border-color: var(--pe-teal);
  background: rgba(17, 54, 62, 0.04);
}

/* Checkbox estilizado del sistema (input nativo con appearance:none) */
.pe-diag-check {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  position: relative;
  width: 22px;
  height: 22px;
  margin: 0.15rem 0 0;
  border: 2px solid var(--pe-teal);
  border-radius: 6px;
  background: var(--pe-blanco);
  cursor: pointer;
  transition: background-color 0.18s ease, border-color 0.18s ease;
}
.pe-diag-check::after {
  content: '';
  position: absolute;
  left: 6px;
  top: 2px;
  width: 5px;
  height: 10px;
  border: solid var(--pe-blanco);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg) scale(0);
  transition: transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.pe-diag-check:checked {
  background: var(--pe-teal);
}
.pe-diag-check:checked::after {
  transform: rotate(45deg) scale(1);
}
.pe-diag-check:focus-visible {
  outline: 2px solid var(--pe-teal);
  outline-offset: 2px;
}

.pe-diag-text {
  display: block;
  min-width: 0;
}
.pe-diag-title {
  display: block;
  font-family: var(--pe-font-head);
  font-weight: 700;
  line-height: 1.3;
  color: var(--pe-marino);
}
.pe-diag-conseq {
  display: block;
  margin-top: 0.25rem;
  font-size: var(--pe-fs-small);
  line-height: 1.45;
  color: var(--pe-carbon);
  opacity: 0.82;
}

/* Franja de respuesta (teal + retícula) — oculta hasta ≥1 marcado */
.pe-diag-response {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1.25rem;
  margin-top: 1.5rem;
  padding: 1.4rem 1.75rem;
  background-color: var(--pe-teal);
  background-image:
    linear-gradient(rgba(240, 238, 233, 0.06) 1px, transparent 1px),
    linear-gradient(90deg, rgba(240, 238, 233, 0.06) 1px, transparent 1px);
  background-size: 30px 30px;
  border-radius: var(--pe-radius);
  color: var(--pe-crema);
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.35s ease, transform 0.35s ease;
}
.pe-diag-response[hidden] {
  display: none;
}
.pe-diag-response.is-in {
  opacity: 1;
  transform: none;
}
.pe-diag-response-text {
  margin: 0;
  font-size: 1.02rem;
  line-height: 1.4;
  flex: 1 1 260px;
}
.pe-diag-count {
  font-family: var(--pe-font-num);
  font-weight: 700;
  color: var(--pe-blanco);
}
/* La cifra va en mono (§6); la frase no. El espacio de JetBrains Mono es casi
   el doble de ancho que el de Instrument Sans, y dentro de "señales detectadas"
   se leía como un doble espacio tecleado por error. */
.pe-diag-word {
  font-weight: 700;
}
.pe-diag-response .pe-diag-cta {
  flex: 0 0 auto;
  margin: 0;
}

/* CTA fijo de degradación sin JS */
.pe-diag-nojs {
  margin-top: 1.5rem;
  text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .pe-diag-response { transition: none; }
  .pe-diag-check::after { transition: none; }
}

@media (max-width: 576px) {
  .pe-diag-response {
    justify-content: center;
    text-align: center;
  }
  .pe-diag-response .pe-diag-cta { width: 100%; }
}

/* ============================================================
   DIAGRAMA TÉCNICO (shell reutilizable — T12)
   El marco común de todo diagrama del sitio: sello, leyenda y pie.
   Trazos crema (el teal se pierde sobre marino — misma regla que la
   calc y el isotipo) y etiquetas mono. Los datos son ILUSTRATIVOS:
   el badge es obligatorio. Las formas específicas viven en el
   <style> de cada página.

   OJO, jul-2026: este shell ya NO describe "un dibujo SVG por página
   de servicio". Las cinco páginas de servicio dejaron de tener
   diagramas SVG — cuatro pasaron a la familia raster de abajo
   (.pe-diagrama--raster) y la quinta no tiene diagrama. El único
   diagrama SVG que queda es el de metodo/, que sí conserva el
   disparo por viewport (pe-diagrama.js añade .play) con
   reduced-motion = estado final estático en el SVG; ese script no se
   carga en ninguna página de servicio. Lo que sigue vivo aquí para
   todos por igual es .pe-diagrama, -badge, -legend y -caption.
   ============================================================ */
.pe-diagrama {
  position: relative;
  max-width: 640px;
  margin: 2.75rem auto 0;
}
/* Sello obligatorio: nada de este diagrama es una cifra real */
.pe-diagrama-badge {
  position: absolute;
  top: 0;
  right: 0;
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.08em;
  color: rgba(240, 238, 233, 0.6);
  border: 1px solid rgba(240, 238, 233, 0.22);
  border-radius: 4px;
  padding: 3px 7px;
}
.pe-diagrama-svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}
.pe-diagrama-legend {
  display: flex;
  gap: 1.5rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 1.1rem;
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.05em;
  color: rgba(240, 238, 233, 0.72);
}
.pe-diagrama-legend span {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}
.pe-diagrama-legend i {
  display: inline-block;
  width: 18px;
  border-top: 2px solid var(--pe-crema);
}
.pe-diagrama-legend i.is-dashed {
  border-top-style: dashed;
  opacity: 0.7;
}
.pe-diagrama-caption {
  max-width: 560px;
  margin: 1.1rem auto 0;
  font-family: var(--pe-font-body);
  font-size: 0.9rem;
  line-height: 1.55;
  text-align: center;
  color: rgba(240, 238, 233, 0.82);
}
@media (max-width: 576px) {
  .pe-diagrama { margin-top: 2rem; }
  .pe-diagrama-badge { font-size: 9px; padding: 2px 5px; }
  .pe-diagrama-legend { gap: 1rem; font-size: 10px; }
}

/* ============================================================
   ESCENA RASTER DE DIAGRAMA (.pe-diagrama--raster) — jul-2026
   Soporte del diagrama cuyo ARTE es una ilustración raster y no
   un dibujo SVG: la imagen va debajo y todo lo que es lenguaje
   —etiquetas y placas de nodo— va ENCIMA en HTML, nunca quemado
   en el píxel. Así el diagrama sigue siendo bilingüe (claves de
   lang.php), seleccionable y legible por lector de pantalla
   aunque la escena sea una imagen.

   Sustituye a la familia .pe-diag-lamina (retirada en el mismo
   batch que la introdujo esta): los otros tres diagramas del
   sitio nunca la usaron y conservan su soporte propio.

   Reglas de la familia:
   · La imagen manda la geometría. El overlay se posiciona en %
     sobre la MISMA caja de la imagen (.pe-diag-raster es el
     contenedor posicionado), y la capa de pulsos vive en un SVG
     con viewBox del tamaño nativo del raster: al escalar la
     imagen todo escala con ella sin desalinearse.
   · El texto del overlay está en px CSS, no en unidades de
     usuario del SVG: no encoge con la imagen y por eso puede
     garantizarse el piso de 10px a 375. Lo que se reposiciona
     por breakpoint son las etiquetas, no la escena.
   · La dirección del flujo la comunica el PULSO (.pe-diag-pulsos):
     un trazo punteado que se desplaza sobre la cinta en el
     sentido de la energía. El pulso es OPCIONAL y depende de lo
     que la escena represente: lo lleva un flujo de energía sobre
     un conductor; NO lo lleva una gráfica. En una curva de
     demanda el eje horizontal es tiempo y no un cable, así que un
     trazo recorriéndola se leería como energía viajando —
     servicios/peak-shaving/ es el caso vivo y por eso no emite la
     capa. Cuando sí la lleva, dos reglas duras:
       – un pulso solo corre sobre la línea central MEDIDA de su
         cinta (trazada sobre el píxel del arte, no a ojo) y solo
         en el sentido de la semántica de ese flujo; si no hay
         línea medida, no hay pulso;
       – el pulso no lleva dato. El estado estático —sin JS, con
         prefers-reduced-motion, o con la capa apagada— es
         exactamente el diagrama publicado (§6: ninguna animación
         mueve una cifra ni una coma, porque no hay nada que la
         animación aporte al contenido).
     La animación es 100% CSS: esta capa no depende de JS.
   · Codificación de fase: --diag-dia (naranja de marca) y
     --diag-noche (teal de marca subido en luminosidad; el
     #11363E puro no se ve sobre marino). El naranja cede a crema
     en cuanto otro naranja de UI puede compartir viewport (§6),
     y los <stop> del gradiente NO llevan hex quemado: toman
     stop-color del token desde aquí, así el relevo alcanza al
     pulso.
   · DOS FAMILIAS DE TOKEN, no una (T32, 29-jul-2026). Hasta T32
     este bloque decía "un solo token, así pulso, etiqueta de
     flujo y muestra de leyenda cambian juntos", y eso ya no es
     cierto: se separaron porque no afirman lo mismo.
       – --diag-dia / --diag-noche son el PULSO: luz que se suma
         a la cinta con mix-blend-mode: screen. Tienen que ser
         claros para verse, y por eso NO pueden seguir al arte
         cuando el arte es oscuro — el pulso "antes" de rescate,
         bajado al gris pizarra de su cinta (#546868 medido),
         desaparecería.
       – --diag-cinta-dia / --diag-cinta-noche son la CINTA TAL
         COMO ESTÁ PINTADA: los consumen la muestra de la leyenda
         y la etiqueta de flujo, que sí afirman "esta línea es de
         este color". Como el arte es raster, ese color está
         quemado en el píxel y no lo decide el CSS: cada pieza
         pone el suyo en el <style> de SU página, medido sobre el
         píxel (_verificacion-no-subir/cinta-color.mjs).
     Por defecto la cinta hereda del pulso, así que una pieza
     nueva cuya cinta ya sea del color de la fase no declara
     nada; solo declara la que se aparta.
   · Límite de la etiqueta: la muestra de leyenda es un filete de
     2px y puede llevar cualquier color del arte, pero la
     etiqueta del overlay es TEXTO y necesita contraste. Cuando
     el color del arte no da para texto legible, la etiqueta se
     queda neutra (sin modificador de fase) en vez de afirmar un
     color falso: caso vivo en servicios/rescate/.
   · Lo que NO vive en este archivo: los tiempos, los grosores de
     trazo y el patrón de punteado de cada cinta dependen de la
     geometría de su arte (largo medido de la línea, ancho de la
     cinta) y van en el <style> local de su página, junto a las
     posiciones porcentuales de las etiquetas. Aquí solo la
     mecánica compartida.
   · La ilustración es AMBIENTACIÓN de marca, no evidencia: el
     sello "ESQUEMA ILUSTRATIVO" (.pe-diagrama-badge) es
     obligatorio y va dentro de la imagen.
   ============================================================ */
.pe-diagrama--raster {
  max-width: 700px;
  /* Fase (pulso) */
  --diag-dia:   var(--pe-naranja);
  --diag-noche: #2E90A8;
  /* Cinta pintada (muestra de leyenda + etiqueta de flujo). Por defecto
     siguen a la fase; cada página sobrescribe la que su arte desmienta. */
  --diag-cinta-dia:   var(--diag-dia);
  --diag-cinta-noche: var(--diag-noche);
}
/* Caja de referencia del overlay: todo lo de dentro se posiciona
   contra la imagen, no contra el bloque (que incluye leyenda y pie). */
.pe-diag-raster {
  position: relative;
  border-radius: var(--pe-radius);
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(240, 238, 233, 0.18);
}
.pe-diag-raster img {
  display: block;
  width: 100%;
  height: auto;
}
.pe-diagrama--raster .pe-diagrama-badge {
  top: 10px;
  right: 10px;
  z-index: 3;
  font-size: 9px;
  padding: 2px 6px;
  background: rgba(10, 18, 32, 0.72);
}

/* Capa de pulsos: la luz que recorre las cintas (SVG a tamaño nativo
   del raster, entre la imagen y el overlay de texto). mix-blend-mode:
   screen hace que el trazo SUME luz a la cinta en vez de taparla — no
   es una segunda cinta encima, es la misma iluminándose por dentro.
   Cada cinta lleva dos trazos con la misma d: halo (ancho, tenue) y
   núcleo (delgado, casi opaco); el "glow" son esos dos, sin filtros
   ni máscaras (barato en GPU de móvil). El desvanecido de las puntas
   es el gradiente del stroke, no una máscara. */
.pe-diag-pulsos {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  pointer-events: none;
  mix-blend-mode: screen;
  /* heredables: valen igual para <path> y para el clon de un <use> */
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.pe-diag-pulsos .pe-diag-halo   { opacity: 0.30; }
.pe-diag-pulsos .pe-diag-nucleo { opacity: 0.92; }
/* El color del pulso se releva por token (§6), no se quema en el <stop>:
   así el naranja→crema de ≤576px arrastra también al gradiente. */
.pe-diag-stop--dia   { stop-color: var(--diag-dia); }
.pe-diag-stop--noche { stop-color: var(--diag-noche); }
/* Crema FIJO: para el tramo de un pulso que ya es crema en el arte y por eso
   NO releva a ≤576px (el relevo va de naranja a crema; el crema se queda).
   Existe para que la regla "ningún <stop> lleva hex quemado" siga valiendo
   también donde el color no depende de la fase. */
.pe-diag-stop--crema { stop-color: var(--pe-crema); }
/* §6 mejora progresiva: reduced-motion = estado final estático, que aquí
   es la ilustración limpia con su overlay. No queda nada a medio camino. */
@media (prefers-reduced-motion: reduce) {
  .pe-diag-pulsos { display: none; }
}

/* Etiquetas: texto real, en px CSS, posicionado en % de la imagen */
.pe-diag-overlay { position: absolute; inset: 0; z-index: 2; }
.pe-diag-etq,
.pe-diag-placa {
  position: absolute;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  font-family: var(--pe-font-num);
  font-weight: 700;
}
.pe-diag-etq {
  font-size: 11px;
  letter-spacing: 0.09em;
  color: rgba(240, 238, 233, 0.88);
  text-shadow: 0 1px 3px rgba(5, 10, 18, 0.95), 0 0 10px rgba(5, 10, 18, 0.8);
}
/* La etiqueta de flujo nombra una cinta, así que se tiñe del color de la
   CINTA, no del pulso (ver las dos familias de token arriba). */
.pe-diag-etq--dia   { color: var(--diag-cinta-dia); }
.pe-diag-etq--noche { color: var(--diag-cinta-noche); }
/* Placa de nodo: el nombre de un nodo siempre va sobre placa, nunca
   suelto — el fondo de una foto no garantiza contraste. */
.pe-diag-placa {
  font-size: 12px;
  letter-spacing: 0.06em;
  color: rgba(240, 238, 233, 0.9);
  background: rgba(9, 17, 28, 0.74);
  border: 1px solid rgba(240, 238, 233, 0.3);
  border-radius: 4px;
  padding: 4px 9px;
}
/* Muestra de leyenda: es la afirmación "esta línea es de este color", así que
   toma el token de la CINTA. Antes de T32 tomaba el de la fase y por eso tres
   de las cuatro piezas mostraban teal para cintas que en el arte son crema o
   gris pizarra. */
.pe-diagrama-legend i.pe-diag-lg--dia   { border-top-color: var(--diag-cinta-dia); }
.pe-diagrama-legend i.pe-diag-lg--noche { border-top-color: var(--diag-cinta-noche); opacity: 1; }

/* ---- Muestra en DEGRADADO (.pe-diag-lg--degradado) ------------------------
   FUERA DE LA GUÍA ANTERIOR, declarado (CLAUDE.md §2.1). Decisión de Ricardo
   del 29-jul-2026 dentro de T32: en servicios/rescate/ la cinta "después" no
   es de un color — arranca crema y remonta a naranja, y el arte lo dibuja así.
   Una muestra de un solo color tendría que elegir una de las dos puntas y
   mentir sobre la otra, cuando la transición ES el contenido de esa cinta.

   Dos cosas que la separan de la muestra base y son deliberadas:
     · El filete pasa de border-top a background-image, porque un border no
       puede llevar gradiente. Se toca solo en este modificador: la base sigue
       siendo border-top y por eso .is-dashed (que es border-top-style) sigue
       funcionando donde se usa.
     · Es más ancha (34px contra 18px). A 18px un crema→naranja se lee como un
       filete sucio en vez de como una transición; el ancho es lo que hace
       legible la única información que esta muestra aporta.
   Los stops reproducen lo medido sobre el píxel del arte: crema hasta ~55% del
   recorrido, naranja en la cola (tramos medidos #F8F2DE #FCF6E1 #FCF7DF
   #FCBA87 #FB5101 de origen a punta). Toma --diag-cinta-dia, así que a ≤576px
   releva a crema con el resto (§6) y la muestra queda toda crema — misma
   consecuencia ya declarada para el pulso de esa cinta. */
.pe-diagrama-legend i.pe-diag-lg--degradado {
  border-top: 0;
  width: 34px;
  height: 2px;
  opacity: 1;
  background-image: linear-gradient(90deg,
    var(--pe-crema) 0%, var(--pe-crema) 55%, var(--diag-cinta-dia) 95%);
}

/* ---- Muestra punteada SOLO en móvil (.pe-diag-lg--movil-guion) ------------
   §6 y decisión 3 de Ricardo (29-jul-2026): a ≤576px --diag-dia releva a crema
   para no tener dos naranjas en pantalla con la barra pegajosa. En las piezas
   cuya cinta neutra TAMBIÉN es crema (medición neta y ciclo BESS) ese relevo
   dejaría las dos muestras idénticas, así que ahí se diferencian por trazo:
   la del flujo de retorno (consumo, descarga) pasa a punteada.

   Es opt-in por marcado, no una regla global de .pe-diag-lg--noche, porque
   rescate NO la necesita —su cinta "antes" es gris pizarra y no colisiona con
   el crema— y aplicársela dibujaría un punteado que su arte no tiene.
   Coste asumido y declarado: en estas dos piezas la muestra punteada describe
   una cinta que en el arte es continua. Es al revés que en peak-shaving, donde
   el punteado de la muestra es fiel porque su límite contratado sí está
   dibujado punteado. */
@media (max-width: 576px) {
  .pe-diagrama-legend i.pe-diag-lg--movil-guion {
    border-top-style: dashed;
  }
}

/* La fila de placas de nodo es lo primero que se aprieta al encoger la
   imagen: el texto está en px y no encoge con ella. Se compensa bajando
   un punto la tipografía y apretando interletrado y acolchado. */
@media (max-width: 768px) {
  .pe-diag-placa { font-size: 11px; padding: 3px 6px; letter-spacing: 0.04em; }
  .pe-diag-etq   { font-size: 10px; }
}
/* §6 — a ≤576px comparte viewport con el CTA naranja de .pe-sticky-cta:
   el naranja del overlay pasa a crema (el del raster no se puede tocar). */
@media (max-width: 576px) {
  .pe-diagrama--raster { --diag-dia: var(--pe-crema); }
  .pe-diagrama--raster .pe-diagrama-badge { font-size: 8px; top: 7px; right: 7px; }
  /* A 10px (el piso) las tres placas de nodo caben en una fila solo si se
     aprieta el interletrado y el acolchado: a 375 la etiqueta más larga
     ("MEDICIÓN NETA") ocupa ~28% del ancho de la imagen. */
  .pe-diag-placa { font-size: 10px; padding: 2px 4px; letter-spacing: 0.02em; }
  .pe-diag-etq   { font-size: 10px; letter-spacing: 0.05em; }
}

/* ============================================================
   REGISTRO CLARO DE ESCENA RASTER (.pe-diagrama--claro) — jul-2026
   FUERA DEL SISTEMA ANTERIOR, declarado (CLAUDE.md §2.1).
   Decisión de Ricardo (28-jul-2026): los diagramas de /metodo/
   NO son placas oscuras — se adaptan al fondo crema de sus
   secciones. Eso obliga a una segunda iluminación de la MISMA
   familia: mismo arte plano editorial, misma paleta de marca,
   misma mecánica de overlay bilingüe; lo único que cambia es que
   la escena está sobre papel claro en vez de noche marino.

   Consecuencia que hay que tener presente: a partir de aquí la
   familia de diagramas tiene DOS registros —las 4 piezas de
   /servicios/ son nocturnas, las de /metodo/ son diurnas—. Se
   sostiene porque es la misma mano dibujando a distinta hora, no
   dos estilos; si en el futuro una pieza nueva no sabe cuál le
   toca, la regla es: la escena sigue al fondo de SU sección.

   Todo .pe-diagrama base está pintado para fondos oscuros (texto
   crema a varias alfas). Sobre claro se rompen cinco cosas, y
   esta clase las invierte una por una:
     1. la placa de nodo (fondo oscuro + texto crema),
     2. la etiqueta suelta (texto crema + sombra negra),
     3. el filete del marco (crema 0.18 → invisible sobre claro),
     4. --diag-noche (#2E90A8 existe porque el teal puro se pierde
        sobre marino; sobre papel pasa lo contrario → teal real),
     5. mix-blend-mode: screen, que sobre base clara ≈ blanco y
        deja el pulso invisible. Ver nota en .pe-diag-pulsos abajo.
   El sello ESQUEMA ILUSTRATIVO sigue siendo obligatorio: el
   registro cambia, la regla de §3 no.
   ============================================================ */
.pe-diagrama--claro {
  --diag-noche: var(--pe-teal);   /* sobre papel el teal real sí contrasta */
}
/* El filete se vuelve marino: sobre crema, el borde de la lámina
   es lo único que separa el papel del arte del papel de la sección. */
.pe-diagrama--claro .pe-diag-raster {
  box-shadow: inset 0 0 0 1px rgba(21, 31, 47, 0.14);
}
/* Sello: chip oscuro sobre arte claro (al revés que en las nocturnas,
   donde el chip oscuro reforzaba la noche). Aquí contrasta por valor. */
.pe-diagrama--claro .pe-diagrama-badge {
  color: rgba(240, 238, 233, 0.92);
  background: rgba(21, 31, 47, 0.78);
  border-color: transparent;
}
/* Etiqueta suelta: tinta marino y sombra CLARA — una sombra oscura
   sobre papel ensucia en vez de despegar. */
.pe-diagrama--claro .pe-diag-etq {
  color: rgba(21, 31, 47, 0.85);
  text-shadow: 0 1px 3px rgba(250, 248, 244, 0.95), 0 0 10px rgba(250, 248, 244, 0.9);
}
.pe-diagrama--claro .pe-diag-etq--dia   { color: var(--diag-dia); }
.pe-diagrama--claro .pe-diag-etq--noche { color: var(--diag-noche); }
/* Placa de nodo invertida: papel con filete marino y tinta marino.
   Sigue siendo placa —el nombre de un nodo nunca va suelto sobre el
   arte—, solo que ahora la placa es clara. */
.pe-diagrama--claro .pe-diag-placa {
  color: var(--pe-marino);
  background: rgba(255, 255, 255, 0.86);
  border-color: rgba(21, 31, 47, 0.22);
}
/* OJO — leyenda y pie NO se tocan aquí a propósito. Viven FUERA de la
   imagen y su contraste lo manda el fondo de la SECCIÓN, no la escena:
   una escena clara puede ir sobre sección marino (es el caso del pilar
   02 de /metodo/) y ahí el pie tiene que seguir siendo crema. Pintarlos
   en esta clase los volvía ilegibles justo en ese caso. Quien invierte
   leyenda y pie es la regla de sección (.met-onlight en /metodo/). */
/* Pulso: 'screen' suma luz y sobre papel claro satura a blanco —
   el trazo desaparece. 'multiply' es su simétrico: OSCURECE la cinta
   por dentro, que es lo que hace una tinta sobre papel. Si una escena
   clara no lleva pulso (una gráfica, p.ej.) esta regla simplemente no
   tiene sobre qué actuar. */
.pe-diagrama--claro .pe-diag-pulsos { mix-blend-mode: multiply; }
/* El relevo naranja→crema de ≤576px (§6) NO aplica sobre papel: el
   crema sobre crema no se ve. Sobre claro el naranja cede a marino,
   que es la otra tinta de la marca y sí contrasta. */
@media (max-width: 576px) {
  .pe-diagrama--claro { --diag-dia: var(--pe-marino); }
}

/* ============================================================
   GALERÍA / LIGHTBOX DE PORTAFOLIO (T13)
   Visor propio sin librerías. Chrome teal/crema (cero naranja).
   Progressive enhancement: sin JS el botón-foto queda inerte y
   la tarjeta se ve igual; con JS abre el visor con las fotos del
   proyecto. object-fit: contain en marco fijo → sin CLS con
   relaciones de aspecto mezcladas.
   ============================================================ */

/* ---- Disparador: la foto de la tarjeta como botón ---- */
button.pe-card-proyecto-foto {
  border: 0;
  padding: 0;
  margin: 0;
  width: 100%;
  background: none;
  font: inherit;
  cursor: zoom-in;
  text-align: left;
}
button.pe-card-proyecto-foto:focus-visible {
  outline: 2px solid var(--pe-teal);
  outline-offset: 3px;
}

/* Distintivo de galería (afford.): conteo + icono, esquina inferior */
.pe-gal-badge {
  position: absolute;
  right: 10px;
  bottom: 10px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 8px;
  border-radius: 999px;
  background: rgba(17, 54, 62, 0.82);
  color: var(--pe-crema);
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.06em;
  line-height: 1;
  backdrop-filter: blur(2px);
  transition: background 0.2s ease, transform 0.2s ease;
}
.pe-gal-badge svg { display: block; width: 12px; height: 12px; }
button.pe-card-proyecto-foto:hover .pe-gal-badge,
button.pe-card-proyecto-foto:focus-visible .pe-gal-badge {
  background: var(--pe-teal);
  transform: translateY(-1px);
}

/* ---- Overlay del visor ---- */
.pe-lightbox {
  position: fixed;
  inset: 0;
  z-index: 9500; /* por encima del botón flotante de WhatsApp (9000) */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(12px, 4vw, 40px);
  background: rgba(9, 14, 22, 0.92);
  backdrop-filter: blur(4px);
  opacity: 0;
  transition: opacity 0.28s ease;
}
.pe-lightbox[hidden] { display: none; }
.pe-lightbox.is-open { opacity: 1; }
body.pe-lb-lock { overflow: hidden; }

/* Retícula de plano sutil sobre el fondo (lenguaje obra-anotada) */
.pe-lightbox::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(240, 238, 233, 0.04) 1px, transparent 1px),
    linear-gradient(90deg, rgba(240, 238, 233, 0.04) 1px, transparent 1px);
  background-size: 44px 44px;
}

.pe-lightbox-dialog {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  max-width: 100%;
  width: 100%;
  height: 100%;
  justify-content: center;
}

/* Marco fijo de la foto: contiene sin recortar ni saltar */
.pe-lb-stage {
  margin: 0;
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.pe-lb-stage picture { display: contents; }
.pe-lb-stage img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: var(--pe-radius);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
  transform: scale(0.985);
  opacity: 0;
  transition: opacity 0.24s ease, transform 0.24s ease;
}
.pe-lb-stage img.is-shown { opacity: 1; transform: scale(1); }

/* Pie: nombre del proyecto + contador mono */
.pe-lb-caption {
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  gap: 14px;
  max-width: 92vw;
  color: var(--pe-crema);
}
.pe-lb-title {
  font-family: var(--pe-font-body);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.01em;
}
.pe-lb-counter {
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  color: rgba(240, 238, 233, 0.72);
  white-space: nowrap;
}

/* ---- Controles ---- */
.pe-lb-btn {
  position: absolute;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(240, 238, 233, 0.28);
  background: rgba(17, 54, 62, 0.72);
  color: var(--pe-crema);
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
  backdrop-filter: blur(2px);
}
.pe-lb-btn:hover,
.pe-lb-btn:focus-visible {
  background: var(--pe-teal);
  border-color: rgba(240, 238, 233, 0.6);
}
.pe-lb-btn:focus-visible { outline: 2px solid var(--pe-crema); outline-offset: 2px; }
.pe-lb-btn svg { display: block; }

.pe-lb-close {
  top: 4px;
  right: 4px;
  width: 44px;
  height: 44px;
}
.pe-lb-nav {
  top: 50%;
  transform: translateY(-50%);
  width: 48px;
  height: 48px;
}
.pe-lb-nav:hover,
.pe-lb-nav:focus-visible { transform: translateY(-50%) scale(1.06); }
.pe-lb-prev { left: 0; }
.pe-lb-next { right: 0; }
.pe-lb-nav[hidden] { display: none; }

@media (max-width: 575px) {
  .pe-lb-nav { width: 42px; height: 42px; bottom: 12px; top: auto; transform: none; }
  .pe-lb-nav:hover, .pe-lb-nav:focus-visible { transform: scale(1.06); }
  .pe-lb-prev { left: 12px; }
  .pe-lb-next { right: 12px; }
  .pe-lb-caption { flex-direction: column; align-items: center; gap: 4px; text-align: center; }
}

@media (prefers-reduced-motion: reduce) {
  .pe-lightbox { transition: none; }
  .pe-lb-stage img { transition: none; transform: none; }
  .pe-gal-badge, .pe-lb-btn { transition: none; }
}

/* ============================================================
   REVEAL POR VIEWPORT (pe-reveal) — reemplazo propio de AOS (T18)
   Motor: Style/Js/pe-reveal.js. El estado oculto previo a la
   animación SOLO existe bajo html.pe-reveal-on, clase que el
   inline del <head> añade únicamente con JS Y sin reduced-motion.
   Sin esa clase (sin JS, o reduced-motion) el contenido se ve
   completo desde el HTML — mejora progresiva, doctrina §6.
   Réplica fiel del fade-up de AOS que reemplaza: subida 100px,
   900ms, easing ease (mismos valores que usaba data-aos-*).
   ============================================================ */
html.pe-reveal-on [data-pe-reveal] {
  opacity: 0;
  transform: translate3d(0, 100px, 0);
  transition: opacity 900ms ease, transform 900ms ease;
}
html.pe-reveal-on [data-pe-reveal="fade"]  { transform: none; }
html.pe-reveal-on [data-pe-reveal="down"]  { transform: translate3d(0, -100px, 0); }
html.pe-reveal-on [data-pe-reveal="left"]  { transform: translate3d(-100px, 0, 0); }
html.pe-reveal-on [data-pe-reveal="right"] { transform: translate3d(100px, 0, 0); }
html.pe-reveal-on [data-pe-reveal].is-in {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* ============================================================
   FOTO ANOTADA (.pe-anotada) — componente global
   Banda de foto real con puntos numerados y notas que se abren al
   pasar el cursor o tocar. Motor: Style/Js/pe-hotspots.js (contrato
   data-pe-hotspots / data-pe-hotspot / data-pe-hotspot-panel); este
   CSS no depende de ninguna otra hoja ni de ningún <style> de página.

   MEJORA PROGRESIVA (CLAUDE.md §6): el estado base es EL DE LAS NOTAS
   VISIBLES. El colapso vive ÚNICAMENTE bajo .pe-anotada.is-armed,
   clase que el JS escribe solo si hay JS, no hay reduced-motion y el
   viewport es ≥768px. Ninguna regla de aquí toca un texto ni una cifra.

   TRAZABILIDAD (§3): --x/--y son porcentajes DE LA FOTO, no del marco.
   El lienzo conserva la proporción real de la imagen (--pe-anot-ar) y
   el marco la recorta a banda con su propia proporción (--pe-anot-banda).
   Como las dos son proporciones y no alturas fijas, la fracción visible
   de la foto es la misma a cualquier ancho: el punto cae siempre sobre
   el mismo pixel del elemento que señala y no hay que recalibrar por
   breakpoint. Las notas viven en una caja gemela del lienzo, FUERA del
   marco, para que el recorte de la banda no las corte.

   Variables (se declaran por instancia, en el HTML):
     --pe-anot-ar     proporción real de la foto (ancho/alto).
     --pe-anot-banda  proporción de la banda; a mayor valor, más recorte.
                      2.62 = los 420px del bloque de obra del index a
                      1100px de ancho de contenedor. Debe ser SIEMPRE
                      mayor que --pe-anot-ar (si no, sobra marco).
     --pe-anot-enc    encuadre vertical opcional (% de la foto): mueve
                      la ventana de recorte cuando el elemento a señalar
                      no está centrado. Positivo = se ve más del alto.
     --x / --y        posición del punto y de su nota, en % de la foto.
     --dx             corrimiento lateral de una nota (px), solo cuando
                      dos notas quedarían encimadas.
     --pe-anot-alto-esc / --pe-anot-alto-movil
                      altos de la banda; SOLO los lee el modificador
                      .pe-anotada--cubre (ver su bloque más abajo), que
                      cambia la banda de proporción a alto fijo.

   Consumidores (T23, 29-jul): el bloque de obra del index —que es el
   origen del patrón— y las dos tarjetas anchas del portafolio. Ya no
   queda copia local: las clases .pe-obra-* del <style> de index.php se
   retiraron y ahí solo viven la cifra, la capa de enlace y los ajustes
   de esa instancia.
   ============================================================ */
.pe-anotada {
  position: relative;
  display: block;
  flex-shrink: 0; /* dentro de .pe-card--proyecto (flex column) la banda no se comprime */
}

/* Marco = la banda visible; recorta el lienzo */
.pe-anotada-marco {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: var(--pe-anot-banda, 2.62);
  overflow: hidden;
}

/* Lienzo = la foto entera, centrada en la banda */
.pe-anotada-lienzo {
  display: block; /* son <span>: sin esto, al volverse estáticos en móvil vuelven a inline */
  position: absolute;
  left: 0;
  top: 50%;
  width: 100%;
  aspect-ratio: var(--pe-anot-ar, 1.7778);
  transform: translateY(calc(-50% + var(--pe-anot-enc, 0%)));
}

.pe-anotada-lienzo picture { display: contents; }

.pe-anotada-lienzo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Velo marino del lenguaje de obra: da contraste a puntos y notas */
.pe-anotada-velo {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to top right, rgba(21, 31, 47, 0.75) 0%, rgba(21, 31, 47, 0.38) 26%, transparent 50%);
}

.pe-anotada-etiqueta {
  position: absolute;
  top: 14px;
  left: 16px;
  z-index: 4;
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--pe-crema);
  background: rgba(21, 31, 47, 0.55);
  padding: 4px 9px;
  border-radius: 4px;
}

/* ---- Punto numerado ---- */
.pe-anotada-punto {
  position: absolute;
  left: var(--x);
  top: var(--y);
  z-index: 3;
  width: 18px;
  height: 18px;
  margin: -9px 0 0 -9px;
  border: 1.5px solid var(--pe-crema);
  border-radius: 50%;
  box-shadow: 0 0 0 3px rgba(21, 31, 47, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
}

.pe-anotada-punto span {
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 8px;
  color: var(--pe-crema);
}

/* ---- Notas: caja gemela del lienzo, fuera del marco ---- */
.pe-anotada-notas {
  display: block;
  position: absolute;
  left: 0;
  top: 50%;
  width: 100%;
  aspect-ratio: var(--pe-anot-ar, 1.7778);
  transform: translateY(calc(-50% + var(--pe-anot-enc, 0%)));
  z-index: 4;
  pointer-events: none;
}

.pe-anotada-nota {
  display: block;
  position: absolute;
  left: var(--x);
  transform: translateX(calc(-50% + var(--dx, 0px)));
  max-width: 250px;
  pointer-events: auto;
  background: rgba(21, 31, 47, 0.88);
  border: 1px solid rgba(240, 238, 233, 0.25);
  border-radius: 8px;
  padding: 8px 11px;
}

/* 52px = 18px de punto + 34px de guía + aire */
.pe-anotada-nota--abajo  { top: calc(var(--y) + 52px); }
.pe-anotada-nota--arriba { bottom: calc(100% - var(--y) + 52px); }

.pe-anotada-nota-titulo {
  display: block;
  font-family: var(--pe-font-num);
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 0.07em;
  color: var(--pe-crema);
  margin-bottom: 2px;
}

.pe-anotada-nota-texto {
  display: block;
  font-family: var(--pe-font-body);
  font-size: 0.78rem;
  line-height: 1.45;
  color: rgba(240, 238, 233, 0.85);
}

/* ---- Disparador de galería dentro de la banda ----
   Dos gestos, dos blancos: el punto abre su anotación, este botón abre
   el visor. Hereda el distintivo .pe-gal-badge de las miniaturas (mismo
   contador, misma esquina); solo cambia que aquí ÉL es el área táctil,
   no la foto entera — de ahí el ::before de ~44px. */
button.pe-gal-badge {
  border: 0;
  font: inherit;
  padding: 7px 11px;
  cursor: zoom-in;
}

button.pe-gal-badge::before {
  content: "";
  position: absolute;
  inset: -8px;
  border-radius: 999px;
}

button.pe-gal-badge:hover,
button.pe-gal-badge:focus-visible {
  background: var(--pe-teal);
  transform: translateY(-1px);
}

button.pe-gal-badge:focus-visible {
  outline: 2px solid var(--pe-crema);
  outline-offset: 2px;
}

/* ============================================================
   MODO CUBRIR (.pe-anotada--cubre) — banda de ALTO FIJO
   ------------------------------------------------------------
   Opt-in. El modo normal de arriba es banda de PROPORCIÓN: el alto
   sale del ancho y la foto se recorta siempre por arriba y por
   abajo. Sirve para las tarjetas del portafolio, donde la banda
   acompaña a una tarjeta que ya manda.

   Este modo es para la banda suelta del index, que necesita un alto
   fijo (420px en escritorio, 300 en teléfono) porque su presencia no
   depende de ninguna tarjeta. Con alto fijo el recorte cambia de eje
   según el ancho: en pantallas anchas sobra alto de foto y se recorta
   arriba/abajo; en pantallas angostas sobra ancho y se recorta por los
   lados. Es lo que hacía object-fit:cover en la copia legada.

   La única línea que importa es el ancho del lienzo:
     max(100%, alto × proporción)
   El segundo término es el ancho que tendría la foto si su ALTO
   llenara la banda. Cuando el marco es más ancho que eso, gana el
   100% (anclado al ancho, recorte vertical); cuando es más angosto,
   gana el calc (anclado al alto, recorte horizontal). Un solo valor
   resuelve los dos casos sin breakpoint inventado — el cruce depende
   de la foto y de la banda, no de un ancho de dispositivo.

   Anclar SIEMPRE al alto no vale: en escritorio dejaría franjas
   vacías a los lados. Anclar siempre al ancho tampoco: es lo que hace
   el modo normal, y con banda alta deja franjas arriba y abajo.

   Lo que NO cambia y es el motivo de todo (§3): los puntos viven
   dentro del lienzo, así que --x/--y siguen siendo % DE LA FOTO y el
   punto cae en el mismo píxel a cualquier ancho. La caja de notas
   repite la misma expresión que el lienzo — si no, --x mediría contra
   dos cajas distintas y las notas se despegarían de sus puntos.

   Variables (por instancia, en el HTML):
     --pe-anot-alto-esc    alto de la banda en escritorio/tableta.
     --pe-anot-alto-movil  alto bajo 768px (opcional; si falta, el de
                           escritorio). Se declaran con estos nombres
                           y NO como --pe-anot-alto, porque el estilo
                           en línea le ganaría a la media query.
   ============================================================ */
.pe-anotada--cubre {
  /* El respaldo NO es decorativo: sin él, una instancia que olvide
     --pe-anot-alto-esc deja --pe-anot-alto en un valor inválido, y entonces
     `height` y el `max()` de abajo caen a su valor inicial — el marco se
     colapsa y el lienzo vuelve al 100% con la proporción base. Se ve como un
     letterbox y no como lo que es, una variable que falta. 420px son los del
     bloque de obra del index, que es donde nació el patrón. */
  --pe-anot-alto: var(--pe-anot-alto-esc, 420px);
  /* Cuando la banda recorta por los lados, el lienzo (y con él la caja de
     notas) es MÁS ANCHO que el bloque. El marco recorta el lienzo, pero la
     caja de notas vive fuera del marco a propósito —para que el recorte de la
     banda no corte una nota— y sin esto su borde derecho empuja el ancho del
     documento: medido, 83px de desborde horizontal a 768px. `clip` en un solo
     eje deja el otro en visible, que es justo lo que hace falta: las notas
     siguen pudiendo salirse por arriba y por abajo de la banda. */
  overflow-x: clip;
}

.pe-anotada--cubre .pe-anotada-marco {
  aspect-ratio: auto;
  height: var(--pe-anot-alto);
}

.pe-anotada--cubre .pe-anotada-lienzo {
  left: 50%;
  width: max(100%, calc(var(--pe-anot-alto) * var(--pe-anot-ar)));
  transform: translate(-50%, calc(-50% + var(--pe-anot-enc, 0%)));
}

/* La caja de notas repite la expresión del lienzo SOLO donde las notas
   flotan. Bajo 768px vuelven al flujo como lista y su caja deja de ser un
   sistema de coordenadas: darle ahí el ancho del lienzo la sacaba del bloque
   (medido: −313px a 375, la lista entera corrida fuera de la pantalla). */
@media (min-width: 768px) {
  .pe-anotada--cubre .pe-anotada-notas {
    left: 50%;
    width: max(100%, calc(var(--pe-anot-alto) * var(--pe-anot-ar)));
    transform: translate(-50%, calc(-50% + var(--pe-anot-enc, 0%)));
  }
}

@media (max-width: 767.98px) {
  .pe-anotada--cubre { --pe-anot-alto: var(--pe-anot-alto-movil, var(--pe-anot-alto-esc)); }
  /* El lienzo sigue cubriendo la banda; las notas no (regla de <768px). */
  .pe-anotada--cubre .pe-anotada-lienzo {
    position: absolute;
    top: 50%;
  }
}

/* Guías del punto a su nota — solo donde las notas flotan */
@media (min-width: 768px) {
  .pe-anotada-punto--abajo::after,
  .pe-anotada-punto--arriba::after {
    content: "";
    position: absolute;
    left: 50%;
    width: 1.2px;
    height: 34px;
    background: rgba(240, 238, 233, 0.75);
  }
  .pe-anotada-punto--abajo::after  { top: 100%; }
  .pe-anotada-punto--arriba::after { bottom: 100%; }
}

/* Notas más estrechas en tablet: la banda es más baja y las cajas
   de 250px se pisarían entre sí */
@media (min-width: 768px) and (max-width: 991.98px) {
  .pe-anotada-nota { max-width: 220px; }
}

/* ---- Estado ARMADO (lo escribe pe-hotspots.js) ---- */
.pe-anotada.is-armed .pe-anotada-punto {
  cursor: pointer;
  background: rgba(21, 31, 47, 0.25);
  transition: background-color 0.22s ease, box-shadow 0.22s ease;
}

/* Zona de toque de 40px sin mover el punto de 18px ya calibrado sobre la foto */
.pe-anotada.is-armed .pe-anotada-punto::before {
  content: "";
  position: absolute;
  inset: -11px;
  border-radius: 50%;
}

.pe-anotada.is-armed .pe-anotada-punto.is-open,
.pe-anotada.is-armed .pe-anotada-punto:focus-visible {
  background: rgba(240, 238, 233, 0.22);
  box-shadow: 0 0 0 3px rgba(21, 31, 47, 0.55);
}

.pe-anotada.is-armed .pe-anotada-punto:focus-visible {
  outline: 2px solid var(--pe-crema);
  outline-offset: 3px;
}

@media (min-width: 768px) {
  .pe-anotada.is-armed .pe-anotada-nota {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.22s ease, transform 0.22s ease, visibility 0s linear 0.22s;
  }
  .pe-anotada.is-armed .pe-anotada-nota--abajo  { transform: translateX(calc(-50% + var(--dx, 0px))) translateY(-6px); }
  .pe-anotada.is-armed .pe-anotada-nota--arriba { transform: translateX(calc(-50% + var(--dx, 0px))) translateY(6px); }
  .pe-anotada.is-armed .pe-anotada-nota.is-open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateX(calc(-50% + var(--dx, 0px)));
    transition-delay: 0s;
  }
  .pe-anotada.is-armed .pe-anotada-punto::after {
    transform: scaleY(0);
    transition: transform 0.22s ease;
  }
  .pe-anotada.is-armed .pe-anotada-punto--abajo::after  { transform-origin: top; }
  .pe-anotada.is-armed .pe-anotada-punto--arriba::after { transform-origin: bottom; }
  .pe-anotada.is-armed .pe-anotada-punto.is-open::after { transform: scaleY(1); }
}

/* Red de seguridad: si alguien armara el bloque bajo reduced-motion (el JS
   no lo hace), las notas siguen visibles y sin movimiento */
@media (min-width: 768px) and (prefers-reduced-motion: reduce) {
  .pe-anotada.is-armed .pe-anotada-nota {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateX(calc(-50% + var(--dx, 0px)));
    transition: none;
  }
  .pe-anotada.is-armed .pe-anotada-punto,
  .pe-anotada.is-armed .pe-anotada-punto::after { transition: none; }
  .pe-anotada.is-armed .pe-anotada-punto::after { transform: none; }
}

/* ---- Móvil (<768px): el JS no arma nada.
   La foto se muestra COMPLETA (sin banda: a este ancho el recorte se
   come el sujeto) y las notas bajan como lista legible. ---- */
@media (max-width: 767.98px) {
  .pe-anotada-marco { aspect-ratio: auto; }
  .pe-anotada-lienzo {
    position: relative;
    top: auto;
    transform: none;
  }
  .pe-anotada-notas {
    position: static;
    width: auto;
    aspect-ratio: auto;
    transform: none;
    pointer-events: auto;
    padding: 14px 26px 0; /* mismo margen lateral que .pe-card-proyecto-body */
  }
  .pe-anotada-nota {
    position: static;
    transform: none;
    max-width: none;
  }
  .pe-anotada-nota + .pe-anotada-nota { margin-top: 8px; }
  button.pe-gal-badge { padding: 6px 10px; }
  /* Sufijo de la etiqueta: se retira en móvil. La etiqueta es una sola línea
     por diseño y a este ancho la más larga (Hielera) se partía en dos y
     tocaba el borde de la banda. Es un CORTE, no una reescritura: el texto
     completo sigue en escritorio y la ficha de la tarjeta nombra la
     ubicación. Marcarlo con la clave *_anot_label_sufijo es opt-in por
     proyecto — sin clave, el <span> no se emite (§7: el texto vive en
     lang.php, esta regla solo decide si se ve). */
  .pe-anotada-etiqueta-sufijo { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  button.pe-gal-badge:hover,
  button.pe-gal-badge:focus-visible { transform: none; }
}
