Files
PrimeCode/app/page.tsx
2025-08-26 08:42:36 +02:00

1736 lines
71 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { motion, AnimatePresence, useScroll, useTransform, useMotionTemplate, useTime, MotionValue, useSpring } from "framer-motion";
import { useState, useCallback, useEffect } from "react"
import { Palette, Sparkles, Gauge, FlaskConical, TrendingUp, Users, Brain, CheckCircle2, Zap, CircleDot, XCircle } from "lucide-react";
// na górze pliku (masz już useEffect), dodaj:
import { createPortal } from "react-dom";
export default function Home() {
const [openIndex, setOpenIndex] = useState<number | null>(null)
const [activeSection, setActiveSection] = useState<string>("PrimeCode");
const [uiVariant, setUiVariant] = useState<"A" | "B" | "C">("A");
// A = Vibrant, B = Editorial, C = Dark
useEffect(() => {
const sections = document.querySelectorAll("section[id]");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setActiveSection(entry.target.id);
}
});
},
{ rootMargin: "-50% 0px -50% 0px", threshold: 0 }
);
sections.forEach((section) => observer.observe(section));
return () => observer.disconnect();
}, []);
const navItems = [
{ id: "PrimeCode", label: "O nas" },
{ id: "Sytuacje", label: "Sytuacje" },
{ id: "Partner", label: "Potrzebujesz partnera" },
{ id: "Model", label: "Model Prime Code" },
{ id: "CoPotrafimy", label: "Co potrafimy?" },
{ id: "JakDzialamy", label: "Jak działamy?" },
{ id: "PomogliśmyCaseStudies", label: "Pomogliśmy" },
];
const caseStudies = [
{
title: "Firma kosmetyczna",
short: "Nowa strategia detaliczna i transformacja doświadczenia klientek w salonach.",
details: [
"Opracowanie nowej strategii detalicznej, integrującej sprzedaż z usługami.",
"Zaprojektowanie atmosfery sklepów oraz selekcja unikalnego asortymentu.",
"Transformacja komunikacji od eksperckiej wiedzy do relacji opartej na empatii.",
"Redefinicja propozycji wartości skupienie na doświadczeniu troski o zdrowie i piękno.",
"Stworzenie concept storeu jako pełnego doświadczenia marki.",
"Przejście z jednego formatu sklepu na trzy lepiej dopasowane formaty detaliczne.",
"Zmiana podejścia operacyjnego: od 4P do 7P, z naciskiem na doświadczenie klientki."
]
},
{
title: "Firma paliwowa",
short: "Integracja doświadczenia na stacjach z tożsamością marki i branding sensoryczny.",
details: [
"Integracja strategii marki ze strategią doświadczeń klienta.",
"Badania neuromarketingowe i ponad 100 rekomendacji optymalizacyjnych.",
"Wielowarstwowa propozycja wartości od tankowania po rozbudowane doświadczenie marki.",
"Identyfikacja momentów prawdy i plan zarządzania nimi.",
"Mapa ścieżek klienta z instrukcją optymalizacji.",
"Projekt atmosfery stacji (kolorystyka, zapach, układ).",
"Kompleksowy branding sensoryczny angażujący wszystkie zmysły.",
"Standardy obsługi klienta odzwierciedlające wartości marki.",
"Mapa wdrożenia z harmonogramem i wytycznymi operacyjnymi."
]
},
{
title: "Firma technologiczna",
short: "Nowa architektura marki, system kompetencji i kultura klientocentryczna.",
details: [
"Zaprojektowanie struktury organizacyjnej i systemu kompetencji.",
"Redefinicja architektury marki (przejście z house of brands na branded house).",
"System zarządzania wartością klienta poziom strategiczny, operacyjny i personalny.",
"„Playbooki” wdrażające pozycjonowanie do działań codziennych.",
"Usługi o wysokiej wartości dodanej, zmieniające postrzeganie firmy.",
"Model „high tech + high touch” łączący technologie z uważnością na klienta.",
"Strategia CRM wspierająca długofalowe relacje i wzrost."
]
}
]
// --- Wspólna treść dla wszystkich wariantów sekcji "DlaczegoIntegracji" ---
const why = {
p1: (
<>
<strong className="text-cyan-800">76% konsumentów oczekuje</strong>, że marka będzie
<strong className="text-cyan-800"> przewidywać ich potrzeby</strong>, nie tylko reagować
<span className="text-gray-500"> (Salesforce, 2023)</span>.
</>
),
p2: (
<>
Pokolenie Z <strong className="text-cyan-800">nie buduje lojalności przez reklamy</strong>.
Buduje przez <strong className="text-cyan-800">wartość, użyteczność i autentyczność</strong>.
<span className="font-semibold text-gray-800"> 65% młodych konsumentów</span> deklaruje,
że lojalność wobec marki zależy od spójnych i realnych doświadczeń
<span className="text-gray-500"> (McKinsey, 2023)</span>.
</>
),
bulletsIntro: "Marka nie żyje w kampaniach. Żyje w:",
bullets: [
"chatbotach, landingach, mailach i pushach,",
"procesach sprzedażowych i onboardingowych,",
"sposobie, w jaki działa Twój model cenowy, UX i obsługa klienta.",
],
p3: (
<>
Jeśli to wszystko nie gra razem, marka <strong className="text-cyan-800">traci moc</strong>.
<br />
<strong className="text-cyan-800">I traci klientów.</strong>
<span className="text-gray-500"> Według badania PwC 32% klientów</span> porzuca markę po jednej
złej interakcji, nawet jeśli wcześniej byli zadowoleni.
</>
),
};
const [expandedIndex, setExpandedIndex] = useState<number | null>(null);
// === NOWE tiles (podmień całą dotychczasową definicję) ===
// === KAFELKI z jednolitym punktorowaniem ===
const tiles = [
{
title: "Brand Daily Scan™ diagnoza w rytmie codzienności",
short: "Błyskawiczna analiza punktów styku, decyzji, procesów i sygnałów marki.",
output: "Mapa luk, insighty, benchmarki, rekomendacje.",
efekt:
"Mapa luk i niespójności, insighty z rzeczywistego użycia marki, benchmarki branżowe oraz rekomendacje naprawcze i wzmacniające.",
details: (
<>
<p >
Nie patrzymy na markę z dystansu. Wchodzimy w jej codzienne tętno.
Skupiamy się na tym, co naprawdę <strong>generuje doświadczenie klienta</strong>:
</p>
{/* stałe, eleganckie kropki */}
<ul className="mt-1 space-y-1">
<li className="relative pl-4 before:content-[''] before:absolute before:left-0 before:top-[0.55rem] before:w-1.5 before:h-1.5 before:rounded-full before:bg-cyan-600">
punkty styku (touchpointy),
</li>
<li className="relative pl-4 before:content-[''] before:absolute before:left-0 before:top-[0.55rem] before:w-1.5 before:h-1.5 before:rounded-full before:bg-cyan-600">
mikrodecyzje zespołów,
</li>
<li className="relative pl-4 before:content-[''] before:absolute before:left-0 before:top-[0.55rem] before:w-1.5 before:h-1.5 before:rounded-full before:bg-cyan-600">
automatyczne procesy i sygnały marki.
</li>
</ul>
</>
),
},
{
title: "Synchronizacja rytmu faza pacingu",
short: "Zgrywamy Twoje działania z logiką marki. Automatyzujemy. Personalizujemy.",
output: "Roadmapa wdrożenia z KPI i zestawem eksperymentów.",
efekt:
"„Zgrane zegary” marki, marketingu, sprzedaży i obsługi; klarowne KPI oraz szybkie testy hipotez.",
details: (
<>
<p>
Integrujemy markę z codzienną dynamiką operacyjną. Nie robimy rewolucji
<strong> synchronizujemy rytm</strong>:
</p>
{/* stałe, eleganckie kropki */}
<ul className="mt-1 space-y-1">
<li className="relative pl-4 before:content-[''] before:absolute before:left-0 before:top-[0.55rem] before:w-1.5 before:h-1.5 before:rounded-full before:bg-cyan-600">
automatyzujemy to, co można,
</li>
<li className="relative pl-4 before:content-[''] before:absolute before:left-0 before:top-[0.55rem] before:w-1.5 before:h-1.5 before:rounded-full before:bg-cyan-600">
personalizujemy to, co warto,
</li>
<li className="relative pl-4 before:content-[''] before:absolute before:left-0 before:top-[0.55rem] before:w-1.5 before:h-1.5 before:rounded-full before:bg-cyan-600">
urealniamy to, co obiecujesz jako marka.
</li>
</ul>
</>
),
},
{
title: "Wdrożenie i skalowanie",
short: "Marka w akcji: od call center i e-maili po pricing, CRM i fizyczną dostępność.",
output: "Efektywność, zaangażowanie, lojalność.",
efekt:
"Wzrost efektywności działań marketingowych, wyższe zaangażowanie użytkowników, zwiększenie lojalności i retencji — zmierzone.",
details: (
<>
<p >
Marka przestaje być tylko deklaracją. Zaczyna
<strong> działać w realnym czasie i miejscu</strong>:
</p>
{/* stałe, eleganckie kropki */}
<ul className="mt-1 space-y-1">
<li className="relative pl-4 before:content-[''] before:absolute before:left-0 before:top-[0.55rem] before:w-1.5 before:h-1.5 before:rounded-full before:bg-cyan-600">
w aplikacji i e-mailach,
</li>
<li className="relative pl-4 before:content-[''] before:absolute before:left-0 before:top-[0.55rem] before:w-1.5 before:h-1.5 before:rounded-full before:bg-cyan-600">
w polityce cenowej i mechanizmach CRM,
</li>
<li className="relative pl-4 before:content-[''] before:absolute before:left-0 before:top-[0.55rem] before:w-1.5 before:h-1.5 before:rounded-full before:bg-cyan-600">
w sklepie internetowym i na półce w punkcie sprzedaży.
</li>
</ul>
</>
),
},
];
const scrollToIntegration = useCallback(() => {
const section = document.getElementById('DlaczegoIntegracji')
section?.scrollIntoView({ behavior: 'smooth' })
}, [])
return (
<div className="relative isolate min-h-screen text-gray-900 overflow-hidden">
<Background variant={uiVariant} />
{/* Sticky Navbar */}
<nav className="fixed top-0 left-0 w-full z-50 bg-white/70 backdrop-blur-md shadow-sm border-b border-cyan-100">
<div className="max-w-7xl mx-auto px-4 flex justify-between items-center py-4">
<a href="#PrimeCode" className="flex items-center gap-3">
<img src="/LogoPrimeCode-transparent.png" alt="Prime Code" className="h-8 w-auto" />
<span className="sr-only">Prime Code O nas</span>
</a>
<div className="md:hidden">
<input type="checkbox" id="menu-toggle" className="peer hidden" />
<label htmlFor="menu-toggle" className="cursor-pointer">
<svg className="h-8 w-8 text-gray-700" viewBox="0 0 24 24" stroke="currentColor">
<path strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</label>
<ul className="hidden peer-checked:flex absolute top-full left-0 w-full flex-col bg-white shadow-lg">
{navItems.map((item) => (
<li key={item.id}>
<a
href={`#${item.id}`}
className={`block px-4 py-2 transition hover:text-cyan-700 ${activeSection === item.id ? "text-cyan-700 border-l-4 border-cyan-700" : ""
}`}
>
{item.label}
</a>
</li>
))}
</ul>
</div>
<ul className="hidden md:flex gap-8 text-gray-700 font-semibold">
{navItems.map((item) => (
<li key={item.id}>
<a
href={`#${item.id}`}
className={`transition hover:text-cyan-700 ${activeSection === item.id ? "text-cyan-700 border-b-2 border-cyan-700 pb-1" : ""
}`}
>
{item.label}
</a>
</li>
))}
</ul>
</div>
</nav>
{/* HERO - Nowoczesna, elegancka sekcja wprowadzająca */}
<section
id="PrimeCode"
className="relative flex flex-col justify-center items-center min-h-screen px-6 py-16 md:py-24 text-center"
>
{/* Dynamiczne tło
<div className="absolute inset-0">
<div className="absolute -top-40 -left-40 w-96 h-96 bg-cyan-300 opacity-30 rounded-full blur-3xl animate-blob"></div>
<div className="absolute -bottom-40 -right-40 w-[500px] h-[500px] bg-blue-300 opacity-30 rounded-full blur-3xl animate-blob animation-delay-2000"></div>
</div> */}
{/* Główna treść */}
<motion.h1
initial={{ opacity: 0, y: 60 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1 }}
className=" bottom-10 z-10 text-7xl md:text-8xl lg:text-9xl font-extrabold text-cyan-900 drop-shadow-xl"
>
Prime Code
</motion.h1>
<motion.h2
initial={{ opacity: 0, y: 40 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3, duration: 0.8 }}
className="mt-2 z-10 text-3xl md:text-4xl font-semibold text-cyan-700"
>
Integrujemy markę w codziennych działaniach
</motion.h2>
{/* Tagline */}
<motion.p
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5, duration: 0.8 }}
className="mt-4 z-10 text-xl md:text-2xl text-cyan-600"
>
Marka, która działa codziennie. W czasie rzeczywistym. W każdym punkcie styku.
</motion.p>
{/* Dekoracyjna linia */}
<motion.div
initial={{ scaleX: 0 }}
animate={{ scaleX: 1 }}
transition={{ delay: 0.8, duration: 0.6 }}
className="mt-6 mb-6 w-32 h-1.5 rounded-full bg-gradient-to-r from-cyan-400 to-blue-500 origin-left z-10"
/>
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 1.0, duration: 0.8 }}
className="z-10 max-w-3xl text-lg md:text-xl text-gray-700 leading-relaxed"
>
W Prime Code integrujemy markę z tym, co najważniejsze realnymi działaniami, danymi,
technologią i zespołami. Nie tworzymy kampanii dla samej widoczności. Projektujemy
<strong className="font-semibold"> mechanizmy wzrostu</strong>, w których marka staje się fundamentem
operacyjnym: w komunikacji, sprzedaży, doświadczeniu klienta, polityce cenowej i kanałach dystrybucji.
</motion.p>
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 1.2, duration: 0.8 }}
className="mt-4 z-10 max-w-3xl text-lg md:text-xl text-gray-700 leading-relaxed"
>
Bo marka <strong className="font-semibold">to nie tylko opowieść.</strong> To system. Aktywny,
skalowalny, zsynchronizowany z organizacją.
</motion.p>
{/* Strzałka zachęcająca do przewinięcia */}
<motion.div
onClick={scrollToIntegration}
animate={{ y: [0, 15, 0] }}
transition={{ repeat: Infinity, duration: 2, ease: 'easeInOut' }}
className="absolute bottom-8 z-10 text-cyan-700 cursor-pointer"
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-10 w-10"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</motion.div>
</section>
{/* Dlaczego integracja marki to konieczność */}
{uiVariant === "C" ? (
// 👉 wariant C (timeline) w całości
<DlaczegoIntegracji_Timeline why={why} />
) : (
// 👉 warianty A i B zostają bez zmian stylistycznych
<section
id="DlaczegoIntegracji"
className="relative flex flex-col justify-center items-center min-h-screen py-20 overflow-hidden"
>
<div className="relative max-w-5xl mx-auto px-6">
{/* Nagłówek wspólny */}
<motion.h2
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="text-4xl font-bold mb-4 text-center text-cyan-800"
>
Dlaczego integracja marki to konieczność?
</motion.h2>
<div className="mx-auto mb-10 h-1 w-20 bg-cyan-600" />
{/* === A === */}
{uiVariant === "A" && (
<motion.div
initial={{ opacity: 0, scale: 0.98 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
className="bg-white border border-cyan-100 rounded-none p-8 md:p-10 text-gray-800 space-y-6 shadow"
>
{/* Akapit 1 */}
<div className="grid grid-cols-[16px_1fr] gap-3 items-start">
<span className="mt-1 block w-2.5 h-2.5 rounded-full bg-cyan-600 shrink-0" aria-hidden="true" />
<p>{why.p1}</p>
</div>
{/* Akapit 2 */}
<div className="grid grid-cols-[16px_1fr] gap-3 items-start">
<span className="mt-1 block w-2.5 h-2.5 rounded-full bg-cyan-600 shrink-0" aria-hidden="true" />
<p>{why.p2}</p>
</div>
{/* Punkt nadrzędny + podpunkty */}
<div className="grid grid-cols-[16px_1fr] gap-3 items-start">
<span className="mt-1 block w-2.5 h-2.5 rounded-full bg-cyan-600 shrink-0" aria-hidden="true" />
<div>
<p>{why.bulletsIntro}</p>
<ul className="mt-2 space-y-2">
{why.bullets.map((txt, i) => (
<li key={i} className="grid grid-cols-[12px_1fr] gap-3 items-start">
<span className="mt-1 block w-2 h-2 rounded-full bg-cyan-500 shrink-0" aria-hidden="true" />
<span>{txt}</span>
</li>
))}
</ul>
</div>
</div>
{/* Akapit 4 */}
<div className="grid grid-cols-[16px_1fr] gap-3 items-start">
<span className="mt-1 block w-2.5 h-2.5 rounded-full bg-cyan-600 shrink-0" aria-hidden="true" />
<p>{why.p3}</p>
</div>
</motion.div>
)}
{/* === B (Editorial) === */}
{uiVariant === "B" && (
<div className="space-y-6">
{/* Dwa callouty */}
<div className="grid md:grid-cols-2 gap-6">
{[why.p1, why.p2].map((node, i) => (
<motion.article
key={i}
initial={{ opacity: 0, y: 14 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: i * 0.05 }}
className="relative bg-white/90 border border-stone-200 shadow-sm p-6"
>
<span className="absolute left-0 top-0 h-full w-1 bg-cyan-600" aria-hidden="true" />
<p className="text-stone-800">{node}</p>
</motion.article>
))}
</div>
{/* Lewa: „żyje w:”, Prawa: PwC */}
<div className="grid md:grid-cols-2 gap-6">
<motion.article
initial={{ opacity: 0, y: 14 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="bg-white border border-cyan-100 p-6 shadow"
>
<p className="font-medium text-cyan-800">{why.bulletsIntro}</p>
<ul className="mt-3 space-y-2 text-gray-800">
{why.bullets.map((txt, i) => (
<li key={i} className="flex gap-3">
<span className="mt-2 w-2 h-2 rounded-full bg-cyan-500 shrink-0" />
<span>{txt}</span>
</li>
))}
</ul>
</motion.article>
<motion.article
initial={{ opacity: 0, y: 14 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.05 }}
className="bg-gradient-to-br from-cyan-50 to-blue-50 border border-cyan-100 p-6 shadow"
>
<p className="text-gray-800">{why.p3}</p>
</motion.article>
</div>
</div>
)}
</div>
{/* Strzałka do kolejnej sekcji */}
<motion.div
onClick={() => document.getElementById('Sytuacje')?.scrollIntoView({ behavior: 'smooth' })}
animate={{ y: [0, 15, 0] }}
transition={{ repeat: Infinity, duration: 2, ease: 'easeInOut' }}
className="absolute bottom-10 z-10 text-cyan-700 cursor-pointer"
aria-label="Przewiń do sekcji: Czy znasz te sytuacje?"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-10 w-10" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</motion.div>
</section>
)}
{/* Czy znasz te sytuacje? */}
<section id='Sytuacje' className="relative flex flex-col justify-center items-center min-h-screen py-24 overflow-hidden">
<div className="max-w-6xl mx-auto px-6">
{/* Dynamiczne tło */}
{/* <div className="absolute inset-0">
<div className="absolute -top-40 -left-40 w-96 h-96 bg-cyan-300 opacity-20 rounded-full blur-3xl animate-blob"></div>
<div className="absolute -bottom-40 -right-40 w-96 h-96 bg-blue-300 opacity-20 rounded-full blur-3xl animate-blob animation-delay-2000"></div>
</div> */}
<motion.h2
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="text-4xl font-bold mb-14 text-center text-cyan-700 drop-shadow"
>
Czy znasz te sytuacje?
</motion.h2>
<div className="grid md:grid-cols-2 gap-8">
{[
{
title: "1. Brak spójności w komunikacji",
text: "Różne działy (np. marketing, sprzedaż, obsługa klienta) komunikują się w różnym tonie i z odmiennym przekazem."
},
{
title: "2. Realizacja działań promocyjnych bez odniesienia do tożsamości marki",
text: "Firma wdraża modne działania (np. TikTok, influencerzy, AI copywriting) bez filtrowania ich przez tożsamość i wartości marki."
},
{
title: "3. Problemy w skalowaniu działań",
text: "Przy szybkim wzroście lub ekspansji różne zespoły zaczynają prowadzić działania niespójne z tożsamością marki."
},
{
title: "4. Zmiany w zespole / outsourcing marketingu",
text: "Nowe osoby lub agencje marketingowe nie rozumieją w pełni marki i działają według własnych schematów."
},
{
title: "5. Brak narzędzi lub procesów ułatwiających pracę z marką",
text: "Pracownicy nie mają dostępu do aktualnych wytycznych (brand plan, key visuals, archetypy, kroki milowe)."
},
{
title: "6. Brak mierzalnego modelu integracji marki",
text: "Firma nie ma sposobu, by sprawdzić, czy kampania, post czy oferta są zgodne z marką."
}
].map((item, i) => (
<motion.div
key={i}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: i * 0.15, duration: 0.7, ease: 'easeOut' }}
className="p-6 bg-cyan-50/70 backdrop-blur-sm border border-cyan-100 rounded-none shadow hover:shadow-lg transition"
>
<h3 className="text-xl font-semibold text-cyan-700 mb-2">{item.title}</h3>
<p className="text-gray-700">{item.text}</p>
</motion.div>
))}
</div>
</div>
{/* Strzałka do sekcji Partner */}
<motion.div
onClick={() => document.getElementById('Partner')?.scrollIntoView({ behavior: 'smooth' })}
animate={{ y: [0, 15, 0] }}
transition={{ repeat: Infinity, duration: 2, ease: 'easeInOut' }}
className="absolute bottom-10 z-10 text-cyan-700 cursor-pointer"
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-10 w-10"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</motion.div>
</section>
{/* Potrzebujesz partnera, który... */}
<section
id="Partner"
className="relative flex flex-col justify-between items-center min-h-screen py-24 overflow-hidden"
>
{/* Tło dekoracyjne */}
{/* <div className="absolute -top-20 -left-20 w-72 h-72 bg-cyan-200 rounded-full blur-3xl opacity-30 animate-pulse" />
<div className="absolute -bottom-20 -right-20 w-96 h-96 bg-blue-200 rounded-full blur-3xl opacity-30 animate-pulse" /> */}
<div className="relative z-10 max-w-5xl mx-auto px-6 w-full flex-grow flex flex-col justify-center items-center">
<motion.h2
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="text-4xl font-bold mb-12 text-center text-cyan-800 drop-shadow"
>
Potrzebujesz partnera, który:
</motion.h2>
<motion.ul
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.9, ease: 'easeOut' }}
className="space-y-6 text-lg leading-relaxed bg-white/70 backdrop-blur-lg border border-cyan-100 shadow-2xl rounded-none p-10 w-full"
>
{[
"myśli procesami, nie kanałami?",
"łączy branding z danymi, CX i automatyzacją?",
"projektuje mechanizmy wzrostu, a nie tylko „fajny content”?",
"wdraża AI w obsłudze marki, zamiast tylko mówić o trendach?",
"testuje i optymalizuje, zamiast zgadywać?"
].map((item, i) => (
<li key={i} className="flex items-start gap-4">
<span className="w-5 h-5 flex-shrink-0 rounded-full bg-cyan-500 mt-1" />
<span className="text-gray-800">
<strong>{item.split(" ")[0]}</strong> {item.replace(item.split(" ")[0], "")}
</span>
</li>
))}
</motion.ul>
{/* Nowa, wizualna dekoracja bez tekstu */}
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.3, duration: 0.8 }}
className="mt-16 flex justify-center items-center space-x-6"
>
<div className="w-24 h-24 bg-cyan-200 rounded-full blur-2xl animate-blob animation-delay-2000" />
<div className="w-32 h-32 bg-blue-200 rounded-full blur-3xl animate-blob" />
<div className="w-20 h-20 bg-cyan-100 rounded-full blur-xl animate-blob animation-delay-1000" />
</motion.div>
</div>
{/* Animowany napis i strzałka przewijająca do Model */}
<motion.div
onClick={() => document.getElementById('Model')?.scrollIntoView({ behavior: 'smooth' })}
animate={{ y: [0, 10, 0] }}
transition={{ repeat: Infinity, duration: 2, ease: 'easeInOut' }}
className="absolute bottom-10 flex flex-col items-center text-cyan-700 cursor-pointer"
>
<span className="text-lg font-medium mb-2">Spójrz na model Prime Code</span>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-8 w-8"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</motion.div>
</section>
{/* Model Prime Code */}
<motion.section
id="Model"
initial={{ opacity: 0, y: 40 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8, ease: "easeOut" }}
className="relative flex flex-col justify-center items-center min-h-screen pt-12 pb-32 overflow-hidden"
>
{/* Dekoracyjne tło */}
{/* <div className="absolute -top-20 -left-20 w-72 h-72 bg-cyan-200 rounded-full blur-3xl opacity-30 animate-pulse" />
<div className="absolute -bottom-20 -right-20 w-96 h-96 bg-blue-200 rounded-full blur-3xl opacity-30 animate-pulse" /> */}
<div className="relative z-10 max-w-6xl w-full mx-auto px-6 flex-grow flex flex-col justify-center items-center">
<h2 className="-mt-4 text-3xl font-bold mb-4 text-cyan-800 text-center">
Model Prime Code: marka jako system operacyjny
</h2>
<p className="-mt-2 text-gray-700 max-w-3xl mx-auto mb-12 text-center">
W klasycznym ujęciu marka to obietnica. W dzisiejszej rzeczywistości to{' '}
<strong>system działania</strong>. Prime Code traktuje markę jak{' '}
<strong>system operacyjny</strong> firmy: regulujący rytm decyzji,
komunikacji i doświadczeń klienta. Spójność przestaje być tylko
kwestią estetyki a staje się{' '}
<strong>mierzalnym źródłem przewagi</strong>.
</p>
{/* Siatka kafelków bez shared layout na całej siatce */}
<div className="grid md:grid-cols-3 gap-6 lg:gap-8 items-start">
{tiles.map((tile, index) => (
<Tile
key={index}
open={expandedIndex === index}
onOpen={() => setExpandedIndex(index)}
onClose={() => setExpandedIndex(null)}
title={tile.title}
short={tile.short}
output={tile.output}
efekt={tile.efekt}
details={tile.details}
/>
))}
</div>
</div>
{/* Strzałka przewijania do następnej sekcji */}
<motion.div
onClick={() => document.getElementById('CoPotrafimy')?.scrollIntoView({ behavior: 'smooth' })}
animate={{ y: [0, 10, 0] }}
transition={{ repeat: Infinity, duration: 2, ease: 'easeInOut' }}
className="absolute bottom-10 flex flex-col items-center text-cyan-700 cursor-pointer"
>
<span className="text-lg font-medium mb-2">Zobacz Co potrafimy?</span>
<svg xmlns="http://www.w3.org/2000/svg" className="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</motion.div>
</motion.section>
{/* Co potrafimy? */}
<motion.section
id="CoPotrafimy"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="relative flex flex-col justify-center items-center min-h-screen pt-12 pb-32 overflow-hidden"
>
{/* Główna zawartość wyśrodkowana pionowo */}
<div className="max-w-5xl w-full mx-auto px-6 flex-grow flex flex-col justify-center">
<h2 className="text-4xl font-bold mb-14 text-center text-cyan-800 drop-shadow">
Co potrafimy?
</h2>
<motion.ul
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.9, ease: 'easeOut' }}
className="space-y-4 text-lg leading-relaxed bg-white/70 backdrop-blur-lg border border-cyan-100 shadow-2xl rounded-none p-10"
>
{[
"Projektujemy marki, które rosną dzięki danym i doświadczeniu użytkownika",
"Tworzymy systemy komunikacji, a nie tylko tone of voice",
"Zarządzamy marką tak jak innowacyjnym produktem lub usługą: zwinnie, testy, feedback, iteracje",
"Wdrażamy AI w miejscach, które mają znaczenie dla doświadczenia marki",
"Projektujemy onboarding, optymalizujemy punkty styku z klientem i mechanizmy wzrostu",
"Projektujemy szablony i piszemy playbooki dla marketingu, sprzedaży, HR i obsługi klienta z marką w centrum"
].map((item, i) => (
<li key={i} className="flex items-start gap-4">
<span className="w-2.5 h-2.5 mt-2 flex-shrink-0 rounded-full bg-cyan-600"></span>
<span className="text-gray-800">{item}</span>
</li>
))}
</motion.ul>
</div>
{/* Strzałka przewijania do następnej sekcji */}
<motion.div
onClick={() => document.getElementById('JakDzialamy')?.scrollIntoView({ behavior: 'smooth' })}
animate={{ y: [0, 10, 0] }}
transition={{ repeat: Infinity, duration: 2, ease: 'easeInOut' }}
className="absolute bottom-10 flex flex-col items-center text-cyan-700 cursor-pointer"
>
<span className="text-lg font-medium mb-2">Zobacz, jak to działa</span>
<svg xmlns="http://www.w3.org/2000/svg" className="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</motion.div>
</motion.section>
{/* Zobacz, jak to działa bez ryzyka */}
<motion.section
id="JakDzialamy"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="relative flex flex-col justify-center items-center min-h-screen pt-12 pb-32 overflow-hidden"
>
{/* Dekoracje w tle */}
{/* <div className="absolute -top-24 -left-24 w-96 h-96 bg-cyan-200 rounded-full blur-3xl opacity-30 animate-pulse" />
<div className="absolute -bottom-24 -right-24 w-80 h-80 bg-blue-300 rounded-full blur-3xl opacity-30 animate-pulse" /> */}
{/* Główna zawartość */}
<div className="relative z-10 max-w-5xl w-full mx-auto px-6 flex-grow flex flex-col justify-center items-center text-center">
<motion.h2
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="text-4xl font-bold mb-6 text-cyan-800 drop-shadow"
>
Zobacz, jak to działa bez ryzyka
</motion.h2>
<motion.h3
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.2, duration: 0.8 }}
className="text-2xl font-semibold mb-8 text-gray-800"
>
Brand Daily Test
</motion.h3>
<motion.p
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.3, duration: 0.8 }}
className="text-lg text-gray-700 max-w-2xl mb-12"
>
W 7 dni pokażemy Ci realne luki, szanse i jeden test do wdrożenia od ręki.
</motion.p>
<div className="grid md:grid-cols-2 gap-8 w-full">
{[
"mini-audyt doświadczeń i danych",
"mapa punktów styku",
"insighty do poprawy spójności i skuteczności",
"1 eksperyment do wdrożenia natychmiast"
].map((item, i) => (
<motion.div
key={i}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: i * 0.15, duration: 0.6 }}
className="flex items-start gap-4 bg-white/80 backdrop-blur-lg border border-cyan-100 rounded-none shadow-lg p-5 hover:shadow-xl transition h-full"
>
{/* kropka jak w sekcji "Potrzebujesz partnera" */}
<span
className="w-5 h-5 flex-shrink-0 rounded-full bg-cyan-500 mt-1"
aria-hidden="true"
/>
<span className="text-gray-800">{item}</span>
</motion.div>
))}
</div>
<motion.p
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.5, duration: 0.8 }}
className="mt-12 text-lg text-gray-700"
>
<a href='#Kontakt' className="font-semibold underline decoration-cyan-600 underline-offset-4 hover:opacity-80">
Efekty zanim podejmiesz decyzję o dalszej współpracy.
</a>
</motion.p>
</div>
{/* Strzałka przewijania do następnej sekcji
<motion.div
onClick={() => document.getElementById('PomogliśmyCaseStudies')?.scrollIntoView({ behavior: 'smooth' })}
animate={{ y: [0, 10, 0] }}
transition={{ repeat: Infinity, duration: 2, ease: 'easeInOut' }}
className="absolute bottom-10 flex flex-col items-center text-cyan-700 cursor-pointer"
>
<span className="text-lg font-medium mb-2">Zobacz komu pomogliśmy</span>
<svg xmlns="http://www.w3.org/2000/svg" className="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</motion.div> */}
</motion.section>
{/* Połączona sekcja „Pomogliśmy” + „Case Studies” (STATYCZNIE) */}
<motion.section
id="PomogliśmyCaseStudies"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="py-24 relative overflow-visible min-h-screen"
>
<div className="max-w-6xl mx-auto px-6 text-center flex flex-col h-full">
{/* Nagłówek „Pomogliśmy” */}
<h2 className="text-4xl font-bold mb-10 text-cyan-800">
Pomogliśmy
</h2>
{/* LISTA STATYCZNA — zamiast karuzel */}
<div className="space-y-6">
{/* wiersz 1 */}
<div className="grid gap-6 md:grid-cols-2">
{[
"Ponad 20 firmom farmaceutycznym",
"Ponad 20 firmom FMCG",
"Ponad 15 firmom B2B",
"10 firmom technologicznym i startupom",
].map((item, i) => (
<div
key={`row1-${i}`}
className="flex items-start gap-4 p-5 bg-white/85 backdrop-blur-md border border-cyan-100 rounded-none shadow-sm hover:shadow-md transition text-left"
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6 text-cyan-600 flex-shrink-0"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={2}
aria-hidden="true"
>
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
</svg>
<p className="text-gray-800 text-base md:text-lg leading-relaxed text-left">
{item}
</p>
</div>
))}
</div>
{/* wiersz 2 */}
<div className="grid gap-6 md:grid-cols-2">
{[
"4 bankom i 3 firmom ubezpieczeniowym",
"5 instytucjom edukacyjnym",
"Firmom z branży rozrywkowej, modowej, przemysłowej, wydawniczej, rolniczej i wielu innych",
"Globalnym centralom koncernów z USA, Kanady, Niemiec, Wielkiej Brytanii, Hiszpanii, Węgier i Polski",
].map((item, i) => (
<div
key={`row2-${i}`}
className="flex items-start gap-4 p-5 bg-white/85 backdrop-blur-md border border-cyan-100 rounded-none shadow-sm hover:shadow-md transition text-left"
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6 text-cyan-600 flex-shrink-0"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={2}
aria-hidden="true"
>
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
</svg>
<p className="text-gray-800 text-base md:text-lg leading-relaxed text-left">
{item}
</p>
</div>
))}
</div>
</div>
{/* Case Studies — bez zmian, korzysta z Twojego komponentu CaseCard */}
<div className="max-w-6xl mx-auto px-6 mt-16">
<h3 className="text-3xl font-bold mb-10 text-cyan-800">
Case Studies
</h3>
<div className="grid md:grid-cols-3 gap-8 items-start">
{caseStudies.map((study, index) => (
<CaseCard
key={index}
index={index}
openIndex={openIndex}
setOpenIndex={setOpenIndex}
title={study.title}
short={study.short}
details={study.details}
/>
))}
</div>
</div>
</div>
</motion.section>
{/* KONTAKT wyeksponowany baner */}
<section
id="Kontakt"
className="relative w-full bg-gradient-to-r from-cyan-700 via-cyan-600 to-blue-700 text-white py-14 md:py-20"
>
<div className="max-w-6xl mx-auto px-6 grid md:grid-cols-[1.1fr_0.9fr] gap-10 items-center">
{/* Tekst + CTA */}
<div>
<h2 className="text-3xl md:text-4xl font-extrabold tracking-tight">
Zacznij od eksperymentu
</h2>
<p className="mt-3 md:mt-4 text-lg text-cyan-100 max-w-xl">
Zobacz, co marka może zrobić w 7 dni.
</p>
<div className="mt-8 flex flex-col sm:flex-row gap-4">
<a
href="mailto:primecode@primecode.pl"
className="inline-flex items-center justify-center px-6 h-12 bg-white text-cyan-700 font-semibold border border-white hover:opacity-90 transition rounded-none"
aria-label="Napisz maila do Prime Code"
>
{/* mail icon */}
<svg className="w-5 h-5 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
d="M4 4h16v16H4z M22 6l-10 7L2 6" />
</svg>
Napisz maila
</a>
<a
href="tel:+48500133609"
className="inline-flex items-center justify-center px-6 h-12 bg-transparent text-white font-semibold border border-white hover:bg-white/10 transition rounded-none"
aria-label="Zadzwoń do Prime Code"
>
{/* phone icon */}
<svg className="w-5 h-5 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07
19.5 19.5 0 0 1-6-6A19.79 19.79 0 0 1 2.1 4.18
2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.98.36 1.93.69 2.84a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.24-1.26a2 2 0 0 1 2.11-.45c.91.33 1.86.56 2.84.69A2 2 0 0 1 22 16.92z" />
</svg>
Zadzwoń
</a>
</div>
</div>
{/* Karta z osobą kontaktową */}
<div className="bg-white text-gray-800 border border-cyan-100 shadow-xl p-6 md:p-7 rounded-none">
<div className="flex items-center gap-4">
<img
src="/jacek.jpg"
alt="Jacek Pogorzelski Prime Code"
className="w-16 h-16 object-cover rounded-full"
/>
<div>
<a
href="https://jacekpogorzelski.pl"
className="text-lg font-semibold text-cyan-700 underline underline-offset-4"
>
Jacek Pogorzelski
</a>
<p className="text-sm text-gray-600 mt-0.5">Prime Code</p>
</div>
</div>
<div className="mt-5 space-y-2">
<a href="mailto:primecode@primecode.pl" className="flex items-center gap-2 group">
<svg className="w-5 h-5 text-cyan-600" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
d="M4 4h16v16H4z M22 6l-10 7L2 6" />
</svg>
<span className="group-hover:underline">primecode@primecode.pl</span>
</a>
<a href="tel:+48500133609" className="flex items-center gap-2 group">
<svg className="w-5 h-5 text-cyan-600" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07
19.5 19.5 0 0 1-6-6A19.79 19.79 0 0 1 2.1 4.18
2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.98.36 1.93.69 2.84a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.24-1.26a2 2 0 0 1 2.11-.45c.91.33 1.86.56 2.84.69A2 2 0 0 1 22 16.92z" />
</svg>
<span className="group-hover:underline">+48 500 133 609</span>
</a>
</div>
</div>
</div>
</section>
{/* FOOTER prosty i równy */}
<footer className="bg-gradient-to-b from-cyan-100 to-blue-100 border-t border-cyan-200">
<div className="max-w-6xl mx-auto px-6 py-8">
<p className="text-center text-sm text-gray-500">© 2025 Prime Code</p>
</div>
</footer>
{/* Quick contact bar */}
<div
aria-label="Szybki kontakt"
className="fixed z-50 bottom-4 right-4 sm:right-6 flex items-center gap-3 bg-white/90 backdrop-blur-md border border-cyan-100 shadow-lg rounded-full px-3 py-2"
>
<img src="/jacek.jpg" alt="Jacek Pogorzelski" className="w-7 h-7 rounded-full object-cover" />
<a href="mailto:primecode@primecode.pl" className="text-sm text-cyan-700 hover:underline">Email</a>
<span className="text-gray-300"></span>
<a href="tel:+48500133609" className="text-sm text-cyan-700 hover:underline">Zadzwoń</a>
</div>
{/* STYLE SWITCHER pływający panel */}
<StyleSwitcher value={uiVariant} onChange={setUiVariant} />
</div>
)
}
function CaseCard({
index,
openIndex,
setOpenIndex,
title,
short,
details
}: {
index: number
openIndex: number | null
setOpenIndex: (i: number | null) => void
title: string
short: string
details: string[]
}) {
const isOpen = openIndex === index
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
whileHover={{ scale: 1.03 }}
className="bg-white/80 backdrop-blur-lg shadow-xl border border-cyan-100 rounded-none
p-6 flex flex-col justify-between min-h-[220px] max-w-[350px] mx-auto transition-all duration-300"
>
<div>
<h3 className="text-2xl font-semibold text-cyan-700 mb-2">{title}</h3>
<p className="text-gray-700 mb-4">{short}</p>
</div>
<button
onClick={() => setOpenIndex(isOpen ? null : index)}
className="mt-auto text-cyan-600 font-semibold hover:underline flex items-center gap-2 focus:outline-none"
>
{isOpen ? 'Zwiń' : 'Pokaż szczegóły'}
<svg
className={`w-4 h-4 transition-transform ${isOpen ? 'rotate-180' : 'rotate-0'}`}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
<AnimatePresence>
{isOpen && (
<motion.ul
key="expanded"
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
transition={{ duration: 0.3 }}
className="mt-4 list-disc pl-5 text-left text-gray-700 space-y-2 text-sm">
{details.map((d, idx) => (
<li key={idx}>{d}</li>
))}
</motion.ul>
)}
</AnimatePresence>
</motion.div>
)
}
function Tile({
open,
onOpen,
onClose,
title,
short,
output,
efekt,
details,
}: {
open: boolean;
onOpen: () => void;
onClose: () => void;
title: string;
short: string;
output: string;
efekt: string;
details: React.ReactNode;
}) {
return (
<article
className={
"flex flex-col rounded-none border border-cyan-100 bg-white/90 transition-shadow duration-300 " +
(open ? "shadow-xl ring-1 ring-cyan-100" : "shadow")
}
>
{/* Górna, widoczna część równa wysokość przy stanie zamkniętym */}
<div className={`p-6 flex flex-col ${open ? "" : "min-h-[280px]"}`}>
<div className="flex justify-between items-start">
<h3 className="text-xl font-semibold text-cyan-700 mb-2">{title}</h3>
</div>
<p className="text-gray-700 mb-2 leading-relaxed text-justify">{short}</p>
<p className="text-sm text-gray-700 leading-[1.65]">
<span className="font-semibold text-cyan-800">Output:</span> {output}
</p>
{!open && (
<div className="mt-auto pt-4 border-t border-cyan-100">
<button
type="button"
onClick={onOpen}
aria-expanded={open}
className="text-cyan-600 font-semibold hover:underline cursor-pointer"
>
Zobacz więcej
</button>
</div>
)}
</div>
{/* Rozwijana część animujemy tylko wysokość tej sekcji */}
<motion.div
initial={false}
animate={open ? { height: "auto", opacity: 1 } : { height: 0, opacity: 0 }}
transition={{ duration: 0.35, ease: [0.22, 1, 0.36, 1] }}
style={{ overflow: "hidden", willChange: "height", position: "relative", top: "-10px" }}
>
<div className="px-6 pt-0 pb-6 text-sm text-gray-700">
{/* typografia: ten sam line-height i marginesy */}
<div className="text-justify hyphens-auto leading-[1.65] [&>p]:mb-2 [&_ul]:my-2 [&_li]:leading-[1.65]">
{details}
<p className="mt-2">
<span className="font-semibold text-cyan-800">Efekt:</span> {efekt}
</p>
</div>
<div className="mt-4 pt-4 border-t border-cyan-100">
<button
type="button"
onClick={onClose}
className="text-cyan-600 font-semibold hover:underline cursor-pointer"
>
Zwiń
</button>
</div>
</div>
</motion.div>
</article>
);
}
// KOMPONENT PRZEŁĄCZNIKA (wrzuć pod innymi komponentami w tym pliku)
function StyleSwitcher({
value,
onChange,
}: {
value: "A" | "B" | "C";
onChange: (v: "A" | "B" | "C") => void;
}) {
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return null;
return createPortal(
<div className="fixed bottom-24 right-4 sm:right-6 z-[9999] pointer-events-auto">
<div className="bg-white/95 backdrop-blur-md border border-cyan-100 shadow-xl rounded-xl px-3 py-2">
<div className="flex items-center gap-2">
<Palette className="w-4 h-4 text-cyan-700" />
<span className="text-[11px] uppercase tracking-wide text-gray-600">Wariant</span>
</div>
<div className="mt-2 grid grid-cols-3 gap-2">
{(["A", "B", "C"] as const).map((v) => (
<button
key={v}
onClick={() => onChange(v)}
className={[
"px-3 py-1.5 rounded-md text-xs font-semibold ring-1 transition",
value === v
? "bg-cyan-600 text-white ring-cyan-600"
: "bg-white text-gray-700 ring-gray-300 hover:bg-gray-50",
].join(" ")}
aria-pressed={value === v}
>
{v}
</button>
))}
</div>
</div>
</div>,
document.body
);
}
function DotList({ items, className = "" }: { items: string[]; className?: string }) {
return (
<ul className={["mt-3 space-y-2", className].join(" ")}>
{items.map((txt, i) => (
<li key={i} className="grid grid-cols-[12px_1fr] gap-3 items-start">
{/* ta sama turkusowa kropka co w innych wypunktowaniach */}
<span
aria-hidden="true"
className="mt-[0.35rem] block w-2 h-2 rounded-full bg-cyan-600"
/>
<span className="text-gray-800">{txt}</span>
</li>
))}
</ul>
);
}
function DlaczegoIntegracji_Timeline({
why,
}: {
why: {
p1: React.ReactNode;
p2: React.ReactNode;
bulletsIntro: string;
bullets: string[];
p3: React.ReactNode;
};
}) {
return (
<section
id="DlaczegoIntegracji"
className="relative flex flex-col justify-center items-center min-h-screen py-20 overflow-hidden"
>
<div className="relative max-w-6xl mx-auto px-6 w-full">
{/* Nagłówek */}
<motion.h2
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="text-4xl font-bold mb-4 text-center text-cyan-800"
>
Dlaczego integracja marki to konieczność?
</motion.h2>
<div className="mx-auto mb-10 h-1 w-20 bg-cyan-600" />
{/* Oś czasu */}
<div className="relative">
{/* pionowa linia */}
<div
aria-hidden="true"
className="hidden md:block absolute left-1/2 top-0 -translate-x-1/2 w-px h-full bg-gradient-to-b from-cyan-200 via-cyan-200/70 to-blue-200"
/>
{/* 01 (lewa) */}
<div className="md:grid md:grid-cols-[1fr_56px_1fr] md:items-center md:gap-8 mb-10">
<motion.div
initial={{ opacity: 0, x: -24 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="bg-white/85 backdrop-blur-md border border-cyan-100 shadow-md rounded-xl p-6 ring-1 ring-white/40"
>
<p className="text-gray-800">{why.p1}</p>
</motion.div>
<div className="hidden md:flex items-center justify-center">
<div className="relative w-14 h-14">
<div className="absolute inset-0 rounded-full bg-white shadow border border-cyan-100" />
<div className="absolute inset-1 rounded-full bg-gradient-to-b from-cyan-50 to-blue-50" />
<div className="relative w-14 h-14 flex items-center justify-center font-bold text-cyan-700">01</div>
</div>
</div>
<div className="md:block hidden" />
</div>
{/* 02 (prawa) */}
<div className="md:grid md:grid-cols-[1fr_56px_1fr] md:items-center md:gap-8 mb-10">
<div className="md:block hidden" />
<div className="hidden md:flex items-center justify-center">
<div className="relative w-14 h-14">
<div className="absolute inset-0 rounded-full bg-white shadow border border-cyan-100" />
<div className="absolute inset-1 rounded-full bg-gradient-to-b from-cyan-50 to-blue-50" />
<div className="relative w-14 h-14 flex items-center justify-center font-bold text-cyan-700">02</div>
</div>
</div>
<motion.div
initial={{ opacity: 0, x: 24 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="bg-white/85 backdrop-blur-md border border-cyan-100 shadow-md rounded-xl p-6 ring-1 ring-white/40"
>
<p className="text-gray-800">{why.p2}</p>
</motion.div>
</div>
{/* 03 (lewa) chipy */}
<div className="md:grid md:grid-cols-[1fr_56px_1fr] md:items-center md:gap-8 mb-10">
<motion.div
initial={{ opacity: 0, x: -24 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="bg-white/85 backdrop-blur-md border border-cyan-100 shadow-md rounded-xl p-6 ring-1 ring-white/40"
>
<p className="text-gray-800 mb-3">
<strong className="text-cyan-800">{why.bulletsIntro}</strong>
</p>
<DotList items={[
"chatbotach, landingach, mailach i pushach,",
"procesach sprzedażowych i onboardingowych,",
"sposobie, w jaki działa Twój model cenowy, UX i obsługa klienta.",
]} />
</motion.div>
<div className="hidden md:flex items-center justify-center">
<div className="relative w-14 h-14">
<div className="absolute inset-0 rounded-full bg-white shadow border border-cyan-100" />
<div className="absolute inset-1 rounded-full bg-gradient-to-b from-cyan-50 to-blue-50" />
<div className="relative w-14 h-14 flex items-center justify-center font-bold text-cyan-700">03</div>
</div>
</div>
<div className="md:block hidden" />
</div>
{/* 04 (prawa) callout */}
<div className="md:grid md:grid-cols-[1fr_56px_1fr] md:items-center md:gap-8">
<div className="md:block hidden" />
<div className="hidden md:flex items-center justify-center">
<div className="relative w-14 h-14">
<div className="absolute inset-0 rounded-full bg-white shadow border border-cyan-100" />
<div className="absolute inset-1 rounded-full bg-gradient-to-b from-cyan-50 to-blue-50" />
<div className="relative w-14 h-14 flex items-center justify-center font-bold text-cyan-700">04</div>
</div>
</div>
<motion.div
initial={{ opacity: 0, x: 24 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="rounded-xl p-6 bg-gradient-to-br from-white/90 to-cyan-50/70 border border-cyan-100 shadow-md"
>
<p className="text-gray-800">{why.p3}</p>
</motion.div>
</div>
</div>
</div>
{/* Strzałka do kolejnej sekcji */}
<motion.div
onClick={() => document.getElementById('Sytuacje')?.scrollIntoView({ behavior: 'smooth' })}
animate={{ y: [0, 15, 0] }}
transition={{ repeat: Infinity, duration: 2, ease: 'easeInOut' }}
className="absolute bottom-10 z-10 text-cyan-700 cursor-pointer"
aria-label="Przewiń do sekcji: Czy znasz te sytuacje?"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-10 w-10" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</motion.div>
</section>
);
}
function Background({ variant }: { variant: "A" | "B" | "C" }) {
const [reduce, setReduce] = useState(false);
useEffect(() => {
setReduce(window.matchMedia("(prefers-reduced-motion: reduce)").matches);
}, []);
return (
<div className="fixed inset-0 -z-10 overflow-hidden pointer-events-none">
{/* WARSTWA BAZOWA jak na początku strony */}
<div className="absolute inset-0 bg-gradient-to-br from-cyan-50 via-white to-blue-100" />
{/* === A — Aurora (oryginalna kolorystyka) === */}
{variant === "A" && (
<>
<motion.div
aria-hidden
className="absolute -top-20 -left-40 w-[900px] h-[900px] rounded-full blur-3xl
bg-gradient-to-tr from-cyan-200 via-blue-200 to-blue-300 opacity-30"
animate={
reduce ? {} : { x: [-10, 20, -10], y: [0, 20, 0], scale: [1, 1.05, 1] }
}
transition={{ duration: 20, repeat: Infinity, ease: "easeInOut" }}
/>
<motion.div
aria-hidden
className="absolute -bottom-32 -right-32 w-[900px] h-[900px] rounded-full blur-3xl
bg-gradient-to-tr from-blue-200 via-cyan-100 to-blue-300 opacity-25"
animate={
reduce ? {} : { x: [10, -20, 10], y: [0, -15, 0], scale: [1, 1.07, 1] }
}
transition={{ duration: 22, repeat: Infinity, ease: "easeInOut" }}
/>
<motion.div
aria-hidden
className="absolute top-[45%] left-1/2 -translate-x-1/2 w-[520px] h-[520px] rounded-full blur-2xl
bg-gradient-to-tr from-cyan-100 via-blue-100 to-blue-200 opacity-20"
animate={reduce ? {} : { scale: [1, 1.08, 1] }}
transition={{ duration: 24, repeat: Infinity, ease: "easeInOut" }}
/>
</>
)}
{/* === B — Editorial (pasy + shine) === */}
{variant === "B" && (
<>
<div
aria-hidden
className="absolute inset-0"
style={{
background:
"radial-gradient(1200px 600px at 50% -200px, rgba(59,130,246,.08), transparent 60%)",
}}
/>
<div
aria-hidden
className="absolute inset-0 opacity-[0.06]"
style={{
backgroundImage:
"repeating-linear-gradient(135deg, rgba(14,165,233,.14) 0, rgba(14,165,233,.14) 1px, transparent 1px, transparent 14px)",
}}
/>
{!reduce && (
<motion.div
aria-hidden
className="absolute inset-y-0 -left-1/3 w-1/3 bg-gradient-to-r from-transparent via-white/35 to-transparent"
animate={{ x: ["-120%", "120%"] }}
transition={{ duration: 22, repeat: Infinity, ease: "linear" }}
/>
)}
</>
)}
{/* === C — Kinetic Grid + SCROLL-REACTIVE AURORA === */}
{variant === "C" && (
<>
<ScrollToneBackground />
<ScrollToneDecor reduce={reduce} />
</>
)}
{/* Ziarno (delikatne) */}
<div
aria-hidden
className="absolute inset-0 opacity-[0.04]"
style={{
backgroundImage: "url('/textures/noise.png')",
backgroundSize: "200px 200px",
}}
/>
</div>
);
}
type ToneOpts = { wobbleSpeed?: number; wobbleAmpDeg?: number };
// PASTELOWE, JESZCZE JAŚNIEJSZE ODCIENIE
// start: bardzo jasny błękit, end: bardzo jasny morelowy
const START = { h: 208, s: 78, l: 96 }; // hsl(208 78% 96%)
const END = { h: 24 + 360, s: 82, l: 94 }; // 24° + 360° => unikamy zieleni
function useBrandTone({ wobbleSpeed = 0.001, wobbleAmpDeg = 0.2 }: ToneOpts = {}) {
const { scrollYProgress } = useScroll();
const time = useTime() as MotionValue<number>;
// SINGLE SWEEP: 0 -> 1 tylko raz
const phase = useSpring(scrollYProgress, { stiffness: 35, damping: 22, mass: 0.9 });
// H, S, L płynnie z START -> END (hue idzie po zegarze 208 -> 384)
const hBase = useTransform(phase, [0, 1], [START.h, END.h]);
const sBase = useTransform(phase, [0, 1], [START.s, END.s]);
const lBase = useTransform(phase, [0, 1], [START.l, END.l]);
// Bardzo subtelny „oddech” hue, żeby tło żyło, ale bez mrygania
const wobbleRaw = useTransform(time, t => Math.sin(t * wobbleSpeed * 1000) * wobbleAmpDeg);
const wobble = useSpring(wobbleRaw, { stiffness: 60, damping: 20 });
// top = baza + leciutki wobble (ułamki stopnia)
const hTop = useTransform([hBase, wobble] as MotionValue<number>[], (vals: number[]) => {
const [h, w] = vals as [number, number];
return h + w; // hue może przekraczać 360° CSS to normalizuje
});
const sTop = sBase;
const lTop = lBase;
// dolna warstwa: odrobinkę mniej nasycona i ciut ciemniejsza (wciąż pastel)
const hBot = useTransform(hTop, v => v - 4);
const sBot = useTransform(sTop, v => Math.max(65, v - 8));
const lBot = useTransform(lTop, v => Math.max(88, v - 4));
// dwa środki zawsze kilka odcieni, ale „kolor przewodni” zmienia się tylko raz
const mix2 = (a: MotionValue<number>, b: MotionValue<number>, wa: number) =>
useTransform([a, b] as MotionValue<number>[], (vals: number[]) => {
const [x, y] = vals as [number, number];
return x * wa + y * (1 - wa);
});
const hMid1 = mix2(hTop, hBot, 0.65);
const sMid1 = mix2(sTop, sBot, 0.65);
const lMid1 = mix2(lTop, lBot, 0.65);
const hMid2 = useTransform([hTop, hBot, wobble] as MotionValue<number>[], (vals: number[]) => {
const [a, b, w] = vals as [number, number, number];
return a * 0.35 + b * 0.65 + w * 0.15;
});
const sMid2 = mix2(sTop, sBot, 0.35);
const lMid2 = mix2(lTop, lBot, 0.35);
// kolory jako CSS-zmienne (bez migotania)
const c1 = useMotionTemplate`hsl(${hTop} ${sTop}% ${lTop}%)`;
const c2 = useMotionTemplate`hsl(${hMid1} ${sMid1}% ${lMid1}%)`;
const c3 = useMotionTemplate`hsl(${hMid2} ${sMid2}% ${lMid2}%)`;
const c4 = useMotionTemplate`hsl(${hBot} ${sBot}% ${lBot}%)`;
const accent = useMotionTemplate`hsl(${hBot} ${sBot}% calc(${lBot} - 10%))`;
const accentSoft = useMotionTemplate`hsl(${hBot} ${sBot}% calc(${lBot} - 10%) / .45)`;
const gridTint = useMotionTemplate`hsl(${hTop} ${sTop}% 46% / .16)`;
// ⬇⬇⬇ DODAJ scrollYProgress do return
return { scrollYProgress, c1, c2, c3, c4, accent, accentSoft, gridTint };
}
function ScrollToneBackground() {
const { c1, c2, c3, c4 } = useBrandTone();
return (
<motion.div
aria-hidden
className="absolute inset-0 z-[1] pointer-events-none"
style={
{
["--c1" as any]: c1,
["--c2" as any]: c2,
["--c3" as any]: c3,
["--c4" as any]: c4,
background:
"linear-gradient(180deg, var(--c1) 0%, var(--c2) 45%, var(--c3) 75%, var(--c4) 100%)",
transform: "translateZ(0)",
contain: "paint",
} as React.CSSProperties
}
/>
);
}
function ScrollToneDecor({ reduce = false }: { reduce?: boolean }) {
const { scrollYProgress, accent, accentSoft, gridTint } = useBrandTone();
const time = useTime() as MotionValue<number>;
const x1 = useTransform(scrollYProgress, [0, 1], [15, 70]);
const y1 = useTransform(scrollYProgress, [0, 1], [18, 34]);
const x2 = useTransform(scrollYProgress, [0, 1], [85, 28]);
const y2 = useTransform(scrollYProgress, [0, 1], [78, 62]);
const wobRaw = useTransform(time, t => Math.sin(t * 0.0016) * 4);
const wob = useSpring(wobRaw, { stiffness: 60, damping: 18 });
const orb1 = useMotionTemplate`
radial-gradient(880px 880px at calc(${x1}% + ${wob}) ${y1}%,
${accentSoft}, transparent 60%)`;
const orb2 = useMotionTemplate`
radial-gradient(1040px 1040px at ${x2}% calc(${y2}% + ${wob}),
${accentSoft}, transparent 58%)`;
const shineX = useSpring(
useTransform(scrollYProgress, [0, 1], ["-130%", "130%"]),
{ stiffness: 60, damping: 20 }
);
const shineBg = useMotionTemplate`linear-gradient(90deg, transparent, ${accentSoft}, transparent)`;
const spin = useTransform(time, t => (t * 0.012) % 360);
const rings = useMotionTemplate`
conic-gradient(from 0deg,
transparent 0deg, ${accentSoft} 24deg, transparent 48deg,
${accentSoft} 72deg, transparent 96deg, ${accentSoft} 120deg, transparent 360deg)`;
const gridImg = useMotionTemplate`
repeating-linear-gradient(0deg, transparent, transparent 23px, ${gridTint} 24px),
repeating-linear-gradient(90deg, transparent, transparent 23px, ${gridTint} 24px)`;
return (
<>
<motion.div aria-hidden className="absolute inset-0 z-[2] pointer-events-none" style={{ backgroundImage: orb1 }} />
<motion.div aria-hidden className="absolute inset-0 z-[2] pointer-events-none" style={{ backgroundImage: orb2 }} />
{!reduce && (
<motion.div
aria-hidden
className="absolute top-0 bottom-0 -left-1/3 w-1/3 z-[3] pointer-events-none"
style={{ x: shineX, background: shineBg, opacity: 0.5 }}
/>
)}
<motion.div aria-hidden className="absolute inset-0 z-[2] pointer-events-none" style={{ background: rings, opacity: 0.08, rotate: spin }} />
<motion.div aria-hidden className="absolute inset-0 z-[2] opacity-[0.09] pointer-events-none" style={{ backgroundImage: gridImg }} />
</>
);
}