// Services — Premium interactive showcase. Replaces boring 3-col card grid.
// Design: large feature card on the left locked to the currently-hovered service,
// with a vertical list of services on the right. Hover/click a service — the big card
// morphs to show that service's content with:
// - huge outlined number that fades in
// - animated metric counter (ticks up)
// - service-specific mini visualization
// - gold gradient sweep
const { useState: useSvcState, useEffect: useSvcEffect } = React;
function Services({ lang }) {
const t = (de, pl) => lang === 'de' ? de : pl;
const services = [
{
n: '01',
title: t('Social Media Content', 'Treści Social Media'),
d: t('Reels, TikToks und Shorts — professionell produziert für maximale Reichweite.', 'Reels, TikToki i Shorty — profesjonalnie produkowane dla maksymalnego zasięgu.'),
metric: { value: 347, suffix: '%', label: t('Durchschnittliche Reichweitensteigerung', 'Średni wzrost zasięgu') },
viz: 'content',
tags: [t('Kurzvideo', 'Krótkie wideo'), 'Reels', 'TikTok', 'Shorts', t('Scripting', 'Skrypty')]
},
{
n: '02',
title: t('AI Automationen', 'Automatyzacje AI'),
d: t('Wiederkehrende Prozesse automatisieren. Mehr Zeit für das, was zählt.', 'Automatyzujemy powtarzalne procesy. Więcej czasu na to, co ważne.'),
metric: { value: 28, suffix: 'h', label: t('Gesparte Arbeitsstunden pro Woche', 'Zaoszczędzonych godzin tygodniowo') },
viz: 'automation',
tags: ['n8n', 'Make', 'Zapier', 'OpenAI', 'Claude', 'CRM']
},
{
n: '03',
title: t('Content Strategie', 'Strategia Treści'),
d: t('Maßgeschneiderte Content-Pläne, die deine Marke nach vorne bringen.', 'Spersonalizowane plany treści, które rozwijają Twoją markę.'),
metric: { value: 90, suffix: t(' Tage', ' dni'), label: t('Vollständiger Content-Fahrplan', 'Pełny plan treści') },
viz: 'strategy',
tags: [t('Recherche', 'Badania'), 'Positioning', 'Hooks', 'Pillars', 'Calendar']
},
{
n: '04',
title: t('Lead Generation', 'Generowanie Leadów'),
d: t('Qualifizierte Anfragen direkt in dein Postfach — planbar und skalierbar.', 'Wykwalifikowane zapytania prosto do Twojej skrzynki — skalowalne.'),
metric: { value: 12, suffix: 'x', label: t('ROI im ersten Quartal', 'ROI w pierwszym kwartale') },
viz: 'leads',
tags: ['Meta Ads', 'TikTok Ads', 'Funnels', 'Landing', 'CRM Sync']
},
{
n: '05',
title: t('Business Optimization', 'Optymalizacja Biznesu'),
d: t('Prozesse analysieren, Engpässe lösen, Effizienz steigern.', 'Analizujemy procesy, usuwamy wąskie gardła, zwiększamy wydajność.'),
metric: { value: 40, suffix: '%', label: t('Effizienzsteigerung im Schnitt', 'Średni wzrost wydajności') },
viz: 'optimization',
tags: [t('Audit', 'Audyt'), 'Workflow', 'Tools', 'SOPs', 'KPI']
},
{
n: '06',
title: t('Branding & Design', 'Branding i Design'),
d: t('Einheitliches Erscheinungsbild, das Vertrauen schafft und verkauft.', 'Spójny wizerunek, który buduje zaufanie i sprzedaje.'),
metric: { value: 3.2, suffix: 'x', decimals: 1, label: t('Höhere Conversion durch starke Marke', 'Wyższa konwersja dzięki silnej marce') },
viz: 'branding',
tags: ['Logo', t('Farbwelt', 'Paleta'), 'Typography', 'Guidelines', 'Assets']
}
];
const [active, setActive] = useSvcState(0);
const current = services[active];
const isMobile = window.useIsMobile ? window.useIsMobile() : false;
const scrollerRef = React.useRef(null);
// Sync active index from horizontal scroll position (mobile only)
React.useEffect(() => {
if (!isMobile) return;
const el = scrollerRef.current;
if (!el) return;
let raf;
const onScroll = () => {
if (raf) return;
raf = requestAnimationFrame(() => {
raf = null;
const cardW = el.clientWidth;
const idx = Math.round(el.scrollLeft / cardW);
setActive(prev => (prev !== idx && idx >= 0 && idx < services.length) ? idx : prev);
});
};
el.addEventListener('scroll', onScroll, { passive: true });
return () => { el.removeEventListener('scroll', onScroll); if (raf) cancelAnimationFrame(raf); };
}, [isMobile, services.length]);
const scrollToCard = (i) => {
const el = scrollerRef.current;
if (!el) return;
el.scrollTo({ left: i * el.clientWidth, behavior: 'smooth' });
};
return (
{/* Ambient gold glow — static, GPU-cheap */}
{/* Header with running ticker */}
{t('Leistungen', 'Usługi')}
/ {String(active + 1).padStart(2, '0')}—{String(services.length).padStart(2, '0')}
{t('Alles, was dein Business', 'Wszystko, czego potrzebuje')}
{t('zum ', 'Twój biznes, aby ')}
{t('Wachsen', 'rosnąć')}
{t(' braucht.', '.')}
{t('Alle Dienste live', 'Wszystkie usługi aktywne')}
{/* MOBILE: horizontal snap-carousel — each service is a self-contained card */}
{isMobile && (
{/* Pagination dots */}
{services.map((s, i) => (
{/* Snap scroller */}
{services.map((s, i) => (
{/* Animated rim */}
{/* Outlined number watermark */}
{s.n}
{/* Viz */}
{/* Metric */}
{t('Im Schnitt', 'Średnio')}
{i === active ? (
) : (
{(s.metric.value).toFixed(s.metric.decimals || 0)}
)}
{s.metric.suffix}
{s.metric.label}
{/* Content */}
{s.n} / {t('Leistung', 'Usługa')}
{s.title}
{s.d}
{s.tags.map(tag => (
{tag}
))}
))}
{/* Swipe hint */}
{t('Wischen', 'Przesuń')}
)}
{/* DESKTOP: 2-col feature panel + service list (unchanged) */}
{!isMobile && (
{/* LEFT: big cinematic feature card */}
{/* Animated gradient rim */}
{/* Huge outlined number */}
{current.n}
{/* Service viz */}
{/* Content */}
{current.n} / {t('Leistung', 'Usługa')}
{current.title}
{current.d}
{/* Tags */}
{current.tags.map((tag, i) => (
{tag}
))}
{/* RIGHT: service list with live metric */}
{/* Metric readout */}
{t('Im Schnitt erreichen wir', 'Średnio osiągamy')}
{current.metric.suffix}
{current.metric.label}
{/* Service list */}
{services.map((s, i) => {
const isActive = i === active;
return (
);
})}
)}
);
}
// Animated counter: ticks up to target
function MetricCounter({ target, decimals = 0, size = 72 }) {
const [val, setVal] = useSvcState(0);
useSvcEffect(() => {
const start = performance.now();
const dur = 800;
let raf;
const tick = (t) => {
const p = Math.min(1, (t - start) / dur);
const eased = 1 - Math.pow(1 - p, 3);
setVal(target * eased);
if (p < 1) raf = requestAnimationFrame(tick);
};
raf = requestAnimationFrame(tick);
return () => cancelAnimationFrame(raf);
}, [target]);
return (
{val.toFixed(decimals)}
);
}
// Phone-trio with real videos, IntersectionObserver entrance + hover focus
function PhoneTrio() {
const [hovered, setHovered] = React.useState(null);
const [entered, setEntered] = React.useState(false);
const phoneRef = React.useRef(null);
const isMobile = (typeof window !== 'undefined' && window.useIsMobile) ? window.useIsMobile() : false;
React.useEffect(() => {
if (!phoneRef.current) return;
const obs = new IntersectionObserver(([e]) => {
if (e.isIntersecting) { setEntered(true); obs.disconnect(); }
}, { threshold: 0.2 });
obs.observe(phoneRef.current);
return () => obs.disconnect();
}, []);
const phoneVideos = [
{ src: 'assets/phone-1-lambo.mp4', poster: 'assets/phone-1-lambo.jpg', likes: '124K' },
{ src: 'assets/phone-2-saaler.mp4', poster: 'assets/phone-2-saaler.jpg', likes: '892K' },
{ src: 'assets/phone-3-speedramp.mp4', poster: 'assets/phone-3-speedramp.jpg', likes: '2.4M' },
];
const phoneW = isMobile ? 100 : 150;
const phoneH = isMobile ? 178 : 266;
const fontSize = isMobile ? 9 : 11;
return (
{phoneVideos.map((v, i) => {
const baseRot = -6 + i*4;
const isHovered = hovered === i;
const isOther = hovered !== null && hovered !== i;
return (
setHovered(i)}
onMouseLeave={() => setHovered(null)}
style={{
position: 'absolute',
left: `${4 + i*30}%`, top: `${2 + i*9}%`,
width: phoneW, height: phoneH,
borderRadius: 18,
overflow: 'hidden',
background: '#0A0A0A',
border: '2px solid rgba(212,175,55,.35)',
'--phone-rot': `${baseRot}deg`,
transform: `rotate(${isHovered ? 0 : baseRot}deg) scale(${isHovered ? 1.1 : isOther ? 0.94 : 1})`,
opacity: !entered ? 0 : isOther ? 0.5 : 1,
zIndex: isHovered ? 10 : 1,
animation: entered
? `phoneTrioEntrance .9s cubic-bezier(.16,1,.3,1) ${i*200}ms both, phoneTrioFloat 4s ease-in-out ${i*1300 + 1100}ms infinite, phoneTrioRim 3.5s ease-in-out ${i*800}ms infinite`
: 'none',
transition: 'transform .45s cubic-bezier(.16,1,.3,1), opacity .35s ease',
cursor: 'pointer',
willChange: 'transform, opacity',
}}
>
);
})}
);
}
// Per-service visualization — distinct for each
function ServiceViz({ kind }) {
const base = { width: '100%', maxWidth: 480, height: 240, position: 'relative' };
if (kind === 'content') {
return (
);
}
if (kind === 'automation') {
// Flowing nodes connected by animated lines
return (
);
}
if (kind === 'strategy') {
// Calendar grid of 90 days, some highlighted
return (
{[...Array(90)].map((_,i) => {
const active = [3,4,8,12,13,18,23,27,28,32,37,41,42,47,52,56,57,61,66,70,71,75,80,84,85,88].includes(i);
return (
);
})}
);
}
if (kind === 'leads') {
// Funnel with qualified leads dropping into inbox
return (
);
}
if (kind === 'optimization') {
// Before/after bar chart
return (
{[[30,'Vorher','Przed'],[52,'Vorher','Przed'],[38,'Vorher','Przed'],[60,'Vorher','Przed']].map(([h, de],i)=>(
))}
);
}
if (kind === 'branding') {
// Color swatches + logo mark
return (
JK
{['#D4AF37','#0a0a0a','#ffffff','#1a1a1a'].map(c => (
))}
);
}
return null;
}
window.Services = Services;