// 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 ( {[[80,80],[200,60],[320,100],[400,180],[240,180]].map(([x,y],i) => ( ))} {[[80,80,200,60],[200,60,320,100],[320,100,400,180],[200,60,240,180],[240,180,320,100]].map(([x1,y1,x2,y2],i) => ( ))} ); } 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 ( {[50,110,170,230,290,350].map((x, i) => ( ))} INBOX ); } 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 => (
{c.toUpperCase()}
))}
); } return null; } window.Services = Services;