Blog O nas Kontakt
SEO Pensatore

SEO techniczne strony internetowej — najważniejsze elementy (Olsztynek)

Wiele firm w Olsztynku traci potencjalnych klientów przez niedopracowaną technicznie stronę. Dowiedz się, dlaczego optymalizacja strony jest fundamentem sukcesu online i jak poprawić widoczność w wyszukiwarkach, by przyciągnąć więcej lokalnych odbiorców.

Wiele lokalnych firm w Olsztynku inwestuje w estetyczną stronę internetową, poświęcając czas i środki na jej wygląd, galerię czy opisy usług. Często jednak zapominają o fundamencie — technicznym SEO. Strona może prezentować się znakomicie, ale jeśli roboty wyszukiwarek mają problem z jej odczytaniem, zaindeksowaniem lub oceniają ją jako wolną i niezoptymalizowaną pod urządzenia mobilne, to nawet najpiękniejszy design nie przyciągnie nowych klientów. To błąd, który kosztuje widoczność w wynikach wyszukiwania i sprawia, że potencjalni odbiorcy z Olsztynka trafiają do konkurencji, która zadbała o techniczne aspekty swojej witryny. Zrozumienie i wdrożenie zasad SEO technicznego jest kluczowe dla każdej firmy, która chce skutecznie działać w sieci, zwłaszcza na rynku lokalnym.

Sytuacja firm usługowych w Olsztynku

Obserwując rynek usług w Olsztynku, łatwo zauważyć, że wiele przedsiębiorstw posiada już swoją stronę internetową. Niestety, znaczna część z nich to witryny, które zostały stworzone lata temu i od tego czasu nie były aktualizowane pod kątem technicznym. Częstym problemem jest przestarzały system zarządzania treścią (CMS), który nie pozwala na efektywną optymalizację, a także brak certyfikatu SSL, co skutkuje komunikatem o niezabezpieczonym połączeniu i obniża zaufanie użytkowników oraz pozycje w wyszukiwarkach. Inne typowe niedociągnięcia to:

  • Słaba responsywność: Strony nie dostosowują się poprawnie do ekranów smartfonów, co utrudnia nawigację i czytanie treści, szczególnie dla mieszkańców Olsztynka korzystających z urządzeń mobilnych.
  • Niska szybkość ładowania: Długi czas oczekiwania na załadowanie witryny zniechęca użytkowników i zwiększa współczynnik odrzuceń.
  • Brak danych strukturalnych: Niewykorzystanie znaczników Schema.org sprawia, że wyszukiwarki mają trudności z jednoznacznym zrozumieniem, czym jest firma, jakie usługi oferuje i gdzie się znajduje w Olsztynku.
  • Nieprawidłowe indeksowanie: Pliki robots.txt lub meta tagi noindex blokujące roboty wyszukiwarek, co uniemożliwia prawidłowe zaindeksowanie ważnych podstron.
  • Błędy 404 i niedziałające linki: Prowadzą do frustracji użytkowników i obniżają autorytet strony.

Wszystkie te czynniki sprawiają, że nawet jeśli firma oferuje usługi wysokiej jakości, jej strona internetowa pozostaje niewidoczna dla potencjalnych klientów szukających usług w Olsztynku. Techniczne SEO to nie tylko lista zadań dla programisty, to strategiczna inwestycja, która bezpośrednio przekłada się na widoczność, zaufanie i w konsekwencji – na liczbę pozyskanych klientów.

Decyzje strategiczne przed startem

Zanim przystąpimy do implementacji zmian technicznych na stronie, niezbędne jest podjęcie kilku strategicznych decyzji. Proces ten powinien być świadomy i oparty na analizie, a nie przypadkowych działaniach. Bez jasnego kierunku, nawet najlepiej wykonane prace techniczne mogą nie przynieść oczekiwanych rezultatów dla firmy działającej w Olsztynku.

  • Audyt techniczny strony: Pierwszym krokiem jest kompleksowy audyt. Pozwala on zidentyfikować istniejące problemy, takie jak błędy indeksowania, niska prędkość, problemy z responsywnością, duplikaty treści czy brak danych strukturalnych. Audyt jest punktem wyjścia do stworzenia realistycznego planu działania.
  • Definiowanie celów biznesowych: Co strona ma osiągnąć? Czy ma generować zapytania, sprzedawać produkty, budować świadomość marki? Inne cele wymagają innych priorytetów w optymalizacji. Dla lokalnej firmy z Olsztynka celem może być np. zwiększenie liczby rezerwacji telefonicznych lub wizyt w punkcie stacjonarnym.
  • Analiza grupy docelowej: Kto jest naszym potencjalnym klientem w Olsztynku? Jakie urządzenia preferuje? Jakie frazy wpisuje w wyszukiwarkę? Zrozumienie zachowań użytkowników pozwala dostosować optymalizację, np. kładąc większy nacisk na optymalizację mobilną, jeśli większość ruchu pochodzi ze smartfonów.
  • Wybór odpowiedniej technologii: Czy aktualny CMS jest wystarczający, czy może potrzebna jest migracja? Wybór hostingu ma wpływ na szybkość ładowania. Te decyzje mają długoterminowe konsekwencje dla możliwości rozwoju i optymalizacji strony.
  • Ustalenie budżetu i zasobów: Optymalizacja strony to proces ciągły, który wymaga nakładów finansowych i czasowych. Jasne określenie dostępnych zasobów pozwala na realistyczne planowanie zakresu prac i kolejności ich realizacji.

Podejście strategiczne do SEO technicznego to inwestycja w przyszłość firmy, która zapewni jej stabilną obecność w wynikach wyszukiwania i pomoże dotrzeć do klientów w Olsztynku i okolicy.

Proces krok po kroku

Optymalizacja strony pod kątem technicznym to złożony proces, który wymaga systematyczności i wiedzy. Poniżej przedstawiamy kluczowe elementy, które powinny być uwzględnione w planie działania, aby zwiększyć widoczność firmy w Olsztynku:

  • Kontrola indeksowania i dostępności dla robotów:
    • Plik robots.txt: Upewnienie się, że plik ten nie blokuje dostępu do ważnych sekcji strony.
    • Mapa witryny (sitemap.xml): Przesłanie aktualnej mapy do Google Search Console, aby ułatwić robotom odkrywanie wszystkich podstron.
    • Canonical Tag: Poprawne użycie tagów canonical, aby uniknąć problemów z duplikacją treści.
  • Szybkość ładowania strony (Core Web Vitals):
    • Optymalizacja obrazów: Kompresja, odpowiednie formaty (WebP), atrybuty alt.
    • Minimalizacja kodu: Usunięcie zbędnych znaków z plików CSS, JavaScript i HTML.
    • Wykorzystanie pamięci podręcznej (cache): Konfiguracja serwera i wtyczek do buforowania treści.
    • Odroczenie ładowania zasobów: Lazy loading dla obrazów i filmów, asynchroniczne ładowanie skryptów.
  • Responsywność i optymalizacja mobilna:
    • Upewnienie się, że strona poprawnie wyświetla się i działa na wszystkich urządzeniach (smartfony, tablety), co jest kluczowe dla użytkowników w Olsztynku.
    • Testowanie strony narzędziem Google Mobile-Friendly Test.
  • Struktura URL i hierarchia:
    • Używanie krótkich, czytelnych i opisowych adresów URL, zawierających słowa kluczowe.
    • Zapewnienie logicznej struktury nawigacji, ułatwiającej użytkownikom i robotom poruszanie się po stronie.
  • Dane strukturalne (Schema Markup):
    • Wdrożenie znaczników Schema.org dla typu biznesu (LocalBusiness), produktów, usług, recenzji, danych kontaktowych. To znacząco zwiększa szanse na pojawienie się w rozszerzonych wynikach wyszukiwania (rich snippets), co jest niezwykle cenne dla firm w Olsztynku.
  • Certyfikat SSL (HTTPS):
    • Przejście na protokół HTTPS jest standardem bezpieczeństwa i czynnikiem rankingowym.
  • Obsługa błędów i przekierowania:
    • Regularne monitorowanie strony pod kątem błędów 404 (nieistniejące strony) i ich naprawa lub ustawienie przekierowań 301.
  • Analiza i usuwanie duplikatów treści:
    • Identyfikacja i rozwiązanie problemów z powieloną treścią, która może negatywnie wpływać na ranking.

Każdy z tych kroków wymaga dokładności i zrozumienia, jak działa wyszukiwarka Google. Regularne przeglądy i aktualizacje są niezbędne, aby strona utrzymywała wysokie pozycje i była stale widoczna dla mieszkańców Olsztynka.

Treści i UX pod lokalne wyszukiwania

Chociaż SEO techniczne skupia się na niewidocznych aspektach strony, jego skuteczność jest ściśle powiązana z jakością treści i doświadczeniem użytkownika (UX). Dla lokalnych firm w Olsztynku, to połączenie jest szczególnie ważne, aby przyciągnąć klientów z najbliższej okolicy.

  • Optymalizacja pod lokalne słowa kluczowe:
    • Badanie fraz zawierających nazwę miejscowości, np. „fryzjer Olsztynek”, „mechanik samochodowy Olsztynek” lub „restauracja Olsztynek”.
    • Naturalne wplatanie tych fraz w tytuły stron, meta opisy, nagłówki (H1-H6) i treść.
  • Meta tagi i nagłówki:
    • Każda podstrona powinna mieć unikalny i precyzyjny tytuł (</code>) oraz opis (<code><meta description></code>), które zawierają słowa kluczowe i zachęcają do kliknięcia.</li> <li>Struktura nagłówków (H1, H2, H3) powinna być logiczna, ułatwiać czytanie i zawierać najważniejsze frazy.</li> </ul> </li> <li><strong>Wewnętrzne linkowanie:</strong> <ul> <li>Tworzenie spójnej sieci linków wewnętrznych, które prowadzą użytkowników i roboty po stronie. Linkowanie do innych usług, referencji czy bloga zwiększa wartość strony i ułatwia indeksowanie.</li> <li>Szczególnie ważne jest linkowanie do podstron specyficznych dla Olsztynka, np. „Nasze realizacje w Olsztynku”.</li> </ul> </li> <li><strong>Doświadczenie użytkownika (UX):</strong> <ul> <li><strong>Intuicyjna nawigacja:</strong> Użytkownik powinien łatwo znaleźć to, czego szuka. Menu powinno być proste i logiczne.</li> <li><strong>Czytelność treści:</strong> Odpowiedni rozmiar czcionki, kontrast, krótkie akapity, listy – wszystko to wpływa na komfort czytania.</li> <li><strong>Łatwość kontaktu:</strong> Wyraźnie widoczny numer telefonu, adres e-mail, formularz kontaktowy czy mapa dojazdu są niezbędne.</li> <li><strong>CTA (Call to Action):</strong> Jasne i widoczne wezwania do działania, np. „Zadzwoń teraz”, „Umów wizytę”, „Sprawdź naszą ofertę w Olsztynku”.</li> </ul> </li> <li><strong>Lokalne strony docelowe:</strong> Tworzenie dedykowanych stron dla konkretnych usług świadczonych w Olsztynku lub w jego okolicach, zoptymalizowanych pod kątem lokalnych słów kluczowych i danych kontaktowych.</li> </ul> <p>Dobre treści i pozytywne doświadczenie użytkownika przekładają się na niższy współczynnik odrzuceń, dłuższy czas spędzony na stronie i większą liczbę konwersji, co jest sygnałem dla wyszukiwarek, że strona jest wartościowa.</p> <h2>Integracje: CRM, analityka, reklamy</h2> <p>Skuteczne techniczne SEO nie działa w próżni. Aby w pełni wykorzystać potencjał strony internetowej i zrozumieć jej wpływ na biznes, niezbędne są integracje z innymi narzędziami. Pozwalają one mierzyć efektywność działań, śledzić zachowania użytkowników i optymalizować kampanie marketingowe, zwłaszcza te skierowane do odbiorców z Olsztynka.</p> <ul> <li><strong>Google Analytics (GA4):</strong> <ul> <li>Poprawna implementacja kodu śledzącego jest podstawą. Umożliwia zbieranie danych o ruchu na stronie, źródłach wejść, zachowaniach użytkowników (np. ile czasu spędzają na konkretnych podstronach, czy docierają do formularza kontaktowego).</li> <li>Konfiguracja celów i zdarzeń pozwala mierzyć konwersje, takie jak wysłanie formularza, kliknięcie numeru telefonu czy pobranie pliku, co jest kluczowe dla oceny skuteczności SEO technicznego.</li> </ul> </li> <li><strong>Google Search Console (GSC):</strong> <ul> <li>To niezastąpione narzędzie do monitorowania technicznych aspektów SEO. GSC informuje o błędach indeksowania, problemach z mobilnością, wydajnością strony (Core Web Vitals) oraz o tym, jakie zapytania prowadzą do wyświetleń i kliknięć strony.</li> <li>Umożliwia również przesyłanie mapy witryny i testowanie pojedynczych adresów URL.</li> </ul> </li> <li><strong>Integracja z systemami CRM:</strong> <ul> <li>Dla firm, które generują leady przez stronę, integracja z systemem CRM jest kluczowa. Pozwala na automatyczne przesyłanie danych z formularzy kontaktowych bezpośrednio do systemu, co ułatwia zarządzanie kontaktami i śledzenie ścieżki klienta.</li> <li>Techniczne zapewnienie płynnego przepływu danych jest niezbędne, aby nie tracić potencjalnych klientów z Olsztynka.</li> </ul> </li> <li><strong>Piksele marketingowe (Google Ads, Facebook Pixel):</strong> <ul> <li>Prawidłowa instalacja pikseli jest fundamentem efektywnych kampanii reklamowych. Pozwalają one na śledzenie konwersji, remarketing oraz tworzenie niestandardowych grup odbiorców, np. osób, które odwiedziły konkretną usługę w Olsztynku, ale nie dokonały zakupu.</li> <li>Wymaga to technicznej poprawności, aby dane były zbierane rzetelnie.</li> </ul> </li> <li><strong>Integracje z systemami rezerwacji/e-commerce:</strong> <ul> <li>Jeśli strona oferuje rezerwacje online lub sprzedaż produktów, techniczne aspekty tych integracji muszą być zoptymalizowane pod SEO. Obejmuje to poprawną strukturę URL, znaczniki Schema dla produktów/usług oraz szybkie ładowanie stron transakcyjnych.</li> </ul> </li> </ul> <p>Dzięki tym integracjom, działania SEO technicznego stają się mierzalne, a ich wpływ na cele biznesowe firmy z Olsztynka jest jasno widoczny. Pozwala to na ciągłe optymalizowanie strategii i maksymalizowanie zwrotu z inwestycji.</p> <h2>FAQ — najczęstsze pytania</h2> <h3>Czy mała firma z Olsztynka potrzebuje SEO technicznego?</h3> <p>Absolutnie tak. Niezależnie od wielkości firmy, jeśli chce być widoczna w Internecie i pozyskiwać klientów z wyszukiwarki, optymalizacja strony pod kątem technicznym jest niezbędna. Małe firmy często konkurują z większymi podmiotami, a solidne SEO techniczne może być ich przewagą, pozwalającą wyprzedzić konkurencję w wynikach wyszukiwania w Olsztynku.</p> <h3>Ile czasu zajmuje zauważenie efektów optymalizacji strony?</h3> <p>Efekty optymalizacji strony mogą być różne i zależą od wielu czynników, takich jak stan początkowy witryny, konkurencja w branży czy zakres wprowadzonych zmian. Pierwsze poprawy w indeksowaniu i szybkości strony można zauważyć już po kilku tygodniach. Pełne efekty w postaci wzrostu pozycji i ruchu są zazwyczaj widoczne po 3-6 miesiącach, a w niektórych przypadkach nawet dłużej, ponieważ Google potrzebuje czasu na przetworzenie i ocenę zmian.</p> <h3>Czy mogę samodzielnie zająć się technicznym SEO?</h3> <p>Podstawowe elementy SEO technicznego, takie jak optymalizacja obrazów czy podstawowe ustawienia CMS, można spróbować wdrożyć samodzielnie, zwłaszcza przy użyciu dostępnych wtyczek. Jednak bardziej zaawansowane aspekty, takie jak optymalizacja Core Web Vitals, wdrażanie danych strukturalnych czy rozwiązywanie złożonych problemów z indeksowaniem, wymagają specjalistycznej wiedzy technicznej i doświadczenia. Błędy w tych obszarach mogą przynieść więcej szkód niż pożytku. Warto rozważyć współpracę z ekspertami, aby mieć pewność, że wszystkie prace są wykonywane prawidłowo i efektywnie.</p> </div> </div> </section> <section class="w-full bg-zinc-900 py-16 md:py-20"> <div class="max-w-5xl mx-auto px-6 text-center reveal-element"> <h2 class="font-heading text-3xl md:text-4xl text-white mb-4">Zadbaj o widoczność w wyszukiwarkach</h2> <p class="text-zinc-300 text-base leading-relaxed max-w-2xl mx-auto mb-8">Popraw techniczne SEO swojej strony internetowej, zwiększ ruch i pozyskaj nowych klientów z Olsztynka.</p> <a href="/wycena/" class="inline-flex items-center justify-center gap-2 bg-rose-500 hover:bg-rose-600 text-white font-medium px-7 py-3.5 rounded-full transition-all hover:scale-105 active:scale-95"> Umów bezpłatną wycenę <svg aria-hidden="true" focusable="false" class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"> <path d="M5 12h14m-7-7l7 7-7 7"></path> </svg> </a> </div> </section> </article> </main> <style> .reveal-element { opacity: 0; transform: translateY(20px); transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1), transform 0.7s cubic-bezier(0.16, 1, 0.3, 1); } .reveal-element.is-visible { opacity: 1; transform: translateY(0); } </style> <style> .blog-content { font-size: 1.0625rem; line-height: 1.75; color: #52525b; } .blog-content > *:first-child { margin-top: 0; } .blog-content h2 { font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-size: clamp(1.5rem, 4vw, 1.875rem); font-weight: 600; line-height: 1.25; letter-spacing: -0.02em; color: #18181b; margin-top: 2.5rem; margin-bottom: 0.75rem; } .blog-content h3 { font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-size: 1.25rem; font-weight: 600; line-height: 1.35; color: #18181b; margin-top: 1.75rem; margin-bottom: 0.5rem; } .blog-content h4 { font-size: 1.125rem; font-weight: 600; color: #18181b; margin-top: 1.5rem; margin-bottom: 0.5rem; } .blog-content p { margin-bottom: 1.25em; line-height: 1.75; color: #52525b; } .blog-content ul, .blog-content ol { margin: 1rem 0 1.5rem; padding-left: 1.5rem; color: #52525b; } .blog-content ul { list-style-type: disc; } .blog-content ol { list-style-type: decimal; } .blog-content li { margin-bottom: 0.5em; line-height: 1.7; } .blog-content li::marker { color: #f43f5e; } .blog-content a { color: #f43f5e; text-decoration: underline; } .blog-content a:hover { color: #e11d48; } .blog-content strong { color: #18181b; font-weight: 600; } .blog-content blockquote { border-left: 4px solid #f43f5e; padding-left: 1rem; margin: 1.5rem 0; color: #71717a; font-style: italic; } </style> <script> document.addEventListener('DOMContentLoaded', function () { var elements = document.querySelectorAll('.reveal-element'); if (!elements.length) return; var observer = new IntersectionObserver(function (entries) { entries.forEach(function (entry) { if (entry.isIntersecting) { entry.target.classList.add('is-visible'); observer.unobserve(entry.target); } }); }, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' }); elements.forEach(function (el) { observer.observe(el); }); }); </script> </div> <section id="kontakt" class="w-full bg-zinc-900"> <div class="max-w-7xl mx-auto px-6 py-20 lg:py-28"> <div class="grid lg:grid-cols-12 gap-12 lg:gap-16 items-start"> <div class="lg:col-span-5 reveal-element" style="opacity: 1; transform: translateY(0px); transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1), transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);"> <p class="text-rose-400 text-sm font-medium tracking-widest uppercase mb-3">Napisz do nas</p> <h2 class="font-heading text-3xl md:text-4xl lg:text-5xl text-white mb-6"> <span>Zbudujmy Ci biznes, który</span> <span class="italic text-rose-400">zarabia</span> </h2> <p class="text-zinc-400 text-base leading-relaxed mb-10">Opowiedz nam o swoim projekcie. Pierwsza konsultacja jest bezpłatna — sprawdzimy co możemy dla Ciebie zrobić i ile to kosztuje.</p> <div class="space-y-6"> <div class="flex items-center gap-4"> <div class="w-10 h-10 bg-zinc-800 rounded-xl flex items-center justify-center border border-zinc-700"> <svg aria-hidden="true" focusable="false" class="w-5 h-5 text-rose-400" fill="none" stroke="currentColor" stroke-width="1.5" viewbox="0 0 24 24"> <path d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75"> </path> </svg> </div> <span class="text-zinc-300 text-sm">biuro@pensatore.pl</span> </div> <div class="flex items-center gap-4"> <div class="w-10 h-10 bg-zinc-800 rounded-xl flex items-center justify-center border border-zinc-700"> <svg aria-hidden="true" focusable="false" class="w-5 h-5 text-rose-400" fill="none" stroke="currentColor" stroke-width="1.5" viewbox="0 0 24 24"> <path d="M2.25 6.75c0 8.284 6.716 15 15 15h2.25a2.25 2.25 0 002.25-2.25v-1.372c0-.516-.351-.966-.852-1.091l-4.423-1.106c-.44-.11-.902.055-1.173.417l-.97 1.293c-.282.376-.769.542-1.21.38a12.035 12.035 0 01-7.143-7.143c-.162-.441.004-.928.38-1.21l1.293-.97c.363-.271.527-.734.417-1.173L6.963 3.102a1.125 1.125 0 00-1.091-.852H4.5A2.25 2.25 0 002.25 4.5v2.25z"> </path> </svg> </div> <a href="tel:+48787112730" class="text-zinc-300 text-sm hover:text-white transition-colors">+48 787 112 730</a> </div> </div> <div class="mt-10 pt-10 border-t border-zinc-800"> <p class="text-zinc-500 text-xs uppercase tracking-wider mb-4">Nasze usługi</p> <div class="flex flex-wrap gap-2"> <a href="/zaistniej-online/" class="text-xs bg-zinc-800 text-zinc-400 px-3 py-1.5 rounded-full border border-zinc-700 hover:text-zinc-200 hover:border-zinc-500 transition-colors">Zaistniej online</a> <a href="/sprzedawaj-online/" class="text-xs bg-zinc-800 text-zinc-400 px-3 py-1.5 rounded-full border border-zinc-700 hover:text-zinc-200 hover:border-zinc-500 transition-colors">Sprzedawaj online</a> <a href="/badz-widoczny/" class="text-xs bg-zinc-800 text-zinc-400 px-3 py-1.5 rounded-full border border-zinc-700 hover:text-zinc-200 hover:border-zinc-500 transition-colors">Bądź widoczny</a> <a href="/pokaz-sie-z-ekranu/" class="text-xs bg-zinc-800 text-zinc-400 px-3 py-1.5 rounded-full border border-zinc-700 hover:text-zinc-200 hover:border-zinc-500 transition-colors">Pokaż się z ekranu</a> </div> </div> </div> <div class="lg:col-span-7 reveal-element"> <div class="bg-zinc-800/50 rounded-2xl p-8 lg:p-10 border border-zinc-700/50 backdrop-blur-sm"> <form class="space-y-5 contact-form" method="post" action="/kontakt/wyslij/" data-contact-form> <input type="hidden" name="csrfmiddlewaretoken" value="fpZjv64cm8ZI9Bkhwbo1Gk6YcFtU6A27CKIhfCUfdyEa4pOkAy7w3byaqLMgePEG"> <input type="hidden" name="source" value="footer" /> <div class="grid sm:grid-cols-2 gap-5"> <div> <label class="text-zinc-400 text-sm mb-2 block">Imię i nazwisko</label> <input type="text" name="name" required class="w-full bg-zinc-900/50 border border-zinc-700 rounded-xl px-4 py-3 text-white text-sm placeholder-zinc-600 focus:outline-none focus:border-rose-500/50 focus:ring-1 focus:ring-rose-500/20 transition-colors" placeholder="Jan Kowalski" /> </div> <div> <label class="text-zinc-400 text-sm mb-2 block">E-mail</label> <input type="email" name="email" required class="w-full bg-zinc-900/50 border border-zinc-700 rounded-xl px-4 py-3 text-white text-sm placeholder-zinc-600 focus:outline-none focus:border-rose-500/50 focus:ring-1 focus:ring-rose-500/20 transition-colors" placeholder="jan@firma.pl" /> </div> </div> <div> <label class="text-zinc-400 text-sm mb-2 block">Temat</label> <input type="text" name="subject" required class="w-full bg-zinc-900/50 border border-zinc-700 rounded-xl px-4 py-3 text-white text-sm placeholder-zinc-600 focus:outline-none focus:border-rose-500/50 focus:ring-1 focus:ring-rose-500/20 transition-colors" placeholder="Np. Wycena strony internetowej" /> </div> <div> <label class="text-zinc-400 text-sm mb-2 block">Opisz swój projekt</label> <textarea rows="4" name="message" required class="w-full bg-zinc-900/50 border border-zinc-700 rounded-xl px-4 py-3 text-white text-sm placeholder-zinc-600 focus:outline-none focus:border-rose-500/50 focus:ring-1 focus:ring-rose-500/20 transition-colors resize-none" placeholder="Opowiedz nam o swoich potrzebach..."></textarea> </div> <button type="submit" class="w-full bg-rose-500 hover:bg-rose-600 text-white font-medium px-7 py-3.5 rounded-full transition-all hover:scale-[1.02] active:scale-[0.98] shadow-lg shadow-rose-500/20">Wyślij zapytanie</button> <p class="text-zinc-500 text-xs text-center" data-contact-status>Odpowiadamy w ciągu 24 godzin. Konsultacja jest bezpłatna.</p> </form> </div> </div> </div> </div> </section> <footer class="w-full bg-zinc-950"> <div class="max-w-7xl mx-auto px-6 py-12"> <div class="flex flex-col lg:flex-row items-start lg:items-center justify-between gap-8 pb-10 border-b border-zinc-800"> <div class="flex items-center gap-2.5"> <span class="font-heading text-lg text-white tracking-tight">pensatore</span> </div> <div class="flex flex-wrap gap-6"><a href="/zaistniej-online/" class="text-sm text-zinc-500 hover:text-zinc-300 transition-colors">Zaistniej online</a><a href="/sprzedawaj-online/" class="text-sm text-zinc-500 hover:text-zinc-300 transition-colors">Sprzedawaj online</a><a href="/badz-widoczny/" class="text-sm text-zinc-500 hover:text-zinc-300 transition-colors">Bądź widoczny</a><a href="/pokaz-sie-z-ekranu/" class="text-sm text-zinc-500 hover:text-zinc-300 transition-colors">Pokaż się z ekranu</a></div> </div> <div class="flex flex-col md:flex-row items-center justify-between gap-4 pt-8"> <p class="text-xs text-zinc-500">© 2026 Pensatore House. Wszelkie prawa zastrzeżone.</p> <p class="text-xs text-zinc-500 text-center md:text-right"> Partner strategiczny: <a href="https://kryminalnezagadki.pl/" class="text-zinc-400 hover:text-zinc-200 transition-colors underline underline-offset-2">Kryminalne Zagadki</a> — logiczne śledztwa online po polsku. </p> <div class="flex items-center gap-6"><a href="/polityka-prywatnosci/" class="text-xs text-zinc-500 hover:text-zinc-300 transition-colors">Polityka prywatności</a><a href="/polityka-cookies/" class="text-xs text-zinc-500 hover:text-zinc-300 transition-colors">Cookies</a></div> </div> </div> </footer> <div id="newsletter-popup" class="fixed inset-0 z-[99999] hidden items-center justify-center bg-zinc-950/70 px-6 backdrop-blur-sm"> <div class="relative w-full max-w-md rounded-3xl bg-white p-8 shadow-2xl shadow-zinc-950/20"> <button type="button" data-newsletter-close class="absolute right-4 top-4 rounded-full p-2 text-zinc-400 hover:bg-zinc-100 hover:text-zinc-700" aria-label="Zamknij newsletter"> <svg aria-hidden="true" focusable="false" class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"> <path d="M6 18L18 6M6 6l12 12"></path> </svg> </button> <p class="text-rose-500 text-sm font-medium tracking-widest uppercase mb-3">Newsletter</p> <h2 class="font-heading text-3xl text-zinc-900 mb-4">Zapisz się i potwierdź 10% zniżki</h2> <p class="text-zinc-500 text-sm leading-relaxed mb-6">Dostaniesz praktyczne wskazówki o stronach, reklamie i sprzedaży online. Kod rabatowy wyślemy po potwierdzeniu adresu e-mail.</p> <form method="post" action="/newsletter/zapisz/" data-newsletter-form class="space-y-4"> <input type="hidden" name="csrfmiddlewaretoken" value="fpZjv64cm8ZI9Bkhwbo1Gk6YcFtU6A27CKIhfCUfdyEa4pOkAy7w3byaqLMgePEG"> <input type="text" name="name" class="w-full rounded-xl border border-zinc-200 px-4 py-3 text-sm focus:border-rose-400 focus:outline-none" placeholder="Imię (opcjonalnie)" /> <input type="email" name="email" required class="w-full rounded-xl border border-zinc-200 px-4 py-3 text-sm focus:border-rose-400 focus:outline-none" placeholder="Twój e-mail" /> <label class="flex items-start gap-3 text-xs leading-relaxed text-zinc-500"> <input type="checkbox" name="marketing_consent" required class="mt-1 h-4 w-4 rounded border-zinc-300 text-rose-500 focus:ring-rose-400" /> <span>Wyrażam zgodę na otrzymywanie od EMPIRE SP. Z O.O. informacji marketingowych i handlowych drogą elektroniczną na podany adres e-mail, w tym newslettera Pensatore. Wiem, że zgodę mogę wycofać w każdej chwili. Szczegóły są w <a href="/polityka-prywatnosci/" class="text-rose-500 hover:text-rose-600">polityce prywatności</a>.</span> </label> <button type="submit" class="w-full rounded-full bg-rose-500 px-6 py-3.5 text-sm font-medium text-white transition-colors hover:bg-rose-600">Wyślij link potwierdzający</button> <p class="text-center text-xs text-zinc-400" data-newsletter-status>Administrator: EMPIRE SP. Z O.O. Zero spamu. Możesz wypisać się w każdej chwili.</p> </form> </div> </div> <script> document.addEventListener('DOMContentLoaded', function () { var contactForm = document.querySelector('[data-contact-form]'); if (contactForm) { contactForm.addEventListener('submit', function (event) { event.preventDefault(); var status = contactForm.querySelector('[data-contact-status]'); var button = contactForm.querySelector('button[type="submit"]'); if (status) status.textContent = 'Wysyłamy wiadomość...'; if (button) button.disabled = true; fetch(contactForm.action, { method: 'POST', body: new FormData(contactForm), headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(function (response) { return response.json().then(function (data) { return { ok: response.ok, data: data }; }); }) .then(function (result) { if (status) status.textContent = result.data.message || (result.ok ? 'Wysłano.' : 'Nie udało się wysłać.'); if (result.ok) { contactForm.reset(); var sourceInput = contactForm.querySelector('input[name="source"]'); if (window.pensatoreTrackFormSubmit) { window.pensatoreTrackFormSubmit({ form_name: 'contact', form_id: 'contact-form-footer', form_source: sourceInput ? sourceInput.value : 'footer', }); } } }) .catch(function () { if (status) status.textContent = 'Nie udało się wysłać wiadomości. Spróbuj ponownie albo napisz e-mail.'; }) .finally(function () { if (button) button.disabled = false; }); }); } var popup = document.getElementById('newsletter-popup'); var newsletterForm = document.querySelector('[data-newsletter-form]'); var closeButtons = document.querySelectorAll('[data-newsletter-close]'); var storageKey = 'pensatore_newsletter_popup_closed'; function closeNewsletterPopup() { if (!popup) return; popup.classList.add('hidden'); popup.classList.remove('flex'); localStorage.setItem(storageKey, '1'); } var cookieConsentKey = 'pensatore_cookie_consent'; function hasCookieDecision() { var value = localStorage.getItem(cookieConsentKey); return value === 'accepted' || value === 'necessary'; } function scheduleNewsletterPopup() { if (!popup || localStorage.getItem(storageKey) === '1') return; if (!hasCookieDecision()) return; window.setTimeout(function () { if (!popup || localStorage.getItem(storageKey) === '1') return; if (!hasCookieDecision()) return; popup.classList.remove('hidden'); popup.classList.add('flex'); }, 2500); } if (hasCookieDecision()) { scheduleNewsletterPopup(); } document.addEventListener('pensatore:cookie-consent', function () { if (localStorage.getItem(storageKey) !== '1') { scheduleNewsletterPopup(); } }); closeButtons.forEach(function (button) { button.addEventListener('click', closeNewsletterPopup); }); if (popup) { popup.addEventListener('click', function (event) { if (event.target === popup) closeNewsletterPopup(); }); } if (newsletterForm) { newsletterForm.addEventListener('submit', function (event) { event.preventDefault(); var status = newsletterForm.querySelector('[data-newsletter-status]'); var button = newsletterForm.querySelector('button[type="submit"]'); if (status) status.textContent = 'Wysyłamy link potwierdzający...'; if (button) button.disabled = true; fetch(newsletterForm.action, { method: 'POST', body: new FormData(newsletterForm), headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(function (response) { var contentType = response.headers.get('content-type') || ''; if (contentType.indexOf('application/json') === -1) { throw new Error('HTTP ' + response.status); } return response.json().then(function (data) { return { ok: response.ok, data: data }; }); }) .then(function (result) { if (status) status.textContent = result.data.message || 'Sprawdź skrzynkę i potwierdź zapis.'; if (result.ok) { localStorage.setItem(storageKey, '1'); newsletterForm.reset(); } }) .catch(function (error) { if (status) status.textContent = 'Nie udało się zapisać. Błąd serwera: ' + error.message + '.'; }) .finally(function () { if (button) button.disabled = false; }); }); } }); </script> <script> (() => { if (window.PensatoreVueSPA) return; window.PensatoreVueSPA = true; const parser = new DOMParser(); const ignoredExtensions = /\.(pdf|zip|rar|7z|jpg|jpeg|png|gif|webp|svg|mp4|webm|doc|docx|xls|xlsx)$/i; let spaApp = null; function getParts(root) { return { view: root.querySelector("#spa-view"), }; } function shouldHandleLink(link, event) { if (!link || event.defaultPrevented) return false; if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return false; if (link.target && link.target !== "_self") return false; if (link.hasAttribute("download")) return false; if (link.dataset.noSpa !== undefined) return false; if (link.getAttribute("href").startsWith("#")) return false; const url = new URL(link.href, window.location.href); if (url.origin !== window.location.origin) return false; if (url.protocol !== "http:" && url.protocol !== "https:") return false; if (url.pathname.startsWith("/admin/") || url.pathname.startsWith("/django-admin/")) return false; if (ignoredExtensions.test(url.pathname)) return false; if (url.pathname === window.location.pathname && url.search === window.location.search) return false; return true; } function syncHead(nextDocument) { document.title = nextDocument.title; const selectors = [ 'meta[name="description"]', 'meta[name="keywords"]', 'meta[name="robots"]', 'link[rel="canonical"]', 'meta[property^="og:"]', 'meta[name^="twitter:"]', 'script[type="application/ld+json"]', ]; selectors.forEach((selector) => { document.head.querySelectorAll(selector).forEach((node) => node.remove()); nextDocument.head.querySelectorAll(selector).forEach((node) => { document.head.appendChild(node.cloneNode(true)); }); }); } function replacePart(currentNode, nextNode) { if (!nextNode) return; const clone = nextNode.cloneNode(true); if (currentNode) { currentNode.replaceWith(clone); return clone; } return null; } function runScripts(scope) { const readyCallbacks = []; const nativeAddEventListener = document.addEventListener.bind(document); document.addEventListener = function (type, listener, options) { if (type === "DOMContentLoaded" && typeof listener === "function") { readyCallbacks.push(listener); return; } nativeAddEventListener(type, listener, options); }; try { scope.querySelectorAll("script").forEach((oldScript) => { if (oldScript.src && oldScript.src.includes("vue.global")) return; const script = document.createElement("script"); Array.from(oldScript.attributes).forEach((attr) => { script.setAttribute(attr.name, attr.value); }); script.textContent = oldScript.textContent; oldScript.replaceWith(script); }); } finally { document.addEventListener = nativeAddEventListener; } readyCallbacks.forEach((listener) => { listener.call(document, new Event("DOMContentLoaded")); }); } function createMountNode() { const node = document.createElement("div"); node.id = "pensatore-vue-spa"; node.hidden = true; document.body.appendChild(node); return node; } function ensurePreloaderHidden() { const preloader = document.getElementById("preloader"); if (!preloader) return; if (window.PensatorePreloader) { window.PensatorePreloader.hide(); return; } preloader.style.opacity = "0"; preloader.style.display = "none"; } function loadVue() { if (window.Vue) return Promise.resolve(window.Vue); if (window.__vueLoadPromise) return window.__vueLoadPromise; window.__vueLoadPromise = new Promise((resolve, reject) => { const script = document.createElement("script"); script.src = "https://unpkg.com/vue@3/dist/vue.global.prod.js"; script.async = true; script.onload = () => resolve(window.Vue); script.onerror = reject; document.body.appendChild(script); }); return window.__vueLoadPromise; } function mountSpa(Vue) { if (spaApp) return spaApp; spaApp = Vue.createApp({ data() { return { loading: false }; }, methods: { async go(url, pushState = true) { this.loading = true; document.documentElement.classList.add("spa-loading"); window.PensatorePreloader?.show(); try { const response = await fetch(url, { headers: { "X-Requested-With": "fetch", Accept: "text/html" }, credentials: "same-origin", }); if (!response.ok) { window.location.href = url; return; } const html = await response.text(); const nextDocument = parser.parseFromString(html, "text/html"); const currentParts = getParts(document); const nextParts = getParts(nextDocument); if (!nextParts.view) { window.location.href = url; return; } syncHead(nextDocument); const updatedParts = [ replacePart(currentParts.view, nextParts.view), ].filter(Boolean); if (pushState) { history.pushState({ spa: true }, "", url); } updatedParts.forEach((part) => runScripts(part)); ensurePreloaderHidden(); document.querySelector("#mobile-nav .mobile-menu")?.classList.add("hidden"); document.querySelector("#mobile-nav .mobile-menu-toggle")?.setAttribute("aria-expanded", "false"); window.scrollTo({ top: 0, behavior: "auto" }); document.dispatchEvent(new CustomEvent("pensatore:page-loaded")); } catch (error) { window.location.href = url; } finally { this.loading = false; document.documentElement.classList.remove("spa-loading"); } }, }, }).mount(createMountNode()); return spaApp; } document.addEventListener("click", async (event) => { const link = event.target.closest("a[href]"); if (!shouldHandleLink(link, event)) return; event.preventDefault(); try { const Vue = await loadVue(); const spa = mountSpa(Vue); spa.go(link.href); } catch (error) { window.location.href = link.href; } }); window.addEventListener("popstate", () => { window.location.href = window.location.href; }); })(); </script> <script> document.addEventListener('DOMContentLoaded', function () { var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; if (reduceMotion) { document.documentElement.classList.add('ph-animate-static'); return; } document.documentElement.classList.add('ph-animate-ready'); var elements = document.querySelectorAll('.reveal-element'); elements.forEach(function (element, index) { element.style.setProperty('--ph-delay', Math.min(index, 4) * 60 + 'ms'); }); var observer = new IntersectionObserver(function (entries) { entries.forEach(function (entry) { if (entry.isIntersecting) { entry.target.classList.add('is-visible'); observer.unobserve(entry.target); } }); }, { threshold: 0.08, rootMargin: '0px 0px -32px 0px' }); elements.forEach(function (element) { observer.observe(element); }); }); </script> </body> </html>