d15312625b
- Hero opacity 0.30→0.55, gradient overlay softened (15%/75% vs 30%/60%) - DifferenceCards photo opacity 0.15→0.40 - ProcessSteps photo opacity 0.15→0.35, removed backdrop-blur - Added photo backgrounds to 11 hero sections across all pages: - planes/en/plans: datacenter-racks - servicios/en/servicios: monitor-grafana - nosotros/en/about: team-desk-mate - contacto/en/contact: hands-typing-coffee - preguntas: maldonado-aerial - instructivos/en/tutorials: monitor-grafana - All hero photos at opacity 0.25 with gradient overlay for text readability
300 lines
8.1 KiB
Plaintext
300 lines
8.1 KiB
Plaintext
---
|
|
// "Cómo trabajamos" — Horizontal asymmetric circles with organic SVG connecting line
|
|
import SectionEyebrow from './SectionEyebrow.astro';
|
|
import type { TranslationKey } from '@/i18n/ui';
|
|
|
|
interface Props {
|
|
t: (key: TranslationKey) => string;
|
|
}
|
|
const { t } = Astro.props;
|
|
|
|
const steps = [
|
|
{ num: '01', titleKey: 'process.step1.title' as TranslationKey, bodyKey: 'process.step1.body' as TranslationKey, yPct: 35 },
|
|
{ num: '02', titleKey: 'process.step2.title' as TranslationKey, bodyKey: 'process.step2.body' as TranslationKey, yPct: 58 },
|
|
{ num: '03', titleKey: 'process.step3.title' as TranslationKey, bodyKey: 'process.step3.body' as TranslationKey, yPct: 28 },
|
|
{ num: '04', titleKey: 'process.step4.title' as TranslationKey, bodyKey: 'process.step4.body' as TranslationKey, yPct: 50 },
|
|
];
|
|
---
|
|
<section class="py-24 md:py-32 relative overflow-hidden" style="background: var(--hds-bg-soft);" id="como-trabajamos">
|
|
<div class="absolute inset-0 pointer-events-none" style="background: var(--hds-gradient-section);" aria-hidden="true"></div>
|
|
|
|
<!-- Background photo: team working (very subtle, blurred) -->
|
|
<div class="absolute inset-0 pointer-events-none" aria-hidden="true" style="opacity: 0.35;">
|
|
<img
|
|
src="/images/photos/hands-typing-coffee-1200x800.webp"
|
|
alt=""
|
|
class="w-full h-full object-cover"
|
|
loading="lazy"
|
|
decoding="async"
|
|
onerror="this.style.display='none'"
|
|
/>
|
|
</div>
|
|
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="max-w-3xl mb-16 md:mb-20 reveal">
|
|
<SectionEyebrow text={t('process.eyebrow')} />
|
|
<h2 class="font-display leading-tight mt-5" style="font-size: clamp(2rem, 5vw, 3.5rem); color: var(--hds-fg);">
|
|
{t('process.title')}
|
|
</h2>
|
|
</div>
|
|
|
|
<!-- Desktop: horizontal asymmetric circles -->
|
|
<div class="process-desktop hidden md:block">
|
|
<svg class="process-line-svg" viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true">
|
|
<path
|
|
class="process-line-path"
|
|
d="M 12.5 35 C 22 35, 28 58, 37.5 58 C 47 58, 53 28, 62.5 28 C 72 28, 78 50, 87.5 50"
|
|
fill="none"
|
|
stroke="var(--color-hds-naranja)"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
vector-effect="non-scaling-stroke"
|
|
stroke-dasharray="200"
|
|
stroke-dashoffset="200"
|
|
opacity="0.5"
|
|
/>
|
|
</svg>
|
|
|
|
<div class="process-circles-row">
|
|
{steps.map((step, i) => (
|
|
<div class="process-circle-col" style={`top: ${step.yPct}%;`}>
|
|
<div class="process-circle glass-card" data-step-index={i}>
|
|
<span class="font-display process-circle-num">{step.num}</span>
|
|
</div>
|
|
<div class="process-circle-text">
|
|
<h3 class="text-lg font-semibold mb-1.5" style="color: var(--hds-fg);">
|
|
{t(step.titleKey)}
|
|
</h3>
|
|
<p class="text-sm leading-relaxed" style="color: var(--hds-fg-soft);">
|
|
{t(step.bodyKey)}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile: vertical layout with connecting line -->
|
|
<div class="process-mobile md:hidden">
|
|
<div class="process-mobile-track" aria-hidden="true">
|
|
<div class="process-mobile-line" id="process-mobile-line"></div>
|
|
</div>
|
|
<div class="process-mobile-steps">
|
|
{steps.map((step, i) => (
|
|
<div class="process-mobile-row" data-step-index={i}>
|
|
<div class="process-circle process-circle-mobile glass-card">
|
|
<span class="font-display process-circle-num">{step.num}</span>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h3 class="text-base font-semibold mb-1" style="color: var(--hds-fg);">
|
|
{t(step.titleKey)}
|
|
</h3>
|
|
<p class="text-sm leading-relaxed" style="color: var(--hds-fg-soft);">
|
|
{t(step.bodyKey)}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<script>
|
|
import gsap from 'gsap';
|
|
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
|
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
|
|
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
|
|
if (!prefersReduced) {
|
|
// Desktop: draw SVG line on scroll
|
|
const path = document.querySelector<SVGPathElement>('.process-line-path');
|
|
if (path) {
|
|
const pathLength = path.getTotalLength();
|
|
path.style.strokeDasharray = String(pathLength);
|
|
path.style.strokeDashoffset = String(pathLength);
|
|
|
|
gsap.to(path, {
|
|
scrollTrigger: {
|
|
trigger: '.process-desktop',
|
|
start: 'top 75%',
|
|
end: 'bottom 60%',
|
|
scrub: 0.8,
|
|
},
|
|
strokeDashoffset: 0,
|
|
ease: 'none',
|
|
});
|
|
}
|
|
|
|
// Desktop: scale-in circles with stagger
|
|
gsap.from('.process-circle-col', {
|
|
scrollTrigger: {
|
|
trigger: '.process-desktop',
|
|
start: 'top 70%',
|
|
toggleActions: 'play none none none',
|
|
},
|
|
opacity: 0,
|
|
scale: 0.6,
|
|
duration: 0.6,
|
|
stagger: 0.18,
|
|
ease: 'back.out(1.7)',
|
|
clearProps: 'transform,opacity',
|
|
});
|
|
|
|
// Desktop: subtle floating animation on circles
|
|
document.querySelectorAll<HTMLElement>('.process-circle-col').forEach((el, i) => {
|
|
gsap.to(el, {
|
|
y: '+=12',
|
|
duration: 2.5 + i * 0.4,
|
|
repeat: -1,
|
|
yoyo: true,
|
|
ease: 'sine.inOut',
|
|
delay: i * 0.3,
|
|
});
|
|
});
|
|
|
|
// Mobile: line fill on scroll
|
|
const mobileLine = document.getElementById('process-mobile-line');
|
|
if (mobileLine) {
|
|
gsap.to(mobileLine, {
|
|
scrollTrigger: {
|
|
trigger: '.process-mobile-steps',
|
|
start: 'top 75%',
|
|
end: 'bottom 60%',
|
|
scrub: 0.8,
|
|
},
|
|
scaleY: 1,
|
|
ease: 'none',
|
|
});
|
|
}
|
|
|
|
// Mobile: fade-in rows
|
|
gsap.from('.process-mobile-row', {
|
|
scrollTrigger: {
|
|
trigger: '.process-mobile-steps',
|
|
start: 'top 75%',
|
|
toggleActions: 'play none none none',
|
|
},
|
|
opacity: 0,
|
|
x: -20,
|
|
duration: 0.5,
|
|
stagger: 0.15,
|
|
ease: 'power2.out',
|
|
clearProps: 'transform,opacity',
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
/* Desktop layout */
|
|
.process-desktop {
|
|
position: relative;
|
|
height: 420px;
|
|
}
|
|
|
|
.process-line-svg {
|
|
position: absolute;
|
|
inset: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: 0;
|
|
}
|
|
|
|
.process-circles-row {
|
|
position: relative;
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
height: 100%;
|
|
z-index: 1;
|
|
}
|
|
|
|
.process-circle-col {
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
padding: 0 0.75rem;
|
|
}
|
|
|
|
.process-circle {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 76px;
|
|
height: 76px;
|
|
border-radius: 50%;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.process-circle-num {
|
|
font-size: 1.6rem;
|
|
font-weight: 500;
|
|
color: var(--color-hds-naranja);
|
|
line-height: 1;
|
|
}
|
|
|
|
.process-circle-text {
|
|
margin-top: 1.25rem;
|
|
text-align: center;
|
|
max-width: 200px;
|
|
}
|
|
|
|
/* Mobile layout */
|
|
.process-mobile {
|
|
position: relative;
|
|
padding-left: 2.5rem;
|
|
}
|
|
|
|
.process-mobile-track {
|
|
position: absolute;
|
|
left: 37px;
|
|
top: 38px;
|
|
bottom: 38px;
|
|
width: 2px;
|
|
background: var(--hds-line);
|
|
border-radius: 2px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.process-mobile-line {
|
|
width: 100%;
|
|
height: 100%;
|
|
background: var(--color-hds-naranja);
|
|
transform: scaleY(0);
|
|
transform-origin: top;
|
|
}
|
|
|
|
.process-mobile-steps {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2rem;
|
|
}
|
|
|
|
.process-mobile-row {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.process-circle-mobile {
|
|
width: 56px;
|
|
height: 56px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.process-circle-mobile .process-circle-num {
|
|
font-size: 1.2rem;
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.process-line-path {
|
|
stroke-dashoffset: 0 !important;
|
|
}
|
|
.process-mobile-line {
|
|
transform: scaleY(1) !important;
|
|
}
|
|
}
|
|
</style>
|