diff --git a/assets/img/ecosistema/digital.jpg b/assets/img/ecosistema/digital.jpg new file mode 100644 index 0000000..45b4de2 Binary files /dev/null and b/assets/img/ecosistema/digital.jpg differ diff --git a/assets/img/ecosistema/excellence.jpg b/assets/img/ecosistema/excellence.jpg new file mode 100644 index 0000000..8adddc6 Binary files /dev/null and b/assets/img/ecosistema/excellence.jpg differ diff --git a/assets/img/hospital.jpg b/assets/img/ecosistema/hospital.jpg similarity index 100% rename from assets/img/hospital.jpg rename to assets/img/ecosistema/hospital.jpg diff --git a/assets/img/ecosistema/projects.png b/assets/img/ecosistema/projects.png new file mode 100644 index 0000000..3576341 Binary files /dev/null and b/assets/img/ecosistema/projects.png differ diff --git a/assets/img/hero/CONATCTO.png b/assets/img/hero/CONATCTO.png new file mode 100644 index 0000000..cbc2580 Binary files /dev/null and b/assets/img/hero/CONATCTO.png differ diff --git a/assets/img/hero/CTA.png b/assets/img/hero/CTA.png new file mode 100644 index 0000000..e328c7b Binary files /dev/null and b/assets/img/hero/CTA.png differ diff --git a/assets/img/hero/CTA2.png b/assets/img/hero/CTA2.png new file mode 100644 index 0000000..f9d51f3 Binary files /dev/null and b/assets/img/hero/CTA2.png differ diff --git a/assets/img/hero/Ecosistema sin iconos.png b/assets/img/hero/Ecosistema sin iconos.png new file mode 100644 index 0000000..6354e22 Binary files /dev/null and b/assets/img/hero/Ecosistema sin iconos.png differ diff --git a/assets/img/hero/curvas.jpg b/assets/img/hero/curvas.jpg new file mode 100644 index 0000000..4971ccb Binary files /dev/null and b/assets/img/hero/curvas.jpg differ diff --git a/assets/img/hero/team.png b/assets/img/hero/team.png deleted file mode 100644 index 793ea23..0000000 Binary files a/assets/img/hero/team.png and /dev/null differ diff --git a/css/ecosistema.css b/css/ecosistema.css index 0f73395..e34b2d3 100644 --- a/css/ecosistema.css +++ b/css/ecosistema.css @@ -1,92 +1,86 @@ -.animacion-infinito { - width: 80%; - min-width: 600px; - max-width: 1000px; - aspect-ratio: 2 / 1; - position: relative; - background-color: transparent; - } - - .capa-svg-lineas { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 1; - /* Fuerza al navegador a usar la Tarjeta Gráfica (GPU) */ - transform: translateZ(0); - } - - .capa-html-nodos { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 10; - pointer-events: none; - } - - .nodo-circulo { - position: absolute; - border-radius: 50%; - display: flex; - justify-content: center; - align-items: center; - box-shadow: 0 12px 25px rgba(0, 0, 0, 0.15), inset 0 -4px 10px rgba(0,0,0,0.1); - transform: translate(-50%, -50%); - pointer-events: auto; - transition: transform 0.3s ease, box-shadow 0.3s ease; - overflow: hidden; - background-color: #fff; /* Fondo por si usas logos PNG transparentes */ - } - - .nodo-circulo:hover { - transform: translate(-50%, -55%) scale(1.05); - box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2); - cursor: pointer; - } - - /* Estilos para insertar logos como pediste */ - .nodo-contenido { - width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center; - } - - .nodo-contenido img { - width: 70%; /* Ajusta el tamaño de tu logo aquí */ - height: 70%; - object-fit: contain; - } - - /* Estilos de las líneas base SVG */ - .linea-base { - fill: none; - stroke-width: 1.5; - opacity: 0.5; - } - - /* Estilo de los Pulsos */ - .linea-pulso { - fill: none; - stroke: #ffffff; - stroke-width: 6; - stroke-linecap: round; - stroke-dasharray: 0 2000; - filter: drop-shadow(0 0 3px rgba(255, 255, 255, 1)) drop-shadow(0 0 8px rgba(255, 255, 255, 0.8)); - opacity: 1; - /* Le avisa al navegador que esto es lo único que se va a animar */ - will-change: stroke-dashoffset; - } - /* ========================================================================== ECOSISTEMA IDE — Sección con 4 tarjetas y paneles expandibles in-place + Con imagen de fondo + overlay + aside glass + texto al 40% ========================================================================== */ +.animacion-infinito { + width: 80%; + min-width: 600px; + max-width: 1000px; + aspect-ratio: 2 / 1; + position: relative; + background-color: transparent; +} + +.capa-svg-lineas { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1; + transform: translateZ(0); +} + +.capa-html-nodos { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 10; + pointer-events: none; +} + +.nodo-circulo { + position: absolute; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + box-shadow: 0 12px 25px rgba(0, 0, 0, 0.15), inset 0 -4px 10px rgba(0,0,0,0.1); + transform: translate(-50%, -50%); + pointer-events: auto; + transition: transform 0.3s ease, box-shadow 0.3s ease; + overflow: hidden; + background-color: #fff; +} + +.nodo-circulo:hover { + transform: translate(-50%, -55%) scale(1.05); + box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2); + cursor: pointer; +} + +.nodo-contenido { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.nodo-contenido img { + width: 70%; + height: 70%; + object-fit: contain; +} + +.linea-base { + fill: none; + stroke-width: 1.5; + opacity: 0.5; +} + +.linea-pulso { + fill: none; + stroke: #ffffff; + stroke-width: 6; + stroke-linecap: round; + stroke-dasharray: 0 2000; + opacity: 1; +} + /* ---------- Variables locales por unidad ---------- */ .ecosistema-section { --unit: var(--ide-primary); @@ -96,19 +90,35 @@ .eco-panel--excellence, .eco-card--excellence, -.eco-pill--excellence { --unit: var(--ide-excellence); --unit-dark: var(--ide-excellence-dark); --unit-soft: rgba(0, 158, 143, 0.10); } +.eco-pill--excellence { + --unit: var(--ide-excellence); + --unit-dark: var(--ide-excellence-dark); + --unit-soft: rgba(0, 158, 143, 0.10); +} .eco-panel--projects, .eco-card--projects, -.eco-pill--projects { --unit: var(--ide-projects); --unit-dark: var(--ide-projects-dark); --unit-soft: rgba(242, 140, 43, 0.10); } +.eco-pill--projects { + --unit: var(--ide-projects); + --unit-dark: var(--ide-projects-dark); + --unit-soft: rgba(242, 140, 43, 0.10); +} .eco-panel--digital, .eco-card--digital, -.eco-pill--digital { --unit: var(--ide-digital); --unit-dark: var(--ide-digital-dark); --unit-soft: rgba(29, 113, 184, 0.10); } +.eco-pill--digital { + --unit: var(--ide-digital); + --unit-dark: var(--ide-digital-dark); + --unit-soft: rgba(29, 113, 184, 0.10); +} .eco-panel--academy, .eco-card--academy, -.eco-pill--academy { --unit: var(--ide-academy); --unit-dark: var(--ide-academy-dark); --unit-soft: rgba(200, 16, 46, 0.10); } +.eco-pill--academy { + --unit: var(--ide-academy); + --unit-dark: var(--ide-academy-dark); + --unit-soft: rgba(200, 16, 46, 0.10); +} /* ---------- Header del ecosistema ---------- */ .eco-header { @@ -125,7 +135,7 @@ /* ---------- Grid de 4 tarjetas ---------- */ .eco-grid { display: grid; - grid-template-columns: repeat(4, 1fr); + grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.5rem; } @@ -133,6 +143,7 @@ position: relative; border-radius: var(--radius-lg); overflow: hidden; + min-width: 0; background: var(--bg-surface); border: 1px solid var(--border-color); transition: transform .35s ease, border-color .35s ease, box-shadow .35s ease; @@ -146,16 +157,20 @@ .eco-card__btn { all: unset; + box-sizing: border-box; display: flex; flex-direction: column; align-items: flex-start; gap: .85rem; padding: 2rem 1.6rem 1.75rem; width: 100%; + min-width: 0; height: 100%; cursor: pointer; position: relative; z-index: 1; + font: inherit; + color: inherit; } .eco-card__btn:focus-visible { @@ -164,7 +179,6 @@ border-radius: var(--radius-lg); } -/* Ícono circular */ .eco-card__icon-wrap { width: 64px; height: 64px; @@ -199,6 +213,8 @@ line-height: 1.2; color: var(--text-main); margin: 0; + hyphens: auto; + min-width: 0; } .eco-card__text { @@ -206,6 +222,8 @@ color: var(--text-muted); line-height: 1.55; margin: 0 0 auto; + overflow-wrap: break-word; + min-width: 0; } .eco-card__cta { @@ -224,7 +242,6 @@ .eco-card__cta i { transition: transform .3s ease; } .eco-card:hover .eco-card__cta i { transform: translateX(5px); } -/* Curva decorativa inferior por tarjeta */ .eco-card::after { content: ""; position: absolute; @@ -318,25 +335,79 @@ color: #fff; } -/* ---------- Panel de unidad ---------- */ +/* ========================================================================== + PANEL DE UNIDAD — Imagen + overlay + glass aside + texto 40% + ========================================================================== */ + .eco-panel { position: relative; border-radius: var(--radius-lg); overflow: hidden; background: var(--bg-surface); border: 1px solid var(--border-color); - padding: clamp(2rem, 4vw, 3rem); isolation: isolate; + /* Sin padding general: el grid interno y la strip manejan sus espacios */ } -/* Fondo con curvas SVG teñidas por el color de la unidad */ -.eco-panel__bg { +/* ---------- Capa 0: imagen de fondo ---------- */ +.eco-panel__media { position: absolute; inset: 0; z-index: 0; + margin: 0; + overflow: hidden; pointer-events: none; - color: var(--unit); - opacity: .12; +} + +.eco-panel__media img { + width: 100%; + height: 100%; + object-fit: cover; + object-position: center right; + display: block; + filter: saturate(.85) contrast(1.02); + transform: scale(1.01); +} + +/* ---------- Capa 1: overlay con gradiente horizontal ---------- */ +.eco-panel__overlay { + position: absolute; + inset: 0; + z-index: 1; + pointer-events: none; + /* Color de unidad a la izquierda → transparente a la derecha */ + background: + linear-gradient( + 90deg, + color-mix(in srgb, var(--unit) 92%, black 8%) 0%, + color-mix(in srgb, var(--unit) 78%, black 22%) 28%, + color-mix(in srgb, var(--unit) 40%, transparent) 55%, + transparent 80% + ); +} + +/* Velo inferior para fundir con la strip */ +.eco-panel__overlay::after { + content: ""; + position: absolute; + inset: 0; + background: linear-gradient( + 180deg, + transparent 0%, + transparent 72%, + color-mix(in srgb, var(--bg-surface) 60%, transparent) 100% + ); +} + +/* ---------- Capa 2: curvas SVG fundidas con el gradiente ---------- */ +.eco-panel__bg { + position: absolute; + inset: 0; + z-index: 2; + pointer-events: none; + color: #ffffff; + opacity: .16; + mix-blend-mode: overlay; } .eco-panel__bg svg { @@ -354,15 +425,25 @@ .eco-panel__bg path:nth-child(1) { opacity: .9; } .eco-panel__bg path:nth-child(2) { opacity: .5; } -/* Grid principal del panel */ +/* ---------- Capa 3: contenido (texto 40% | aside glass al borde derecho) ---------- */ .eco-panel__grid { position: relative; - z-index: 1; + z-index: 3; display: grid; - grid-template-columns: 1.1fr 1fr; - gap: 2.5rem; - align-items: start; - margin-bottom: 2.5rem; + grid-template-columns: minmax(0, 40%) 1fr; + gap: 2rem; + align-items: stretch; + padding: clamp(2rem, 3.5vw, 3rem); + min-height: 440px; +} + +/* Columna principal: texto limitado al 40% */ +.eco-panel__main { + display: flex; + flex-direction: column; + justify-content: center; + gap: .9rem; + color: #ffffff; } .eco-panel__brand { @@ -370,41 +451,60 @@ font-family: 'Bebas Neue', sans-serif; letter-spacing: .32em; font-size: 1rem; - color: var(--unit); - margin-bottom: .75rem; + color: #ffffff; + opacity: .92; + margin-bottom: .25rem; } .eco-panel__title { font-family: 'Barlow Semi Condensed', sans-serif; font-size: clamp(1.8rem, 3vw, 2.4rem); line-height: 1.15; - color: var(--text-main); - margin-bottom: 1rem; + color: #ffffff; + margin: 0; } .eco-panel__lead { - font-size: 1.02rem; - color: var(--text-body); - line-height: 1.65; - margin-bottom: 1.5rem; - max-width: 52ch; + font-size: 1rem; + line-height: 1.6; + color: rgba(255, 255, 255, 0.9); + margin: 0; } +/* CTA invertido para máximo contraste sobre el color de la unidad */ .eco-panel__cta { - background-color: var(--unit); - border-color: var(--unit); -} -.eco-panel__cta:hover { - background-color: var(--unit-dark); - border-color: var(--unit-dark); + align-self: flex-start; + background-color: #ffffff; + border-color: #ffffff; + color: var(--unit-dark); + margin-top: .5rem; } -/* Lista lateral de capacidades */ +.eco-panel__cta:hover { + background-color: rgba(255, 255, 255, 0.9); + border-color: rgba(255, 255, 255, 0.9); + color: var(--unit-dark); +} + +/* ---------- Aside glass pegado al borde derecho ---------- */ .eco-panel__side { - background: color-mix(in srgb, var(--unit) 5%, var(--bg-surface)); - border: 1px solid color-mix(in srgb, var(--unit) 22%, var(--border-color)); + align-self: center; + justify-self: end; + width: min(380px, 100%); + padding: 1.5rem 1.5rem 1.35rem; border-radius: var(--radius-md); - padding: 1.5rem 1.4rem; + + background: color-mix(in srgb, var(--unit) 50%, transparent); + border: 1px solid color-mix(in srgb, #ffffff 32%, transparent); + backdrop-filter: blur(14px) saturate(140%); + -webkit-backdrop-filter: blur(14px) saturate(140%); + box-shadow: + 0 18px 40px -20px rgba(0, 0, 0, .35), + inset 0 1px 0 rgba(255, 255, 255, .18); + + color: #ffffff; + /* Sangrado hacia el borde derecho para “tocar” el borde del panel */ + margin-right: clamp(-2.5rem, -2vw, -1rem); } .eco-panel__side-title { @@ -413,64 +513,69 @@ text-transform: uppercase; letter-spacing: .08em; font-size: .95rem; - color: var(--unit); + color: #ffffff; + opacity: .92; margin-bottom: 1rem; } .eco-panel__list { list-style: none; display: grid; - gap: .9rem; + gap: .85rem; margin: 0; padding: 0; } .eco-panel__list li { display: flex; - gap: .75rem; + gap: .7rem; align-items: flex-start; } .eco-panel__li-icon { flex-shrink: 0; - width: 34px; - height: 34px; + width: 32px; + height: 32px; border-radius: 50%; display: grid; place-items: center; - background: var(--unit-soft); - color: var(--unit); - font-size: .85rem; + background: rgba(255, 255, 255, .16); + border: 1px solid rgba(255, 255, 255, .25); + color: #ffffff; + font-size: .8rem; } .eco-panel__list strong { display: block; font-family: 'Barlow Condensed', sans-serif; font-weight: 700; - font-size: 1rem; - color: var(--text-main); + font-size: .98rem; + color: #ffffff; letter-spacing: .02em; } .eco-panel__list p { - font-size: .85rem; - color: var(--text-muted); + font-size: .82rem; + color: rgba(255, 255, 255, .85); line-height: 1.45; margin: .1rem 0 0; } -/* Franja inferior con minicards */ +/* ---------- Franja inferior: fondo sólido, corta la imagen ---------- */ .eco-panel__strip { position: relative; - z-index: 1; - border-top: 1px solid color-mix(in srgb, var(--unit) 20%, var(--border-color)); - padding-top: 1.75rem; + z-index: 3; + /*background: var(--bg-surface);*/ + bottom: 0; + + padding: 0rem clamp(2rem, 3.5vw, 3rem) clamp(1rem, 1vw, 1rem); + /*border-top: 1px solid color-mix(in srgb, var(--unit) 22%, var(--border-color));*/ } .eco-panel__strip-title { font-family: 'Barlow Semi Condensed', sans-serif; font-size: 1.1rem; - color: var(--text-main); + color: var(--text-inverse); margin-bottom: 1rem; } @@ -511,15 +616,48 @@ ========================================================================== */ @media (max-width: 1100px) { - .eco-grid { grid-template-columns: repeat(2, 1fr); } - .eco-panel__grid { grid-template-columns: 1fr; gap: 1.75rem; } + .eco-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } + + .eco-panel__grid { + grid-template-columns: 1fr; + gap: 1.75rem; + min-height: 0; + padding: 1.75rem; + } + + .eco-panel__side { + justify-self: stretch; + width: 100%; + margin-right: 0; + } + + .eco-panel__media img { + object-position: center; + } + .eco-panel__strip-grid { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 640px) { - .eco-grid { grid-template-columns: 1fr; } - .eco-panel { padding: 1.5rem; } + .eco-grid { grid-template-columns: minmax(0, 1fr); } + + .eco-panel__grid { + padding: 1.5rem; + } + + /* En mobile el gradiente pasa a vertical porque el texto ya no está a la izquierda */ + .eco-panel__overlay { + background: + linear-gradient( + 180deg, + color-mix(in srgb, var(--unit) 92%, black 8%) 0%, + color-mix(in srgb, var(--unit) 60%, transparent) 60%, + transparent 100% + ); + } + .eco-panel__strip-grid { grid-template-columns: 1fr; } + .eco-unit__topbar { flex-direction: column; align-items: stretch; } .eco-unit__nav { justify-content: flex-start; } } @@ -529,7 +667,11 @@ [data-theme="dark"] .eco-panel { background: var(--bg-surface); } -[data-theme="dark"] .eco-panel__side, + +[data-theme="dark"] .eco-panel__media img { + filter: saturate(.8) brightness(.88) contrast(1.02); +} + [data-theme="dark"] .eco-mini { background: color-mix(in srgb, var(--unit) 10%, var(--bg-surface)); } @@ -541,7 +683,8 @@ .eco-card__cta i, .eco-mini, .eco-unit__back, - .eco-state--unit { + .eco-state--unit, + .eco-panel__media img { transition: none !important; animation: none !important; } diff --git a/css/styles.css b/css/styles.css index c0ce2cc..6c8cd82 100644 --- a/css/styles.css +++ b/css/styles.css @@ -308,6 +308,10 @@ p, li, .lead-text, .text-body, .text-muted { .section-padding-npb { padding-top: clamp(1rem, 2vw, 3.5rem); } +.section-padding-xs { + padding-top: clamp(0.5rem, 1vw, 1.5rem); + padding-bottom: clamp(1rem, 2vw, 1.5rem); +} .bg1{ background: radial-gradient(circle at 20% 80%, var(--ide-accent-soft) 0%, transparent 50%), var(--bg-body); @@ -374,6 +378,20 @@ p, li, .lead-text, .text-body, .text-muted { background-position: center; background-repeat: no-repeat; } +.herobg-5{ + background-image: + linear-gradient( + to right, + rgba(0, 0, 0, 0.6) 0%, + rgba(0, 0, 0, 0.3) 20%, + rgba(0, 0, 0, 0.15) 70%, + rgba(0, 0, 0, 0.0) 100% + ), + url('../assets/img/hero/CTA2.png'); + background-size: cover; + background-position: center; + background-repeat: no-repeat; +} @@ -2606,6 +2624,26 @@ canvas { filter: grayscale(100%); opacity: 0.1; } +.parallax-bg-layer3 { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + /* Imagen de fondo */ + background-image: url('../assets/img/hero/curvas.jpg'); + background-position: center center; + background-repeat: no-repeat; + background-size: cover; + + /* CLAVE: Deja la imagen fija en el viewport mientras el sitio scrollea */ + background-attachment: fixed; + + /* Estética sobria IDE */ + filter: grayscale(100%); + opacity: 0.1; +} /* Cortina suave en bordes superior e inferior para fundir con el header/footer */ .parallax-overlay { position: absolute; diff --git a/desafios.html b/desafios.html index f9dc186..bb84de1 100644 --- a/desafios.html +++ b/desafios.html @@ -46,11 +46,8 @@ -
- +
+
diff --git a/ecosistema.html b/ecosistema.html index 170e39b..ee9cca4 100644 --- a/ecosistema.html +++ b/ecosistema.html @@ -34,7 +34,7 @@
- Conocé el Ecosistema -
+
+
+
+
@@ -85,7 +91,7 @@ IDE EXCELLENCE -

Excelencia operacional y sistemas de gestión

+

Excelencia operacional y
sistemas de gestión

Procesos, ISO, riesgos y mejora continua para sostener el desempeño.

Explorar unidad @@ -146,14 +152,13 @@
- -
-
-
- CAPACIDADES -

Conocé Nuestro Ecosistema en detalle

-
- -
-
-
-

IDE Excellence

-

Para fortalecer la gestión y mejorar el desempeño

-

- Integramos procesos, sistemas de gestión, mejora continua y sostenibilidad para ayudar a las organizaciones a gestionar mejor, optimizar su desempeño y generar valor sostenible. -

-
- Procesos - Sistemas de gestión - Mejora continua - Desempeño - Riesgos - Sostenibilidad -
- HABLEMOS → -
-
- IDE Excellence -
-
-
- - -
-
-
- IDE Project -
-
-

IDE Project

-

Para convertir iniciativas en resultados

-

- Fortalecemos la capacidad de las organizaciones para seleccionar, priorizar y gestionar proyectos, conectando estrategia, recursos y ejecución para transformar iniciativas en resultados. -

-
- Proyectos - PMO - Portafolios - Gobernanza - Metodologías - Resultados -
- HABLEMOS → -
-
-
- - -
-
-
-

IDE Digital

-

Tecnología con sentido

-

- Conectamos gestión, procesos, datos e inteligencia artificial para identificar dónde la tecnología puede simplificar, automatizar y potenciar la forma en que las organizaciones trabajan y toman decisiones. -

-
- Digitalización - Automatización - Datos - Inteligencia Artificial - Integración - Decisiones -
- HABLEMOS → -
-
- IDE Digital -
-
-
- - -
-
-
- IDE Academy -
-
-

IDE Academy

-

Para desarrollar capacidades

-

- Diseñamos experiencias de aprendizaje que conectan conocimiento, práctica y contexto para fortalecer las capacidades que profesionales, equipos y organizaciones necesitan para gestionar, liderar y transformar. -

-
- Formación Ejecutiva - In-Company - Programas - Talleres - Rutas de aprendizaje -
- EXPLORAR ACADEMY → -
-
-
-
-
- - +
@@ -581,16 +485,38 @@
- -
-
-

¿Dónde podemos generar mayor impacto en tu organización?

-

- Conversemos para comprender tu desafío e identificar qué capacidades pueden aportar mayor valor. -

-
- HABLEMOS - Explorar Punto de Partida + +
+
+
+
+ +

+ Una única solución no siempre
encaja para todos los desafíos. +

+

+ Integramos las capacidades necesarias para diseñar una respuesta que tenga sentido para tu organización y su contexto. +

+ + + +
+ +
+
+
diff --git a/index.html b/index.html index 3afc3f5..5d3908e 100644 --- a/index.html +++ b/index.html @@ -123,7 +123,7 @@

Fortalecer la gestión

Sistemas de gestión, normas ISO (9001, 14001, 45001, 50001, 22000, 27001, 28000, 39001, 21001 y 29993), gestión por procesos, calidad y mejora continua con sentido de negocio.

- Explorar Excellence → + Explorar Excellence →
diff --git a/js/ecosistema.js b/js/ecosistema.js index e146b28..8ac898c 100644 --- a/js/ecosistema.js +++ b/js/ecosistema.js @@ -1,5 +1,6 @@ /* ========================================================================== - ECOSISTEMA IDE — Cambio in-place entre tarjetas y paneles de unidad + ECOSISTEMA IDE — Cambio in-place + deep link por hash + URLs válidas: #eco-excellence | #eco-projects | #eco-digital | #ecosistema ========================================================================== */ (function () { 'use strict'; @@ -14,117 +15,173 @@ const backBtn = section.querySelector('[data-eco-close]'); const pills = Array.from(section.querySelectorAll('.eco-pill')); - let lastFocusedTrigger = null; + const VALID_UNITS = ['excellence', 'projects', 'digital']; + const HASH_PREFIX = '#eco-'; + const HASH_ECOSYSTEM = '#ecosistema'; - /* --- Mostrar panel de una unidad --- */ - function openUnit(id) { + let lastFocusedTrigger = null; + let currentUnit = null; // null = ecosistema + + /* ---------- Utilidades de URL ---------- */ + function unitFromHash() { + const h = window.location.hash; + if (h === HASH_ECOSYSTEM) return null; + if (h.startsWith(HASH_PREFIX)) { + const id = h.slice(HASH_PREFIX.length); + return VALID_UNITS.includes(id) ? id : null; + } + return null; + } + + function hashForUnit(id) { + return id ? HASH_PREFIX + id : HASH_ECOSYSTEM; + } + + /* ---------- Render (no toca la URL) ---------- */ + function renderUnit(id) { const panel = panels.find(p => p.dataset.ecoPanel === id); if (!panel) return; - // Guardamos el trigger que originó el cambio (para devolver foco) const origin = triggers.find(t => t.dataset.ecoOpen === id); if (origin) lastFocusedTrigger = origin; - // Ocultar ecosistema, mostrar estado unidad stateEcosystem.hidden = true; stateUnit.hidden = false; - // Alternar paneles panels.forEach(p => { const isActive = p.dataset.ecoPanel === id; p.hidden = !isActive; if (isActive) { - // Re-trigger de la animación de entrada p.style.animation = 'none'; - // Forzar reflow - void p.offsetWidth; + void p.offsetWidth; // reflow para reiniciar animación p.style.animation = ''; } }); - // Aria expandido en tarjetas triggers.forEach(t => { - const isThis = t.dataset.ecoOpen === id; - t.setAttribute('aria-expanded', isThis ? 'true' : 'false'); + t.setAttribute('aria-expanded', t.dataset.ecoOpen === id ? 'true' : 'false'); }); - // Pills activas pills.forEach(pill => { pill.classList.toggle('is-active', pill.dataset.ecoOpen === id); }); - // Foco accesible al título del panel const title = panel.querySelector('.eco-panel__title'); if (title) { title.setAttribute('tabindex', '-1'); - // Pequeño timeout para asegurar visibilidad tras el cambio de estado requestAnimationFrame(() => title.focus({ preventScroll: false })); } - // Scroll suave al inicio de la sección (solo si quedó fuera de vista) - const rect = section.getBoundingClientRect(); - if (rect.top < -80) { - section.scrollIntoView({ behavior: 'smooth', block: 'start' }); - } + currentUnit = id; } - /* --- Volver al estado ecosistema --- */ - function closeUnit() { + function renderEcosystem({ restoreFocus = true } = {}) { stateUnit.hidden = true; stateEcosystem.hidden = false; triggers.forEach(t => t.setAttribute('aria-expanded', 'false')); pills.forEach(p => p.classList.remove('is-active')); - // Devolver foco a la tarjeta origen - if (lastFocusedTrigger && typeof lastFocusedTrigger.focus === 'function') { - lastFocusedTrigger.focus({ preventScroll: false }); - } else { - // Fallback: primer botón del grid - const first = triggers[0]; - if (first) first.focus({ preventScroll: false }); + if (restoreFocus) { + if (lastFocusedTrigger && typeof lastFocusedTrigger.focus === 'function') { + lastFocusedTrigger.focus({ preventScroll: false }); + } else if (triggers[0]) { + triggers[0].focus({ preventScroll: false }); + } + } + + currentUnit = null; + } + + /* ---------- API con URL ---------- */ + function openUnit(id, { push = true, scroll = true } = {}) { + if (!VALID_UNITS.includes(id)) return; + renderUnit(id); + + if (push) { + const url = window.location.pathname + window.location.search + hashForUnit(id); + history.pushState({ eco: id }, '', url); + } + + if (scroll) { + const rect = section.getBoundingClientRect(); + if (rect.top < -80 || rect.top > 200) { + section.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } } } - /* --- Listeners --- */ + function closeUnit({ push = true, scroll = false } = {}) { + renderEcosystem(); + if (push) { + const url = window.location.pathname + window.location.search + HASH_ECOSYSTEM; + history.pushState({ eco: null }, '', url); + } + if (scroll) { + section.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } + } + + /* ---------- Listeners de UI ---------- */ triggers.forEach(trigger => { trigger.addEventListener('click', (e) => { const id = trigger.dataset.ecoOpen; if (!id) return; - // Si es un real (academy), dejamos que navegue + // Academy es : dejamos navegar if (trigger.tagName === 'A' && trigger.getAttribute('href')) return; e.preventDefault(); openUnit(id); }); - // Soporte teclado para tarjetas no-button (por si acaso) trigger.addEventListener('keydown', (e) => { - if (e.key === 'Enter' || e.key === ' ') { - const id = trigger.dataset.ecoOpen; - if (!id) return; - if (trigger.tagName === 'A') return; - e.preventDefault(); - openUnit(id); - } + if (e.key !== 'Enter' && e.key !== ' ') return; + const id = trigger.dataset.ecoOpen; + if (!id) return; + if (trigger.tagName === 'A') return; + e.preventDefault(); + openUnit(id); }); }); - if (backBtn) backBtn.addEventListener('click', closeUnit); + if (backBtn) backBtn.addEventListener('click', () => closeUnit({ scroll: true })); - // Escape cierra el panel expandido section.addEventListener('keydown', (e) => { - if (e.key === 'Escape' && !stateUnit.hidden) { - closeUnit(); - } + if (e.key === 'Escape' && !stateUnit.hidden) closeUnit(); }); - /* --- Deep link opcional por hash (#eco-projects) sin recargar --- */ - function readHash() { - const hash = window.location.hash.replace('#eco-', ''); - if (['excellence', 'projects', 'digital'].includes(hash)) { - openUnit(hash); + /* ---------- Sincronización con la URL ---------- */ + function syncFromLocation() { + const id = unitFromHash(); + if (id && id !== currentUnit) { + renderUnit(id); + } else if (!id && currentUnit !== null) { + renderEcosystem({ restoreFocus: false }); } } - window.addEventListener('hashchange', readHash); - readHash(); + + // Carga inicial: si el hash trae unidad, abrir + scroll + (function initFromUrl() { + const id = unitFromHash(); + if (id) { + renderUnit(id); + requestAnimationFrame(() => { + section.scrollIntoView({ behavior: 'auto', block: 'start' }); + }); + } else { + renderEcosystem({ restoreFocus: false }); + } + })(); + + // Cambios manuales del hash (pegar link, editar barra, links compartidos) + window.addEventListener('hashchange', syncFromLocation); + + // Atrás/adelante del navegador + window.addEventListener('popstate', syncFromLocation); + + /* ---------- API pública opcional ---------- */ + window.EcoIDE = { + open: openUnit, + close: closeUnit, + current: () => currentUnit, + }; })(); \ No newline at end of file diff --git a/js/netschema.js b/js/netschema.js index 5728009..56b5f1f 100644 --- a/js/netschema.js +++ b/js/netschema.js @@ -116,7 +116,7 @@ const nodosData = [ // Crear pulsos conn.pulsos = []; - const cantPulsos = 10; + const cantPulsos = 6; for (let i = 0; i < cantPulsos; i++) { const pathPulso = document.createElementNS('http://www.w3.org/2000/svg', 'path'); @@ -149,24 +149,54 @@ const nodosData = [ }); }, 1200); - // 4. Motor de Animación Ultraligero - function animarFrame() { - conexiones.forEach(conn => { - conn.pulsos.forEach(p => { - p.dash -= p.speed; - - // OPTIMIZACIÓN EXTREMA: Solo interactuamos con el DOM si el pulso saltó de carril - if (p.needsPathUpdate) { - p.el.setAttribute('d', conn.rutasCache[p.currentOffset]); - p.needsPathUpdate = false; - } - - // Lo único que se actualiza contínuamente es el desplazamiento - p.el.style.strokeDashoffset = p.dash; - }); - }); +// 4. Motor de Animación Ultraligero +let animando = false; +let rafId = null; - requestAnimationFrame(animarFrame); - } +function animarFrame() { + if (!animando) return; // corta el loop cuando no es visible + conexiones.forEach(conn => { + conn.pulsos.forEach(p => { + p.dash -= p.speed; + if (p.needsPathUpdate) { + p.el.setAttribute('d', conn.rutasCache[p.currentOffset]); + p.needsPathUpdate = false; + } + p.el.style.strokeDashoffset = p.dash; + }); + }); + rafId = requestAnimationFrame(animarFrame); +} - animarFrame(); \ No newline at end of file +function iniciarAnimacion() { + if (animando) return; + animando = true; + rafId = requestAnimationFrame(animarFrame); +} + +function detenerAnimacion() { + animando = false; + if (rafId) cancelAnimationFrame(rafId); +} + +// Detectar visibilidad de la sección del header +const heroVisual = document.querySelector('.hero-visual'); +if (heroVisual && 'IntersectionObserver' in window) { + const io = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) iniciarAnimacion(); + else detenerAnimacion(); + }); + }, { threshold: 0.05 }); + io.observe(heroVisual); +} else { + iniciarAnimacion(); // fallback +} + +// Pausar también cuando la pestaña queda oculta +document.addEventListener('visibilitychange', () => { + if (document.hidden) detenerAnimacion(); + else if (heroVisual && heroVisual.getBoundingClientRect().top < window.innerHeight) { + iniciarAnimacion(); + } +}); \ No newline at end of file diff --git a/soluciones.html b/soluciones.html index 203fdb4..043d0bd 100644 --- a/soluciones.html +++ b/soluciones.html @@ -46,7 +46,11 @@
-
+
+