Błąd "Element X not allowed as child of element Y in this context" to jeden z najczęstszych problemów podczas walidacji kodu HTML. Pojawia się, gdy próbujemy zagnieździć element w innym elemencie w sposób niezgodny ze standardami HTML. W tym przewodniku dowiesz się, jakie są przyczyny tego błędu, jakie są najczęstsze przypadki jego występowania oraz jak skutecznie go naprawić, aby Twoja strona była zgodna ze standardami W3C.

⚡ Ekspresowe Podsumowanie:

  1. Przyczyna błędu: Błąd pojawia się, gdy umieszczasz element HTML wewnątrz innego elementu, który zgodnie ze specyfikacją nie może go zawierać.
  2. Typowe przypadki: Umieszczanie elementów blokowych wewnątrz elementów liniowych, nieprawidłowa struktura list, tabeli lub formularzy.
  3. Rozwiązania: Zastosowanie prawidłowej struktury zagnieżdżenia zgodnej ze specyfikacją HTML5.
  4. Narzędzia pomocnicze: Walidator W3C, narzędzia deweloperskie przeglądarek, edytory z podpowiedziami składni.

🗺️ Spis Treści - Twoja Mapa Drogowa


📚 Zrozumienie błędu zagnieżdżenia elementów

Błąd "Element X not allowed as child of element Y in this context" (Element X nie jest dozwolony jako dziecko elementu Y w tym kontekście) jest stosunkowo prosty do zrozumienia, ale może być trudny do zidentyfikowania i naprawienia, szczególnie w bardziej złożonych strukturach HTML.

Co dokładnie oznacza ten błąd?

Ten komunikat wskazuje, że próbujesz umieścić element HTML (oznaczony jako X) wewnątrz innego elementu (oznaczonego jako Y), ale specyfikacja HTML nie pozwala na takie zagnieżdżenie. Każdy element HTML ma ściśle określone reguły dotyczące tego, jakie inne elementy mogą być jego "dziećmi" (czyli elementami zagnieżdżonymi).

Dlaczego to jest ważne?

Przestrzeganie prawidłowej struktury zagnieżdżania elementów jest kluczowe z kilku powodów:

  1. Zgodność ze standardami: Strony zgodne ze standardami W3C mają większą szansę na poprawne wyświetlanie we wszystkich przeglądarkach.
  2. Dostępność: Prawidłowa struktura HTML jest kluczowa dla czytników ekranu i innych technologii wspomagających.
  3. SEO: Wyszukiwarki lepiej interpretują i indeksują strony z poprawnym, semantycznym kodem HTML.
  4. Utrzymanie kodu: Czysty, zgodny ze standardami kod jest łatwiejszy do utrzymania i modyfikowania.

Podstawowe zasady zagnieżdżania elementów

W HTML istnieją pewne fundamentalne zasady, które warto znać:

  1. Elementy blokowe vs liniowe: Elementy blokowe (np. <div>, <p>, <h1>) mogą zawierać inne elementy blokowe i liniowe, ale elementy liniowe (np. <span>, <a>, <strong>) mogą zawierać tylko inne elementy liniowe.

  2. Elementy strukturalne: Niektóre elementy wymagają konkretnej struktury zagnieżdżenia, np. w <ul> lub <ol> można umieszczać tylko elementy <li>.

  3. Kontekst paragrafu: Niektóre elementy, jak <p>, mają ograniczony zestaw potomków i nie mogą zawierać innych elementów blokowych.

  4. Elementy puste: Niektóre elementy (np. <img>, <input>, <br>) są elementami pustymi i nie mogą zawierać innych elementów.

💡 Najczęstsze przypadki błędu i ich rozwiązania

Przyjrzyjmy się najczęściej spotykanym przypadkom tego błędu i sposobom ich rozwiązania:

1. Elementy blokowe wewnątrz elementów liniowych

Problem:

<span>
    <div>Ten kod generuje błąd</div>
</span>

Błąd: "Element div not allowed as child of element span in this context"

Rozwiązanie:

<!-- Opcja 1: Zamień element liniowy na blokowy -->
<div>
    <div>Ten kod jest poprawny</div>
</div>

<!-- Opcja 2: Zamień element blokowy na liniowy -->
<span>
    <span>Ten kod również jest poprawny</span>
</span>

2. Błędna struktura list

Problem:

<ul>
    Niepoprawny tekst bezpośrednio w liście
    <div>Niepoprawny element div w liście</div>
</ul>

Błąd: "Element div not allowed as child of element ul in this context"

Rozwiązanie:

<ul>
    <li>Tekst powinien być w elemencie li</li>
    <li><div>Teraz div jest poprawnie umieszczony w li</div></li>
</ul>

3. Elementy blokowe wewnątrz paragrafów

Problem:

<p>
    Początek paragrafu
    <div>Ten div powoduje błąd</div>
    Koniec paragrafu
</p>

Błąd: "Element div not allowed as child of element p in this context"

Rozwiązanie:

<p>Początek paragrafu</p>
<div>Ten div jest teraz poza paragrafem</div>
<p>Koniec paragrafu</p>

4. Nieprawidłowa struktura tabeli

Problem:

<table>
    <tr>
        <td>Komórka 1</td>
    </tr>
    <div>Ten div nie może być tutaj</div>
</table>

Błąd: "Element div not allowed as child of element table in this context"

Rozwiązanie:

<table>
    <tbody>
        <tr>
            <td>Komórka 1</td>
        </tr>
        <tr>
            <td>
                <div>Div może być wewnątrz komórki</div>
            </td>
        </tr>
    </tbody>
</table>

5. Błędy w formularzach

Problem:

<form>
    <label>Etykieta</label>
    <input type="text">
    <div>
        <button>Przycisk w div</button>
    </div>
    <p>Paragraf w formularzu</p>
</form>

Ten kod jest poprawny w HTML5, ale wcześniej mógł powodować problemy. Warto pamiętać, że formularze mają elastyczną strukturę i mogą zawierać większość elementów poza innymi formularzami.

✨ Pro Tip: W przypadku złożonych formularzy, dobrą praktyką jest grupowanie powiązanych elementów za pomocą <fieldset> z odpowiednim <legend>, co poprawia dostępność i semantykę:

<form>
    <fieldset>
        <legend>Dane osobowe</legend>
        <label for="name">Imię:</label>
        <input type="text" id="name">
    </fieldset>
    <button type="submit">Wyślij</button>
</form>

🔍 Jak zidentyfikować i naprawić błędy zagnieżdżenia

Aby skutecznie identyfikować i naprawiać błędy zagnieżdżenia, warto korzystać z odpowiednich narzędzi i technik:

1. Walidator W3C

Najprostszym sposobem sprawdzenia, czy Twój kod HTML zawiera błędy zagnieżdżenia, jest skorzystanie z oficjalnego walidatora W3C:

  1. Odwiedź stronę validator.w3.org
  2. Wprowadź adres URL swojej strony, prześlij plik HTML lub wklej bezpośrednio kod
  3. Analizuj otrzymane wyniki, zwracając szczególną uwagę na komunikaty o błędach zagnieżdżenia

Walidator W3C wskaże dokładnie, które elementy są nieprawidłowo zagnieżdżone, i często sugeruje rozwiązania.

2. Narzędzia deweloperskie przeglądarek

Nowoczesne przeglądarki oferują zaawansowane narzędzia deweloperskie, które pomagają identyfikować problemy z kodem HTML:

  1. Otwórz narzędzia deweloperskie (zazwyczaj F12 lub Ctrl+Shift+I)
  2. Przejdź do zakładki "Elements" (Chrome) lub "Inspector" (Firefox)
  3. Przeszukaj DOM (Document Object Model) w poszukiwaniu nieprawidłowych struktur
  4. Zwróć uwagę na ostrzeżenia wyświetlane przez przeglądarkę

3. Edytory kodu z podpowiedziami składni

Korzystaj z edytorów kodu, które oferują podpowiedzi składni i walidację w czasie rzeczywistym:

  • Visual Studio Code z rozszerzeniami takimi jak HTML Hint czy HTMLHint
  • PhpStorm lub WebStorm z wbudowaną obsługą walidacji HTML
  • Sublime Text z pluginem SublimeLinter

Takie narzędzia często podkreślają problematyczne fragmenty kodu jeszcze przed zapisaniem pliku.

4. Podejście systematyczne

Przy naprawianiu błędów zagnieżdżenia warto zastosować systematyczne podejście:

  1. Izoluj problem: Wyodrębnij fragment kodu, który powoduje błąd
  2. Zrozum ograniczenia: Sprawdź w dokumentacji, jakie elementy mogą być zagnieżdżane w elemencie nadrzędnym
  3. Przeorganizuj strukturę: Zmień strukturę HTML, zachowując jednocześnie zamierzony wygląd i funkcjonalność
  4. Testuj inkrementalnie: Po każdej zmianie waliduj kod, aby upewnić się, że błąd został rozwiązany i nie wprowadzono nowych problemów

Uwaga: Pamiętaj, że niektóre frameworki i biblioteki mogą generować HTML, który wygląda niepoprawnie, ale działa prawidłowo w kontekście danego narzędzia. Zawsze sprawdzaj dokumentację używanych technologii.

🛠️ Przewodnik po dozwolonych zagnieżdżeniach elementów HTML5

Poniżej prezentujemy przewodnik po najczęściej używanych elementach HTML5 i ich dozwolonych "dzieciach", który pomoże Ci unikać błędów zagnieżdżenia:

Elementy dokumentu i sekcji

  • \ - Może zawierać: \, \
  • \ - Może zawierać: \, \<meta>, \<link>, \<style>, \<script>, \<noscript>, \<base></li> <li><strong>\<body></strong> - Może zawierać praktycznie wszystkie elementy widoczne (blokowe i liniowe)</li> <li><strong>\<header></strong>, <strong>\<footer></strong>, <strong>\<main></strong>, <strong>\<section></strong>, <strong>\<article></strong>, <strong>\<aside></strong>, <strong>\<nav></strong> - Elementy strukturalne, mogą zawierać większość elementów blokowych i liniowych, ale nie mogą zawierać \<header> lub \<footer> wewnątrz \<header> lub \<footer></li> </ul> <h3>Elementy blokowe</h3> <ul> <li><strong>\<div></strong> - Może zawierać praktycznie wszystkie elementy (blokowe i liniowe)</li> <li><strong>\<p></strong> - Może zawierać tylko elementy liniowe, NIE może zawierać elementów blokowych</li> <li><strong>\<h1></strong> do <strong>\<h6></strong> - Powinny zawierać głównie tekst i elementy liniowe, unikaj zagnieżdżania elementów blokowych</li> <li><strong>\<blockquote></strong> - Może zawierać elementy blokowe i liniowe</li> <li><strong>\<pre></strong> - Zazwyczaj zawiera tekst i ograniczony zestaw elementów liniowych</li> </ul> <h3>Listy</h3> <ul> <li><strong>\<ul></strong>, <strong>\<ol></strong> - Mogą zawierać TYLKO elementy \<li></li> <li><strong>\<li></strong> - Może zawierać zarówno elementy blokowe, jak i liniowe</li> <li><strong>\<dl></strong> - Może zawierać tylko elementy \<dt> i \<dd></li> <li><strong>\<dt></strong> - Powinien zawierać głównie tekst i elementy liniowe</li> <li><strong>\<dd></strong> - Może zawierać elementy blokowe i liniowe</li> </ul> <h3>Tabele</h3> <ul> <li><strong>\<table></strong> - Może zawierać: \<caption>, \<colgroup>, \<thead>, \<tbody>, \<tfoot>, \<tr></li> <li><strong>\<tr></strong> - Może zawierać tylko \<th> i \<td></li> <li><strong>\<th></strong>, <strong>\<td></strong> - Mogą zawierać zarówno elementy blokowe, jak i liniowe</li> </ul> <h3>Formularze</h3> <ul> <li><strong>\<form></strong> - Może zawierać większość elementów HTML poza innym \<form></li> <li><strong>\<fieldset></strong> - Grupuje powiązane elementy formularza, powinien zawierać \<legend> i elementy formularza</li> <li><strong>\<select></strong> - Może zawierać tylko elementy \<option> i \<optgroup></li> <li><strong>\<optgroup></strong> - Może zawierać tylko elementy \<option></li> <li><strong>\<button></strong> - Może zawierać elementy liniowe (ale nie \<a>, \<button>, \<select>, \<textarea>, \<input>, \<label>)</li> </ul> <h3>Elementy liniowe</h3> <ul> <li><strong>\<a></strong> - Może zawierać większość elementów liniowych i niektóre blokowe w HTML5 (ale nie inne \<a>)</li> <li><strong>\<span></strong>, <strong>\<em></strong>, <strong>\<strong></strong>, <strong>\<code></strong>, <strong>\<i></strong>, <strong>\<b></strong> - Powinny zawierać tylko tekst i inne elementy liniowe</li> <li><strong>\<br></strong>, <strong>\<img></strong>, <strong>\<input></strong> - Elementy puste, nie mogą zawierać żadnych dzieci</li> </ul> <p><strong>✨ Pro Tip:</strong> Jeśli nie jesteś pewien, jakie elementy mogą być zagnieżdżone w konkretnym elemencie, sprawdź oficjalną dokumentację HTML na <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element">MDN Web Docs</a> lub <a href="https://www.w3.org/TR/html52/dom.html#elements">W3C</a>.</p> <h2>🧪 Przykłady przed i po poprawkach</h2> <p>Najlepszym sposobem na zrozumienie, jak naprawiać błędy zagnieżdżenia, jest analiza konkretnych przykładów:</p> <h3>Przykład 1: Menu nawigacyjne</h3> <p><strong>Przed (z błędem):</strong></p> <pre><code class="language-html"><nav> Home <div>O nas</div> <div>Kontakt</div> </nav></code></pre> <p><strong>Błąd:</strong> Tekst i elementy div nie powinny być bezpośrednimi dziećmi nav.</p> <p><strong>Po (poprawione):</strong></p> <pre><code class="language-html"><nav> <ul> <li><a href="/">Home</a></li> <li><a href="/o-nas">O nas</a></li> <li><a href="/kontakt">Kontakt</a></li> </ul> </nav></code></pre> <h3>Przykład 2: Artykuł z obrazkami</h3> <p><strong>Przed (z błędem):</strong></p> <pre><code class="language-html"><article> <h2>Tytuł artykułu</h2> <p> Początek tekstu <div class="image-container"> <img src="obraz.jpg" alt="Opis obrazu"> </div> Dalsza część tekstu. </p> </article></code></pre> <p><strong>Błąd:</strong> Element div nie może być dzieckiem p.</p> <p><strong>Po (poprawione):</strong></p> <pre><code class="language-html"><article> <h2>Tytuł artykułu</h2> <p>Początek tekstu</p> <div class="image-container"> <img src="obraz.jpg" alt="Opis obrazu"> </div> <p>Dalsza część tekstu.</p> </article></code></pre> <h3>Przykład 3: Struktura formularza</h3> <p><strong>Przed (z błędem):</strong></p> <pre><code class="language-html"><form> <label>Imię</label> <label>Email</label> <input type="text"> <input type="email"> <button>Wyślij</button> </form></code></pre> <p><strong>Błąd:</strong> Brak powiązania między labelami i inputami.</p> <p><strong>Po (poprawione):</strong></p> <pre><code class="language-html"><form> <div class="form-group"> <label for="name">Imię</label> <input type="text" id="name"> </div> <div class="form-group"> <label for="email">Email</label> <input type="email" id="email"> </div> <button type="submit">Wyślij</button> </form></code></pre> <h3>Przykład 4: Lista z mieszaną zawartością</h3> <p><strong>Przed (z błędem):</strong></p> <pre><code class="language-html"><ul> <li>Pierwszy element</li> Tekst poza li <div>Element div</div> <li>Ostatni element</li> </ul></code></pre> <p><strong>Błąd:</strong> Tekst i div nie mogą być bezpośrednimi dziećmi ul.</p> <p><strong>Po (poprawione):</strong></p> <pre><code class="language-html"><ul> <li>Pierwszy element</li> <li>Tekst w odpowiednim miejscu</li> <li><div>Element div teraz w li</div></li> <li>Ostatni element</li> </ul></code></pre> <h2>❓ FAQ - Odpowiedzi na Twoje Pytania</h2> <p><strong>Czy wszystkie przeglądarki tak samo interpretują błędy zagnieżdżenia?</strong><br /> Nie. Różne przeglądarki mogą stosować różne strategie naprawy niepoprawnego kodu HTML. Dlatego strona z błędami może wyglądać inaczej w różnych przeglądarkach, co prowadzi do problemów z kompatybilnością.</p> <p><strong>Czy HTML5 jest bardziej elastyczny w kwestii zagnieżdżania niż starsze wersje?</strong><br /> Tak, HTML5 wprowadził pewne złagodzenia w porównaniu do wcześniejszych standardów. Na przykład, w HTML5 element \<a> może zawierać niektóre elementy blokowe, co wcześniej było niedozwolone.</p> <p><strong>Jak sprawdzić, czy mój framework generuje poprawny HTML?</strong><br /> Możesz użyć walidatora W3C na wyrenderowanej stronie (nie na szablonach). Pamiętaj jednak, że niektóre frameworki celowo generują kod, który wygląda na niepoprawny, ale działa poprawnie w kontekście danego narzędzia.</p> <p><strong>Czy błędy zagnieżdżenia wpływają na SEO?</strong><br /> Tak, mogą wpływać. Wyszukiwarki polegają na poprawnym, semantycznym HTML do zrozumienia struktury i treści strony. Poważne błędy mogą utrudnić indeksowanie i potencjalnie wpłynąć na pozycję w wynikach wyszukiwania.</p> <p><strong>Co zrobić, jeśli naprawienie błędu zagnieżdżenia psuje wygląd mojej strony?</strong><br /> Jeśli naprawa struktury HTML wpływa na wygląd strony, prawdopodobnie potrzebujesz także dostosować swój CSS. Zamiast polegać na niepoprawnej strukturze HTML, lepiej jest naprawić zarówno HTML, jak i CSS, aby zachować zgodność ze standardami.</p> <h2>🏁 Podsumowanie - Twórz poprawny, semantyczny HTML</h2> <p>Błędy zagnieżdżenia elementów HTML, choć czasem frustrujące, są stosunkowo łatwe do naprawienia, gdy zrozumiesz podstawowe zasady struktury HTML. Pamiętaj, że tworzenie kodu zgodnego ze standardami nie jest tylko kwestią "czystości" - ma realne zalety w postaci lepszej kompatybilności między przeglądarkami, dostępności i optymalizacji dla wyszukiwarek.</p> <p>Kluczem do unikania i naprawiania błędów zagnieżdżenia jest:</p> <ol> <li><strong>Poznanie zasad:</strong> Zrozumienie, które elementy mogą być zagnieżdżone w innych</li> <li><strong>Regularna walidacja:</strong> Sprawdzanie kodu za pomocą oficjalnego walidatora W3C</li> <li><strong>Właściwe narzędzia:</strong> Korzystanie z edytorów z podpowiedziami składni</li> <li><strong>Myślenie semantyczne:</strong> Używanie elementów HTML zgodnie z ich znaczeniem, a nie tylko wyglądem</li> </ol> <p>Pamiętaj, że poprawny, semantyczny HTML to fundament każdej dobrze działającej strony internetowej.</p> <h3>✅ Twoja Checklista:</h3> <ul> <li>🔍 Regularnie waliduj swój kod HTML</li> <li>🔄 Poznaj ograniczenia zagnieżdżania dla używanych elementów</li> <li>🔒 Stosuj edytory kodu z podpowiedziami składni HTML</li> <li>📝 Myśl o znaczeniu semantycznym każdego elementu</li> <li>📊 Testuj stronę w różnych przeglądarkach</li> </ul> <p><strong>🚀 Potrzebujesz pomocy z kodowaniem strony?</strong></p> <p>W <a href="https://iqhost.pl/oferta">IQHost</a> oferujemy nie tylko niezawodny hosting, ale także wsparcie techniczne, które pomoże Ci rozwiązać problemy z kodem HTML. Nasze serwery są zoptymalizowane do szybkiego działania stron internetowych, a nasz zespół ekspertów służy pomocą w kwestiach technicznych.</p> <p><em>Skontaktuj się z nami już dziś, aby dowiedzieć się, jak możemy pomóc Ci w tworzeniu doskonałych stron internetowych zgodnych ze standardami!</em></p> <!-- Tagi wpisu --> <div class="article-tags"> <h3>Kategorie i tagi</h3> <div class="tag-list"> <a href="https://dev2.iqhost.pl/blog?kategoria=Web+Development" class="tag"> <i class="fas fa-tag"></i> Web Development </a> <a href="https://dev2.iqhost.pl/blog?kategoria=Rozwi%C4%85zywanie+problem%C3%B3w" class="tag"> <i class="fas fa-tag"></i> Rozwiązywanie problemów </a> </div> </div> <!-- Ocena artykułu --> <div class="article-feedback"> <h3>Czy ten artykuł był pomocny?</h3> <div class="feedback-buttons"> <button class="article-feedback-button positive" data-post-id="jak-poprawic-blad-element-x-not-allowed-as-child-of-element-y-in-this-context" data-helpful="true"> <i class="fas fa-thumbs-up"></i> Tak </button> <button class="article-feedback-button negative" data-post-id="jak-poprawic-blad-element-x-not-allowed-as-child-of-element-y-in-this-context" data-helpful="false"> <i class="fas fa-thumbs-down"></i> Nie </button> </div> <div class="feedback-thank-you mt-4" style="display: none;"> <p>Dziękujemy za Twoją opinię! Twoja ocena pomoże nam ulepszać naszego bloga.</p> </div> </div> <div class="post-navigation"> <a href="https://dev2.iqhost.pl/blog" class="btn btn-outline-primary"> <i class="fas fa-arrow-left"></i> Wróć do listy wpisów </a> </div> <!-- Inline CTA — Vercel/Linear style --> <style> #bw-cta { --bw-primary: #3b82f6; --bw-cyan: #06b6d4; --bw-success: #10b981; --bw-text: #f8fafc; --bw-dim: #94a3b8; background: #0a0f1a; border: 1px solid rgba(255,255,255,0.08); border-radius: 20px; padding: 40px 36px; position: relative; overflow: hidden; margin: 40px 0; } body:not(.dark-mode) #bw-cta { background: #f8fafc; border-color: #e2e8f0; --bw-text: #0f172a; --bw-dim: #475569; } #bw-cta .bw-glow { position: absolute; top: -60px; right: -60px; width: 200px; height: 200px; background: radial-gradient(circle, rgba(59,130,246,0.1), transparent 70%); pointer-events: none; } #bw-cta .bw-glow-2 { position: absolute; bottom: -40px; left: -40px; width: 150px; height: 150px; background: radial-gradient(circle, rgba(6,182,212,0.08), transparent 70%); pointer-events: none; } #bw-cta .bw-grid { position: absolute; inset: 0; pointer-events: none; background-image: linear-gradient(rgba(59,130,246,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(59,130,246,0.03) 1px, transparent 1px); background-size: 30px 30px; mask-image: radial-gradient(ellipse at center, black 30%, transparent 80%); -webkit-mask-image: radial-gradient(ellipse at center, black 30%, transparent 80%); } #bw-cta .bw-inner { position: relative; z-index: 2; } #bw-cta .bw-top { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px; margin-bottom: 20px; } #bw-cta .bw-tag { display: inline-flex; align-items: center; gap: 6px; font-size: 0.65rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--bw-cyan); background: rgba(6,182,212,0.08); border: 1px solid rgba(6,182,212,0.15); padding: 4px 12px; border-radius: 6px; font-family: 'JetBrains Mono', monospace; } #bw-cta .bw-tag-dot { width: 5px; height: 5px; background: currentColor; border-radius: 50%; animation: bwBl 2s infinite; } @keyframes bwBl { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } } #bw-cta .bw-badges { display: flex; gap: 8px; flex-wrap: wrap; } #bw-cta .bw-badge { display: inline-flex; align-items: center; gap: 6px; font-size: 0.7rem; font-weight: 600; color: var(--bw-dim); background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.06); padding: 5px 12px; border-radius: 8px; } body:not(.dark-mode) #bw-cta .bw-badge { background: rgba(0,0,0,0.03); border-color: rgba(0,0,0,0.06); } #bw-cta .bw-badge svg { width: 14px; height: 14px; } #bw-cta .bw-badge-green svg { color: var(--bw-success); } #bw-cta .bw-badge-blue svg { color: var(--bw-primary); } #bw-cta .bw-badge-cyan svg { color: var(--bw-cyan); } #bw-cta .bw-title { font-size: 1.5rem; font-weight: 800; color: var(--bw-text); letter-spacing: -0.02em; margin-bottom: 10px; line-height: 1.2; } #bw-cta .bw-desc { font-size: 0.95rem; color: var(--bw-dim); line-height: 1.6; margin-bottom: 24px; max-width: 600px; } #bw-cta .bw-actions { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; } #bw-cta .bw-btn { display: inline-flex; align-items: center; gap: 10px; padding: 14px 32px; background: #101014; color: #fff; border: 1px solid var(--bw-primary); border-radius: 8px; font-weight: 700; font-size: 0.95rem; text-decoration: none; position: relative; overflow: hidden; transition: 0.3s; box-shadow: 0 8px 24px -8px rgba(59,130,246,0.35), inset 0 0 16px rgba(59,130,246,0.08); } body:not(.dark-mode) #bw-cta .bw-btn { background: var(--bw-primary); border-color: var(--bw-primary); box-shadow: 0 4px 16px rgba(59,130,246,0.25); } body:not(.dark-mode) #bw-cta .bw-btn:hover { box-shadow: 0 8px 24px rgba(59,130,246,0.35); } #bw-cta .bw-btn::after { content: ''; position: absolute; top: 0; left: -100%; width: 40px; height: 100%; background: linear-gradient(90deg, transparent, rgba(59,130,246,0.6), transparent); transform: skewX(-20deg); animation: bwL 3s infinite; } @keyframes bwL { 0% { left: -100%; } 20% { left: 200%; } 100% { left: 200%; } } #bw-cta .bw-btn:hover { transform: translateY(-1px); } #bw-cta .bw-btn svg { width: 16px; height: 16px; transition: transform 0.3s; } #bw-cta .bw-btn:hover svg { transform: translateX(3px); } #bw-cta .bw-ghost { color: var(--bw-dim); text-decoration: none; font-weight: 600; font-size: 0.9rem; display: inline-flex; align-items: center; gap: 6px; transition: 0.2s; } #bw-cta .bw-ghost:hover { color: var(--bw-text); } @media (max-width: 640px) { #bw-cta { padding: 28px 20px; } #bw-cta .bw-title { font-size: 1.25rem; } #bw-cta .bw-top { flex-direction: column; align-items: flex-start; } #bw-cta .bw-actions { flex-direction: column; width: 100%; } #bw-cta .bw-btn { width: 100%; justify-content: center; } } </style> <div id="bw-cta"> <div class="bw-glow"></div> <div class="bw-glow-2"></div> <div class="bw-grid"></div> <div class="bw-inner"> <div class="bw-top"> <div class="bw-tag"><span class="bw-tag-dot"></span> WordPress Hosting</div> <div class="bw-badges"> <span class="bw-badge bw-badge-green"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 7 13.5 15.5 8.5 10.5 2 17"/><polyline points="16 7 22 7 22 13"/></svg> 7× szybszy </span> <span class="bw-badge bw-badge-blue"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/><line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/></svg> NVMe SSD </span> <span class="bw-badge bw-badge-cyan"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg> LSCache </span> </div> </div> <div class="bw-title">Hosting zoptymalizowany pod WordPress</div> <p class="bw-desc">LiteSpeed + NVMe + wbudowany cache. Konfiguracja serwera dopasowana do WordPressa — bez ręcznego tuningowania. Strony ładują się w ułamku sekundy.</p> <div class="bw-actions"> <a href="https://dev2.iqhost.pl/hosting-wordpress" class="bw-btn"> Sprawdź pakiety <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg> </a> <a href="https://dev2.iqhost.pl/migracja" class="bw-ghost"> Darmowa migracja → </a> </div> </div> </div> </div> </div> <div class="article-sidebar"> <!-- Spis treści --> <div class="sidebar-section"> <h3 class="sidebar-title"><i class="fas fa-list"></i> Spis treści</h3> <div class="sidebar-toc"> <ul class="simple-toc-list" id="toc-right-menu" role="navigation" aria-label="Spis treści"> <!-- Spis treści zostanie wygenerowany przez JavaScript --> </ul> </div> </div> <!-- Kategorie --> <div class="sidebar-section"> <h3 class="sidebar-title"><i class="fas fa-folder"></i> Kategorie</h3> <ul class="sidebar-categories"> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Bezpiecze%C5%84stwo"> Bezpieczeństwo </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Hosting"> Hosting </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Serwery"> Serwery </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Poradniki"> Poradniki </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=WordPress"> WordPress </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Chmura"> Chmura </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Linux"> Linux </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Administracja"> Administracja </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=blog"> blog </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Infrastruktura"> Infrastruktura </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Technologia"> Technologia </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Wirtualizacja"> Wirtualizacja </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Narz%C4%99dzia"> Narzędzia </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Domeny"> Domeny </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Programowanie"> Programowanie </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Administracja+Serwerem"> Administracja Serwerem </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=DevOps"> DevOps </a> </li> <li class="sidebar-category-item active"> <a href="https://dev2.iqhost.pl/blog?kategoria=Rozwi%C4%85zywanie+problem%C3%B3w"> Rozwiązywanie problemów </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Optymalizacja"> Optymalizacja </a> </li> <li class="sidebar-category-item "> <a href="https://dev2.iqhost.pl/blog?kategoria=Administracja+serwerem"> Administracja serwerem </a> </li> </ul> </div> <!-- Podobne wpisy (widoczne tylko na dużych ekranach) --> <div class="sidebar-section d-none d-lg-block"> <h3 class="sidebar-title">Podobne artykuły</h3> <div class="sidebar-posts"> <div class="sidebar-post-item"> <a href="https://dev2.iqhost.pl/blog/jak-naprawic-blad-pliki-cookie-sa-blokowane-w-wordpressie" class="sidebar-post-link"> <div class="sidebar-post-title">Jak naprawić błąd "Pliki cookie są blokowane" w WordPressie? Kompleksowy poradnik</div> <div class="sidebar-post-meta"> <span class="post-date">03.05.2025</span> </div> </a> </div> <div class="sidebar-post-item"> <a href="https://dev2.iqhost.pl/blog/jak-stworzyc-wlasna-skorke-w-wordpress-krok-po-kroku" class="sidebar-post-link"> <div class="sidebar-post-title">Jak stworzyć własną skórkę w WordPress krok po kroku - kompletny przewodnik</div> <div class="sidebar-post-meta"> <span class="post-date">01.05.2025</span> </div> </a> </div> <div class="sidebar-post-item"> <a href="https://dev2.iqhost.pl/blog/python-skrypt-do-aplikacji-web-na-hostingu" class="sidebar-post-link"> <div class="sidebar-post-title">Jak stworzyć i wdrożyć skrypt Python dla aplikacji webowej na hostingu</div> <div class="sidebar-post-meta"> <span class="post-date">01.05.2025</span> </div> </a> </div> </div> </div> <!-- Baner promocyjny - skopiowane z post-view.php --> <!-- Promo sidebar — Vercel/Linear style --> <style> #bp-promo { --bp-primary: #3b82f6; --bp-cyan: #06b6d4; --bp-text: #f8fafc; --bp-dim: #94a3b8; background: #0a0f1a; border: 1px solid rgba(255,255,255,0.08); border-radius: 16px; padding: 28px 24px; position: relative; overflow: hidden; margin-bottom: 24px; } body:not(.dark-mode) #bp-promo { background: #f8fafc; border-color: #e2e8f0; } body:not(.dark-mode) #bp-promo .bp-tag { color: #3b82f6; background: rgba(59,130,246,0.08); border-color: rgba(59,130,246,0.15); } body:not(.dark-mode) #bp-promo .bp-title { color: #0f172a; } body:not(.dark-mode) #bp-promo .bp-desc { color: #475569; } body:not(.dark-mode) #bp-promo .bp-price { color: #0f172a; } body:not(.dark-mode) #bp-promo .bp-price-sub { color: #64748b; } body:not(.dark-mode) #bp-promo .bp-features li { color: #475569; } body:not(.dark-mode) #bp-promo .bp-features li::before { color: #10b981; } #bp-promo .bp-glow { position: absolute; top: -40px; right: -40px; width: 120px; height: 120px; background: radial-gradient(circle, rgba(59,130,246,0.12), transparent 70%); pointer-events: none; } #bp-promo .bp-tag { display: inline-flex; align-items: center; gap: 6px; font-size: 0.65rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--bp-cyan); background: rgba(6,182,212,0.08); border: 1px solid rgba(6,182,212,0.15); padding: 4px 10px; border-radius: 6px; margin-bottom: 16px; font-family: 'JetBrains Mono', monospace; } #bp-promo .bp-tag-dot { width: 5px; height: 5px; background: currentColor; border-radius: 50%; } #bp-promo .bp-title { font-size: 1.15rem; font-weight: 800; color: var(--bp-text); letter-spacing: -0.02em; margin-bottom: 8px; line-height: 1.2; } #bp-promo .bp-desc { font-size: 0.82rem; color: var(--bp-dim); line-height: 1.5; margin-bottom: 16px; } #bp-promo .bp-price { font-size: 1.6rem; font-weight: 900; color: var(--bp-text); letter-spacing: -0.03em; margin-bottom: 4px; font-family: 'JetBrains Mono', monospace; } #bp-promo .bp-price-sub { font-size: 0.75rem; color: var(--bp-dim); margin-bottom: 16px; } #bp-promo .bp-features { list-style: none; padding: 0; margin: 0 0 20px; } #bp-promo .bp-features li { font-size: 0.8rem; color: var(--bp-dim); padding: 4px 0; display: flex; align-items: center; gap: 8px; } #bp-promo .bp-features li::before { content: '✓'; color: #10b981; font-weight: 700; font-size: 0.75rem; } #bp-promo .bp-btn { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; padding: 12px 0; background: #101014; color: #fff; border: 1px solid var(--bp-primary); border-radius: 8px; font-weight: 700; font-size: 0.9rem; text-decoration: none; position: relative; overflow: hidden; transition: 0.3s; box-shadow: 0 4px 16px -4px rgba(59,130,246,0.3), inset 0 0 12px rgba(59,130,246,0.08); } #bp-promo .bp-btn::after { content: ''; position: absolute; top: 0; left: -100%; width: 40px; height: 100%; background: linear-gradient(90deg, transparent, rgba(59,130,246,0.6), transparent); transform: skewX(-20deg); animation: bpLaser 3s infinite; } @keyframes bpLaser { 0% { left: -100%; } 20% { left: 200%; } 100% { left: 200%; } } #bp-promo .bp-btn:hover { background: rgba(59,130,246,0.1); transform: translateY(-1px); box-shadow: 0 8px 24px -4px rgba(59,130,246,0.4), inset 0 0 20px rgba(59,130,246,0.12); } #bp-promo .bp-btn svg { width: 16px; height: 16px; transition: transform 0.3s; } #bp-promo .bp-btn:hover svg { transform: translateX(3px); } </style> <div class="sidebar-section" id="bp-promo"> <div class="bp-glow"></div> <div class="bp-tag"><span class="bp-tag-dot"></span> LiteSpeed + NVMe</div> <div class="bp-title">Hosting WordPress</div> <div class="bp-desc">Serwery zoptymalizowane pod WordPress z wbudowanym LSCache.</div> <div class="bp-price">49,14 zł<span style="font-size:0.5em;font-weight:400;color:var(--bp-dim)">/rok</span></div> <div class="bp-price-sub">Pakiet HS5 · 5 GB NVMe · 5 domen</div> <ul class="bp-features"> <li>Darmowy SSL Let's Encrypt</li> <li>Backup 30 dni</li> <li>Imunify360 ochrona</li> <li>Transfer bez limitu</li> </ul> <a href="https://dev2.iqhost.pl/hosting" class="bp-btn"> Sprawdź pakiety <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg> </a> </div> </div> </div> </div> </section> <!-- CTA — Blog Bento Layout --> <style> #blog-cta { --bc-primary: #3b82f6; --bc-cyan: #06b6d4; --bc-success: #10b981; --bc-glass-bg: rgba(255,255,255,0.03); --bc-glass-border: rgba(255,255,255,0.06); --bc-text-main: #f8fafc; --bc-text-dim: #94a3b8; --bc-ease: cubic-bezier(0.34, 1.56, 0.64, 1); position: relative; overflow: hidden; background: #050810; padding: 100px 0 120px; } body:not(.dark-mode) #blog-cta { background: #050810; } #blog-cta.cta-section { background-color: transparent; background-image: none; } #blog-cta.cta-section::before { display: none; } #blog-cta .bc-grid-bg { position: absolute; inset: 0; pointer-events: none; z-index: 0; background-image: linear-gradient(rgba(59,130,246,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(59,130,246,0.03) 1px, transparent 1px); background-size: 60px 60px; mask-image: radial-gradient(ellipse 80% 60% at 50% 40%, black 20%, transparent 80%); -webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 40%, black 20%, transparent 80%); } #blog-cta .bc-glow { position: absolute; border-radius: 50%; filter: blur(100px); z-index: 0; pointer-events: none; } #blog-cta .bc-g1 { width: 500px; height: 500px; background: rgba(59,130,246,0.08); top: -100px; left: -100px; animation: bcF 12s ease-in-out infinite; } #blog-cta .bc-g2 { width: 400px; height: 400px; background: rgba(6,182,212,0.06); bottom: -80px; right: -80px; animation: bcF 15s ease-in-out infinite reverse; } @keyframes bcF { 0%,100% { transform: translate(0,0); } 50% { transform: translate(30px,-20px); } } #blog-cta .bc-inner { max-width: 1300px; margin: 0 auto; padding: 0 40px; position: relative; z-index: 2; } #blog-cta .bc-bento { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center; } /* Left */ #blog-cta .bc-content { position: relative; } #blog-cta .bc-pill { display: inline-flex; align-items: center; padding: 6px 16px; background: rgba(59,130,246,0.1); border: 1px solid rgba(59,130,246,0.2); border-radius: 99px; font-size: 0.75rem; font-weight: 700; color: var(--bc-primary); margin-bottom: 24px; letter-spacing: 0.08em; text-transform: uppercase; box-shadow: 0 0 30px rgba(59,130,246,0.15); } #blog-cta .bc-pill-dot { width: 6px; height: 6px; background: currentColor; border-radius: 50%; margin-right: 10px; animation: bcBl 2s infinite; } @keyframes bcBl { 0%,100% { opacity: 1; } 50% { opacity: 0.5; } } #blog-cta .bc-heading { font-size: 3rem; line-height: 1.1; font-weight: 800; letter-spacing: -0.03em; margin-bottom: 20px; color: var(--bc-text-main); } #blog-cta .bc-hg { background: linear-gradient(135deg, #fff 30%, #94a3b8 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } #blog-cta .bc-ha { background: linear-gradient(90deg, #3b82f6, #2dd4bf); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } #blog-cta .bc-desc { font-size: 1.1rem; line-height: 1.7; color: var(--bc-text-dim); max-width: 480px; margin-bottom: 32px; } /* Buttons */ #blog-cta .bc-buttons { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; margin-bottom: 32px; } #blog-cta .bc-btn-laser { background: #101014; color: #fff; text-decoration: none; padding: 16px 36px; border-radius: 8px; font-weight: 700; font-size: 1rem; display: inline-flex; align-items: center; gap: 12px; border: 1px solid var(--bc-primary); position: relative; overflow: hidden; transition: 0.3s; cursor: pointer; box-shadow: 0 10px 30px -10px rgba(59,130,246,0.4), inset 0 0 20px rgba(59,130,246,0.1); } #blog-cta .bc-btn-laser::after { content: ''; position: absolute; top: 0; left: -100%; width: 50px; height: 100%; background: linear-gradient(90deg, transparent, rgba(59,130,246,0.7), transparent); transform: skewX(-20deg); animation: bcL 3s infinite; } @keyframes bcL { 0% { left: -100%; } 20% { left: 200%; } 100% { left: 200%; } } #blog-cta .bc-btn-laser:hover { background: rgba(59,130,246,0.1); box-shadow: 0 15px 40px -5px rgba(59,130,246,0.4), inset 0 0 30px rgba(59,130,246,0.2); transform: scale(1.02); } #blog-cta .bc-btn-laser .bc-icon { width: 18px; height: 18px; transition: transform 0.3s; } #blog-cta .bc-btn-laser:hover .bc-icon { transform: translateX(4px); } #blog-cta .bc-btn-ghost { color: #a1a1aa; text-decoration: none; font-weight: 600; font-size: 1rem; display: inline-flex; align-items: center; gap: 8px; transition: 0.2s; cursor: pointer; background: none; border: none; padding: 0; } #blog-cta .bc-btn-ghost:hover { color: #fff; text-shadow: 0 0 10px rgba(255,255,255,0.5); } /* Info cards */ #blog-cta .bc-info-row { display: flex; gap: 16px; } #blog-cta .bc-info-card { flex: 1; display: flex; align-items: center; gap: 14px; padding: 16px 20px; background: var(--bc-glass-bg); border: 1px solid var(--bc-glass-border); border-radius: 14px; backdrop-filter: blur(10px); transition: all 0.3s var(--bc-ease); color: inherit; } #blog-cta .bc-info-card:hover { background: rgba(255,255,255,0.06); border-color: rgba(59,130,246,0.2); transform: translateY(-3px); box-shadow: 0 10px 30px rgba(0,0,0,0.15); } #blog-cta .bc-ii { width: 42px; height: 42px; border-radius: 10px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } #blog-cta .bc-ii.bc-ii-articles { background: rgba(59,130,246,0.15); color: var(--bc-primary); } #blog-cta .bc-ii.bc-ii-topics { background: rgba(16,185,129,0.15); color: var(--bc-success); } #blog-cta .bc-ii svg { width: 20px; height: 20px; } #blog-cta .bc-il { font-weight: 700; font-size: 0.9rem; color: var(--bc-text-main); margin-bottom: 2px; } #blog-cta .bc-iv { font-size: 0.8rem; color: var(--bc-text-dim); } /* Right: Visual */ #blog-cta .bc-visual { position: relative; display: flex; align-items: center; justify-content: center; } #blog-cta .bc-img-frame { position: relative; border-radius: 20px; overflow: hidden; border: 1px solid var(--bc-glass-border); box-shadow: 0 20px 60px rgba(0,0,0,0.3), 0 0 0 1px rgba(255,255,255,0.03); transition: transform 0.5s var(--bc-ease); } #blog-cta .bc-img-frame:hover { transform: scale(1.02) translateY(-5px); } #blog-cta .bc-img-frame img { display: block; width: 100%; height: auto; filter: brightness(1.05) contrast(1.05); } #blog-cta .bc-img-overlay { position: absolute; inset: 0; background: linear-gradient(180deg, transparent 40%, rgba(5,8,16,0.6) 100%); pointer-events: none; } /* Floating badges */ #blog-cta .bc-badge { position: absolute; display: flex; align-items: center; gap: 10px; padding: 12px 18px; background: rgba(15,23,42,0.85); backdrop-filter: blur(16px); border: 1px solid var(--bc-glass-border); border-radius: 14px; z-index: 5; box-shadow: 0 10px 30px rgba(0,0,0,0.25); animation: bcBd 4s ease-in-out infinite; } #blog-cta .bc-badge-tl { top: 20px; left: -30px; } #blog-cta .bc-badge-br { bottom: 30px; right: -30px; animation-delay: 2s; } @keyframes bcBd { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-8px); } } #blog-cta .bc-bi { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } #blog-cta .bc-bi.bc-bi-posts { background: rgba(59,130,246,0.15); color: var(--bc-primary); } #blog-cta .bc-bi.bc-bi-cat { background: rgba(6,182,212,0.15); color: var(--bc-cyan); } #blog-cta .bc-bi svg { width: 18px; height: 18px; } #blog-cta .bc-bn { font-size: 1.1rem; font-weight: 800; color: var(--bc-text-main); line-height: 1.2; } #blog-cta .bc-bl { font-size: 0.7rem; color: var(--bc-text-dim); text-transform: uppercase; letter-spacing: 0.06em; } /* Responsive */ @media (max-width: 1000px) { #blog-cta .bc-bento { grid-template-columns: 1fr; text-align: center; gap: 50px; } #blog-cta .bc-content { display: flex; flex-direction: column; align-items: center; } #blog-cta .bc-desc { margin-left: auto; margin-right: auto; } #blog-cta .bc-buttons { justify-content: center; } #blog-cta .bc-info-row { justify-content: center; } #blog-cta .bc-badge-tl { left: 10px; } #blog-cta .bc-badge-br { right: 10px; } } @media (max-width: 600px) { #blog-cta { padding: 60px 0 80px; } #blog-cta .bc-inner { padding: 0 20px; } #blog-cta .bc-heading { font-size: 2.2rem; } #blog-cta .bc-buttons { flex-direction: column; align-items: center; } #blog-cta .bc-btn-laser { width: 100%; justify-content: center; } #blog-cta .bc-info-row { flex-direction: column; } #blog-cta .bc-badge { display: none; } } </style> <section id="blog-cta" class="cta-section"> <div class="bc-grid-bg"></div> <div class="bc-glow bc-g1"></div> <div class="bc-glow bc-g2"></div> <div class="bc-inner"> <div class="bc-bento"> <div class="bc-content" data-aos="fade-right"> <div class="bc-pill"> <span class="bc-pill-dot"></span> Blog IQHost </div> <h2 class="bc-heading"> <span class="bc-hg">Wiedza, która</span><br> <span class="bc-ha">napędza Twój biznes</span> </h2> <p class="bc-desc"> Artykuły, poradniki i case study ze świata hostingu, bezpieczeństwa i technologii webowych. Pisane przez praktyków, nie copywriterów. </p> <div class="bc-buttons"> <a href="https://dev2.iqhost.pl/blog" class="bc-btn-laser"> Przeglądaj artykuły <svg class="bc-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg> </a> <a href="https://dev2.iqhost.pl/baza-wiedzy" class="bc-btn-ghost"> Baza Wiedzy → </a> </div> <div class="bc-info-row"> <div class="bc-info-card"> <div class="bc-ii bc-ii-articles"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20"/></svg> </div> <div> <div class="bc-il">300+ artykułów</div> <div class="bc-iv">Hosting, domeny, WordPress</div> </div> </div> <div class="bc-info-card"> <div class="bc-ii bc-ii-topics"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg> </div> <div> <div class="bc-il">Nowe co tydzień</div> <div class="bc-iv">Aktualne treści techniczne</div> </div> </div> </div> </div> <div class="bc-visual" data-aos="fade-left"> <div class="bc-badge bc-badge-tl"> <div class="bc-bi bc-bi-posts"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg> </div> <div> <div class="bc-bn">300+</div> <div class="bc-bl">Artykułów</div> </div> </div> <div class="bc-img-frame"> <img src="https://dev2.iqhost.pl/assets/images/blog-cta-graphic.png?v=1772125382" alt="Blog IQHost — artykuły i poradniki hostingowe" width="768" height="512" loading="lazy"> <div class="bc-img-overlay"></div> </div> <div class="bc-badge bc-badge-br"> <div class="bc-bi bc-bi-cat"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg> </div> <div> <div class="bc-bn">15+</div> <div class="bc-bl">Kategorii</div> </div> </div> </div> </div> </div> </section> <!-- Skrypt do generowania spisu treści - NOWY DESIGN z hierarchią --> <script> document.addEventListener('DOMContentLoaded', function() { // Funkcja do generowania spisu treści - prosta wersja function generateTableOfContents() { const contentDiv = document.querySelector('.article-text'); if (!contentDiv) return; const headings = contentDiv.querySelectorAll('h2, h3'); if (headings.length === 0) { const tocSection = document.querySelector('.sidebar-section'); if (tocSection) tocSection.style.display = 'none'; return; } const tocList = document.getElementById('toc-right-menu'); if (!tocList) return; tocList.innerHTML = ''; // Filtruj nagłówki do pominięcia const skipPatterns = ['spis treści', 'spis tresci', 'table of contents', 'kategorie i tagi', 'czy ten artykuł']; headings.forEach(function(heading, index) { const headingText = heading.textContent.toLowerCase().trim(); // Pomiń nagłówki pasujące do wzorców for (const pattern of skipPatterns) { if (headingText.includes(pattern)) return; } // Dodaj ID do nagłówka jeśli nie ma if (!heading.id) { const slug = heading.textContent .toLowerCase() .replace(/[^\w\s-]/g, '') .replace(/\s+/g, '-') .substring(0, 50); heading.id = slug || ('heading-' + index); } const listItem = document.createElement('li'); listItem.className = 'toc-item toc-' + heading.tagName.toLowerCase(); const link = document.createElement('a'); link.href = '#' + heading.id; link.className = 'toc-link'; // Tekst - usuń emoji i skróć let displayText = heading.textContent.trim(); displayText = displayText.replace(/^[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}⚡📚💻🚀🛠️📦🔐🌐❓🏁✨⚙️✅🗺️👍🔍🛒📈🚫📧🔄🎯]+\s*/gu, ''); if (displayText.length > 40) { link.title = displayText; displayText = displayText.substring(0, 37) + '...'; } link.textContent = displayText; // Smooth scroll link.addEventListener('click', function(e) { e.preventDefault(); const targetElement = document.getElementById(heading.id); if (targetElement) { window.scrollTo({ top: targetElement.offsetTop - 100, behavior: 'smooth' }); document.querySelectorAll('.toc-link').forEach(l => l.classList.remove('active')); this.classList.add('active'); } }); listItem.appendChild(link); tocList.appendChild(listItem); }); } // Funkcja do obsługi przełącznika sidebara function setupSidebarToggle() { console.log('=== setupSidebarToggle START ==='); const sidebarToggle = document.getElementById('sidebar-toggle'); console.log('sidebarToggle element:', sidebarToggle); if (!sidebarToggle) { console.error('ERROR: Sidebar toggle button NOT FOUND!'); return; } const sidebar = document.querySelector('.article-sidebar'); const mainContent = document.querySelector('.article-main'); console.log('sidebar element:', sidebar); console.log('mainContent element:', mainContent); if (!sidebar || !mainContent) { console.error('ERROR: Sidebar or mainContent NOT FOUND!'); return; } let isHidden = false; sidebarToggle.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); console.log('=== CLICK! isHidden before:', isHidden); isHidden = !isHidden; console.log('=== isHidden after toggle:', isHidden); if (isHidden) { // Ukryj sidebar.style.cssText = 'display: none !important; visibility: hidden !important; opacity: 0 !important;'; mainContent.style.cssText = 'grid-column: 1 / -1 !important; max-width: 100% !important;'; console.log('>>> UKRYWAM SIDEBAR'); } else { // Pokaż sidebar.style.cssText = ''; mainContent.style.cssText = ''; console.log('>>> POKAZUJĘ SIDEBAR'); } const textSpan = sidebarToggle.querySelector('.text'); if (textSpan) { textSpan.textContent = isHidden ? 'Pokaż panel boczny' : 'Ukryj panel boczny'; } }); console.log('=== Sidebar toggle INITIALIZED ==='); } // Funkcja do obsługi przycisków oceny artykułu function setupFeedbackButtons() { const feedbackButtons = document.querySelectorAll('.article-feedback-button'); if (feedbackButtons.length === 0) return; feedbackButtons.forEach(function(button) { button.addEventListener('click', function() { // Tutaj można dodać logikę zapisu oceny artykułu, np. przez AJAX // Ukryj przyciski i pokaż podziękowanie const feedbackButtonsContainer = button.closest('.feedback-buttons'); const feedbackThankYou = button.closest('.article-feedback').querySelector('.feedback-thank-you'); if (feedbackButtonsContainer) feedbackButtonsContainer.style.display = 'none'; if (feedbackThankYou) feedbackThankYou.style.display = 'block'; }); }); } // Funkcja do zaznaczania aktywnej sekcji podczas przewijania - prosta wersja function setupScrollSpy() { const headings = document.querySelectorAll('.article-text h2, .article-text h3'); const tocLinks = document.querySelectorAll('.toc-link'); if (headings.length === 0 || tocLinks.length === 0) return; let ticking = false; window.addEventListener('scroll', function() { if (!ticking) { window.requestAnimationFrame(function() { const scrollPosition = window.scrollY; // Znajdź aktywny nagłówek let currentHeading = null; headings.forEach(function(heading) { if (scrollPosition >= heading.offsetTop - 150) { currentHeading = heading; } }); // Zaznacz aktywny link if (currentHeading) { tocLinks.forEach(function(link) { link.classList.remove('active'); if (link.getAttribute('href') === '#' + currentHeading.id) { link.classList.add('active'); } }); } ticking = false; }); ticking = true; } }); } // Inicjalizacja wszystkich funkcji generateTableOfContents(); setupSidebarToggle(); setupFeedbackButtons(); setupScrollSpy(); // Dodatkowa inicjalizacja scrollspy po załadowaniu wszystkich obrazów window.addEventListener('load', function() { setupScrollSpy(); }); }); </script> <!-- Highlight.js tylko dla bloga --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> <script src="https://dev2.iqhost.pl/assets/js/blog-article.js"></script> <!-- Skrypt dodający klasy do artykułu --> <script> document.addEventListener('DOMContentLoaded', function() { // Dodaj klasę blog-article-content do treści artykułu const articleContent = document.querySelector('.article-text'); if (articleContent) { articleContent.classList.add('blog-article-content'); } // Ukryj nagłówek "Spis treści" w treści artykułu (bo mamy go w sidebarze) const headings = articleContent ? articleContent.querySelectorAll('h2, h3') : []; headings.forEach(heading => { const text = heading.textContent.toLowerCase(); if (text.includes('spis treści') || text.includes('spis tresci') || text.includes('table of contents') || text.includes('mapa drogowa')) { // Ukryj nagłówek i następny element (jeśli to separator lub pusty element) heading.style.display = 'none'; const nextEl = heading.nextElementSibling; if (nextEl && (nextEl.tagName === 'HR' || nextEl.innerHTML.trim() === '' || nextEl.innerHTML.includes('<!-- '))) { nextEl.style.display = 'none'; } } }); // Ukryj inline TOC - listę z linkami nawigacyjnymi w treści (zachowujemy tylko sidebar TOC) if (articleContent) { const allLists = articleContent.querySelectorAll('ul, ol'); allLists.forEach(list => { const links = list.querySelectorAll('a'); // Sprawdź czy większość linków to anchory wewnętrzne (#) let anchorCount = 0; links.forEach(link => { if (link.href && link.href.includes('#') && !link.href.includes('http')) { anchorCount++; } else if (link.getAttribute('href') && link.getAttribute('href').startsWith('#')) { anchorCount++; } }); // Jeśli lista ma więcej niż 10 linków i większość to anchory - to prawdopodobnie inline TOC if (links.length > 10 && anchorCount > links.length * 0.7) { list.style.display = 'none'; // Ukryj też poprzedni HR jeśli istnieje const prevEl = list.previousElementSibling; if (prevEl && prevEl.tagName === 'HR') { prevEl.style.display = 'none'; } // Ukryj następny HR jeśli istnieje const nextEl = list.nextElementSibling; if (nextEl && nextEl.tagName === 'HR') { nextEl.style.display = 'none'; } } }); } // Dodatkowe usprawnienia dla spisu treści const tocContainer = document.querySelector('.sidebar-toc'); if (tocContainer) { // Usuń wszystkie zbyt długie wcięcia const tocLinks = tocContainer.querySelectorAll('.toc-link'); tocLinks.forEach(link => { // Jeśli tekst jest zbyt długi, przytnij go if (link.textContent.length > 40) { link.title = link.textContent; // Pełna nazwa jako tooltip link.textContent = link.textContent.substring(0, 37) + '...'; } }); } // Naprawa ID nagłówków dla poprawnego działania spisu treści // Mapa dla nagłówków/ID w markdown, dokładnie takich jak w pliku .md const headingIdMap = { '\ud83c\uddf5\ud83c\uddf1 Dlaczego .pl Króluje w Polskim Internecie?': 'dlaczego-pl', '\ud83d\udc4d Krok 1: Nazwa Domeny Idealna - Jak Ją Stworzyć?': 'krok1', '\ud83d\udd0d Krok 2: Dostępność i Sekrety WHOIS': 'krok2', '\ud83d\udeab Najczęstsze Błędy Przy Rejestracji': 'common-mistakes', '\ud83d\uded2 Krok 3: Rejestracja Krok Po Kroku': 'krok3', '\u2705 Twoja Checklista Rejestracji Domeny .pl': 'checklist', '\u2699\ufe0f Krok 4: DNS & DNSSEC - Techniczne Serce Domeny': 'krok4', '\ud83d\udce7 Krok 5: SPF, DKIM, DMARC - Zadbaj o Dostarczalność E-maili': 'krok5', '\ud83d\udd04 Krok 6: Zarządzanie Cyklem Życia': 'krok6', '\ud83d\udcc8 Krok 7: Pro SEO Tricki dla Domeny .pl': 'krok7', '\u2753 FAQ - Odpowiedzi na Twoje Pytania': 'faq', '\ud83c\udfc1 Podsumowanie - Gotowy na Sukces?': 'podsumowanie' }; // Znajdź wszystkie nagłówki h2 w artykule const h2s = document.querySelectorAll('.article-text h2'); h2s.forEach(heading => { const text = heading.textContent.trim(); if (headingIdMap[text]) { heading.id = headingIdMap[text]; console.log('Ustawiono ID:', heading.id, 'dla nagłówka:', text); } }); // Również naprawiamy linki w spisie treści setTimeout(() => { const tocLinks = document.querySelectorAll('.toc-link'); tocLinks.forEach(link => { const text = link.textContent.trim(); Object.entries(headingIdMap).forEach(([headingText, id]) => { // Sprawdź, czy tekst linku jest częścią tekstu nagłówka po usunięciu emoji const cleanHeadingText = headingText.replace(/^[\u{1F300}-\u{1F6FF}\u{2600}-\u{26FF}\s]+/u, '').trim(); if (cleanHeadingText.includes(text)) { link.href = '#' + id; console.log('Naprawiono link:', link.textContent, 'href:', link.href); } }); }); }, 500); }); </script> <!-- Stopka --> <footer class="footer"> <div class="container"> <!-- 5 kolumn w jednym rzędzie --> <div class="footer-main-grid"> <!-- Kolumna 1: Brand --> <div class="footer-column footer-brand-column"> <img src="https://dev2.iqhost.pl/assets/images/logo-full-iqhost-white.png?v=1772125382" alt="IQHost.pl Logo" class="footer-logo" width="140" height="auto"> <p class="footer-tagline">Tworzymy hosting, który szanuje Twój czas i budżet. Stała cena odnowienia i rozliczenie roczne to nasza standardowa praktyka.</p> <div class="footer-badges"> <div class="badge-item"> <i class="fas fa-shield-alt"></i> <span>100% Bezpieczeństwa</span> </div> <div class="badge-item"> <i class="fas fa-headset"></i> <span>Szybki Support</span> </div> <div class="badge-item"> <i class="fas fa-calendar-check"></i> <span>30 dni gwarancji</span> </div> </div> </div> <!-- Kolumna 2: Migracja --> <div class="footer-column"> <h3>Migracja</h3> <ul class="footer-links"> <li><a href="https://dev2.iqhost.pl/migracja">Proces migracji</a></li> <li><a href="https://dev2.iqhost.pl/migracja#benefits">Korzyści</a></li> <li><a href="https://dev2.iqhost.pl/migracja#steps">Jak przebiega migracja</a></li> <li><a href="https://dev2.iqhost.pl/migracja#faq">FAQ</a></li> <li><a href="https://dev2.iqhost.pl/migracja#explanation">Dlaczego warto</a></li> <li><a href="https://dev2.iqhost.pl#plans">Cennik hostingu</a></li> </ul> </div> <!-- Kolumna 3: Usługi --> <div class="footer-column"> <h3>Usługi</h3> <ul class="footer-links"> <li><a href="https://dev2.iqhost.pl">Hosting WWW</a></li> <li><a href="https://dev2.iqhost.pl#plans">Cennik hostingu</a></li> <li><a href="https://dev2.iqhost.pl/domeny">Domeny internetowe</a></li> <li><a href="https://dev2.iqhost.pl/program-partnerski">Program partnerski</a></li> <li><a href="https://panel.iqgroup.pl">Panel klienta</a></li> <li><a href="https://monitor.iqhs.eu/?route=publicpage&key=QAyt2V7Yi2SRTzqNbY" target="_blank">Monitoring serwerów</a></li> </ul> </div> <!-- Kolumna 4: Wsparcie --> <div class="footer-column"> <h3>Wsparcie</h3> <ul class="footer-links"> <li><a href="https://dev2.iqhost.pl/baza-wiedzy">Baza wiedzy</a></li> <li><a href="https://dev2.iqhost.pl/blog">Blog</a></li> <li><a href="https://dev2.iqhost.pl/pomoc">Centrum pomocy</a></li> <li><a href="https://monitor.iqhs.eu/?route=publicpage&key=QAyt2V7Yi2SRTzqNbY" target="_blank">Status serwerów</a></li> <li><a href="https://dev2.iqhost.pl/kontakt">Kontakt</a></li> <li><a href="https://panel.iqgroup.pl/submitticket.php?step=2&deptid=1" target="_blank">Zgłoś problem</a></li> </ul> </div> <!-- Kolumna 5: Firma --> <div class="footer-column"> <h3>Firma</h3> <ul class="footer-links"> <li><a href="https://dev2.iqhost.pl/o-nas">O nas</a></li> <li><a href="https://dev2.iqhost.pl/kontakt">Kontakt</a></li> <li><a href="https://dev2.iqhost.pl/regulamin">Regulamin</a></li> <li><a href="https://dev2.iqhost.pl/polityka-prywatnosci">Polityka prywatności</a></li> <li><a href="https://dev2.iqhost.pl/polityka-cookies">Polityka cookies</a></li> <li><a href="https://dev2.iqhost.pl/dokumenty-prawne">Wszystkie dokumenty</a></li> </ul> </div> </div> <!-- Newsletter Section --> <div class="footer-newsletter"> <div class="newsletter-content"> <h3>Bądź pierwszy. Odbieraj ekskluzywne porady.</h3> </div> <div class="newsletter-right"> <form class="newsletter-form" id="footer-newsletter-form" action="/newsletter/subscribe.php" method="post"> <input type="email" name="email" placeholder="Twój adres e-mail" aria-label="Adres e-mail do newslettera" required> <button type="submit" class="newsletter-button"> <i class="fas fa-paper-plane"></i> Subskrybuj </button> <input type="hidden" name="consent" value="1"> <input type="hidden" name="g-recaptcha-response" id="newsletter-recaptcha-response"> </form> <small class="newsletter-hint">Porady techniczne, dostęp do nowości przed premierą, ekskluzywne zniżki. Zero spamu, tylko wartościowe treści.</small> <div id="newsletter-result" class="newsletter-result" style="display: none;"></div> </div> </div> <!-- Dolna część stopki --> <div class="footer-bottom"> <div class="footer-bottom-left"> <p>© 2026 IQhost.pl - Marka Iqgroup.pl <span class="separator">|</span> NIP: 9910389442 <span class="separator">|</span> REGON: 161561682</p> </div> <div class="footer-bottom-center"> <a href="https://dev2.iqhost.pl/regulamin">Regulamin</a> <a href="https://dev2.iqhost.pl/polityka-prywatnosci">Polityka prywatności</a> <a href="https://dev2.iqhost.pl/polityka-cookies">Polityka cookies</a> <a href="https://dev2.iqhost.pl/rodo">RODO</a> <a href="https://dev2.iqhost.pl/regulamin#12-dostepnosc-uslug-i-wsparcie-techniczne-sla">Warunki SLA</a> </div> <div class="footer-bottom-right"> <!-- Social Media Icons — neumorphic circles --> <div class="footer-social-icons"> <a href="https://www.facebook.com/iqhostpl" class="fs-icon fs-facebook" target="_blank" rel="noopener noreferrer" aria-label="Facebook"> <svg viewBox="0 0 36 36" fill="currentColor" width="16" height="16"><path d="M20.181 35.87C29.094 34.791 36 27.202 36 18c0-9.941-8.059-18-18-18S0 8.059 0 18c0 8.442 5.811 15.526 13.652 17.471L14 34v-9H9.993v-5H14v-3.95c0-4.647 2.432-6.816 6.28-6.816 1.888 0 2.906.14 3.381.203v4.38h-2.636c-1.677 0-2.262 1.588-2.262 3.377V20h4.827l-.656 5H18.763v11.136c.475.055.955.098 1.418.098V35.87z"/></svg> </a> <a href="https://twitter.com/iqhostpl" class="fs-icon fs-x" target="_blank" rel="noopener noreferrer" aria-label="X (Twitter)"> <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg> </a> <a href="https://www.instagram.com/iqhostpl" class="fs-icon fs-instagram" target="_blank" rel="noopener noreferrer" aria-label="Instagram"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="20" rx="5" ry="5"/><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"/><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"/></svg> </a> <a href="https://www.linkedin.com/company/iqhostpl" class="fs-icon fs-linkedin" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn"> <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg> </a> <a href="https://www.google.com/maps/place/IQHost.pl/" class="fs-icon fs-google" target="_blank" rel="noopener noreferrer" aria-label="Opinie Google"> <svg width="14" height="14" viewBox="0 0 24 24"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18A11.96 11.96 0 001 12c0 1.94.46 3.77 1.18 5.07l3.66-2.98z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/></svg> </a> </div> <div class="footer-certifications"> <span class="cert-badge"><i class="fas fa-shield-alt"></i> SSL secured</span> <span class="cert-badge"><i class="fas fa-lock"></i> Bezpieczne płatności</span> </div> </div> </div> </div> <!-- Scroll to top button --> <button id="scroll-to-top" class="scroll-to-top" aria-label="Przewiń do góry"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="19" x2="12" y2="5"></line><polyline points="5 12 12 5 19 12"></polyline></svg> </button> </footer> <script> document.addEventListener('DOMContentLoaded', function() { // Newsletter form const form = document.getElementById('footer-newsletter-form'); const resultBox = document.getElementById('newsletter-result'); const submitBtn = form.querySelector('.newsletter-button'); function showResult(message, success) { resultBox.textContent = message; resultBox.style.display = 'block'; resultBox.className = 'newsletter-result ' + (success ? 'success' : 'error'); setTimeout(() => { resultBox.style.display = 'none'; }, 5000); } form.addEventListener('submit', function(e) { e.preventDefault(); submitBtn.disabled = true; submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Wysyłanie...'; grecaptcha.ready(function() { grecaptcha.execute('6LeaPwsqAAAAALYV9xE_2tC5d1DUUXBC6SxTPOwV', {action: 'newsletter_subscribe'}) .then(function(token) { document.getElementById('newsletter-recaptcha-response').value = token; const formData = new FormData(form); fetch('/newsletter/subscribe.php', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { submitBtn.disabled = false; submitBtn.innerHTML = '<i class="fas fa-paper-plane"></i> Subskrybuj'; showResult(data.message, data.success); if (data.success) form.reset(); }) .catch(error => { submitBtn.disabled = false; submitBtn.innerHTML = '<i class="fas fa-paper-plane"></i> Subskrybuj'; showResult('Wystąpił błąd. Spróbuj ponownie.', false); }); }); }); }); }); </script> <!-- Cookie Consent Banner --> <div class="cookie-consent" id="cookieConsent"> <div class="container"> <div class="cookie-content"> <p>Używamy plików cookie, aby zapewnić najlepsze doświadczenia na naszej stronie. <a href="https://dev2.iqhost.pl/cookies">Dowiedz się więcej</a> o naszej polityce cookies.</p> <div class="cookie-buttons"> <button class="cookie-button secondary" id="cookiePreferences">Preferencje</button> <button class="cookie-button primary" id="acceptCookies">Akceptuję</button> </div> </div> </div> </div> <!-- Modal z informacjami o formularzu migracji - styl zgodny z modali strony /pomoc --> <div class="modal" id="migrationModal" style="display: none;" aria-hidden="true"> <div class="modal-overlay" tabindex="-1"> <div class="modal-container" role="dialog" aria-modal="true" aria-labelledby="migration-modal-title"> <header class="modal-header"> <h2 class="modal-title" id="migration-modal-title"> Formularz migracji - informacja </h2> <button class="modal-close-button" id="closeMigrationModal" aria-label="Zamknij okno modalne"> <i class="fas fa-times"></i> </button> </header> <main class="modal-content"> <div class="migration-info-wrapper"> <div class="info-header"> <i class="fas fa-info-circle"></i> <h3>Aby wypełnić formularz migracji:</h3> </div> <ul class="requirements-list"> <li><i class="fas fa-check-circle"></i> Musisz posiadać zarejestrowane konto w IQhost</li> <li><i class="fas fa-check-circle"></i> Musisz mieć zakupiony pakiet hostingowy</li> </ul> <p class="info-note"> Formularz migracji jest dostępny w Panelu Klienta po zalogowaniu. Możemy bezpłatnie przenieść Twoją stronę z dowolnego hostingu! </p> <div class="options-grid"> <div class="option-box"> <div class="option-header"> <div class="option-icon"> <i class="fas fa-shopping-cart"></i> </div> <h4>Nie masz jeszcze pakietu?</h4> </div> <p>Wybierz jeden z naszych pakietów i rozpocznij proces migracji.</p> <a href="https://dev2.iqhost.pl" class="cta-button primary">Wybierz pakiet</a> </div> <div class="option-box"> <div class="option-header"> <div class="option-icon"> <i class="fas fa-user-circle"></i> </div> <h4>Masz już konto z pakietem?</h4> </div> <p>Zaloguj się do Panelu Klienta i wypełnij formularz migracji.</p> <a href="https://panel.iqgroup.pl/modules/addons/iq_migration_form/clientarea.php" class="cta-button secondary">Przejdź do formularza migracji</a> </div> </div> <div class="guarantees-section"> <div class="guarantee-item"> <i class="fas fa-clock"></i> <span>Migracja w ciągu 2-3 dni</span> </div> <div class="guarantee-item"> <i class="fas fa-money-bill-wave"></i> <span>Całkowicie za darmo</span> </div> <div class="guarantee-item"> <i class="fas fa-shield-alt"></i> <span>Bezpieczny transfer danych</span> </div> </div> </div> </main> <footer class="modal-footer"> <button class="cta-button secondary small-button close-modal-trigger" id="closeModalButton" aria-label="Zamknij to okno">Zamknij</button> </footer> </div> </div> </div> <style> /* Style dopasowane do modali z /pomoc */ .migration-info-wrapper { color: var(--text-primary, #333); } .migration-info-wrapper .info-header { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; } .migration-info-wrapper .info-header i { font-size: 1.5rem; color: var(--primary-color, #0056b3); } .migration-info-wrapper .info-header h3 { font-size: 1.3rem; font-weight: 600; margin: 0; color: var(--text-primary, #333); } .migration-info-wrapper .requirements-list { margin: 0 0 20px 0; padding: 0; list-style-type: none; } .migration-info-wrapper .requirements-list li { display: flex; align-items: baseline; gap: 10px; padding: 10px 12px; margin-bottom: 10px; background-color: rgba(0, 86, 179, 0.05); border-radius: 8px; } .migration-info-wrapper .requirements-list li i { color: var(--success-color, #28a745); } .migration-info-wrapper .info-note { margin-bottom: 24px; padding: 12px 16px; background-color: rgba(0, 86, 179, 0.05); border-left: 4px solid var(--primary-color, #0056b3); border-radius: 0 4px 4px 0; font-size: 0.95rem; line-height: 1.5; } .migration-info-wrapper .options-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 24px; } .migration-info-wrapper .option-box { padding: 20px; border-radius: 8px; background-color: var(--background-light-primary, #fff); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); transition: transform 0.3s ease, box-shadow 0.3s ease; } .migration-info-wrapper .option-box:hover { transform: translateY(-5px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); } .migration-info-wrapper .option-header { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; } .migration-info-wrapper .option-icon { width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background-color: rgba(0, 86, 179, 0.1); color: var(--primary-color, #0056b3); font-size: 1.2rem; } .migration-info-wrapper .option-header h4 { margin: 0; font-size: 1.1rem; font-weight: 600; color: var(--primary-color, #0056b3); } .migration-info-wrapper .option-box p { font-size: 0.95rem; margin-bottom: 16px; color: var(--text-secondary, #555); line-height: 1.5; } .migration-info-wrapper .guarantees-section { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; background-color: var(--background-light-secondary, #f8f9fa); padding: 16px; border-radius: 8px; } .migration-info-wrapper .guarantee-item { display: flex; align-items: center; gap: 8px; padding: 8px 16px; background-color: var(--background-light-primary, #fff); border-radius: 20px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); font-size: 0.9rem; color: var(--text-secondary, #555); animation: fadeIn 0.5s ease-out forwards; animation-delay: calc(var(--index) * 0.1s); opacity: 0; } .migration-info-wrapper .guarantee-item:nth-child(1) {--index: 0;} .migration-info-wrapper .guarantee-item:nth-child(2) {--index: 1;} .migration-info-wrapper .guarantee-item:nth-child(3) {--index: 2;} .migration-info-wrapper .guarantee-item i { color: var(--primary-color, #0056b3); } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } /* Responsywność */ @media (max-width: 768px) { .migration-info-wrapper .options-grid { grid-template-columns: 1fr; } .migration-info-wrapper .guarantees-section { flex-direction: column; align-items: center; } } /* Dark mode */ body.dark-mode .migration-info-wrapper { color: var(--dm-text-primary, #e0e0e0); } body.dark-mode .migration-info-wrapper .info-header h3 { color: var(--dm-text-primary, #e0e0e0); } body.dark-mode .migration-info-wrapper .requirements-list li { background-color: rgba(0, 119, 230, 0.1); } body.dark-mode .migration-info-wrapper .info-note { background-color: rgba(0, 119, 230, 0.1); border-left-color: var(--dm-primary-color, #0077e6); } body.dark-mode .migration-info-wrapper .option-box { background-color: var(--dm-background-light-primary, #2c3034); } body.dark-mode .migration-info-wrapper .option-header h4 { color: var(--dm-primary-color, #0077e6); } body.dark-mode .migration-info-wrapper .option-icon { background-color: rgba(0, 119, 230, 0.2); color: var(--dm-primary-color, #0077e6); } body.dark-mode .migration-info-wrapper .option-box p { color: var(--dm-text-secondary, #b0b0b0); } body.dark-mode .migration-info-wrapper .guarantees-section { background-color: var(--dm-background-light-secondary, #343a40); } body.dark-mode .migration-info-wrapper .guarantee-item { background-color: var(--dm-background-light-primary, #2c3034); color: var(--dm-text-secondary, #b0b0b0); } body.dark-mode .migration-info-wrapper .guarantee-item i { color: var(--dm-primary-color, #0077e6); } </style> <!-- Floating Cart Icon — sticky above cart drawer, opens drawer on click --> <a href="#" class="cart-float-icon" id="cartFloatIcon" onclick="if(window.cartDrawer)window.cartDrawer.toggle();return false;"> <i class="fas fa-shopping-cart"></i> <span class="cart-float-badge" id="cartFloatBadge">0</span> </a> <!-- Floating Cart Drawer --> <div class="cart-drawer-wrapper" id="cartDrawerWrapper"> <!-- Drawer Content (Szuflada z produktami) --> <div class="cart-content-list" id="cartDrawerContent"> <div class="cart-drawer-header"> <h4>Twój wybór</h4> <button class="cart-clear-btn" id="cartClearBtn">Wyczyść wszystko</button> </div> <div class="cart-items-list" id="cartItemsList"> <!-- Items will be rendered by JavaScript --> </div> </div> <!-- The Floating Bar --> <div class="cart-floating-bar" id="cartFloatingBar"> <div class="cart-bar-left"> <div class="cart-bar-count" id="cartDrawerCount">0</div> <div class="cart-bar-text"> <div class="cart-bar-total" id="cartDrawerTotal">0,00 zł</div> <div class="cart-bar-subtitle"> Wartość brutto <i class="fas fa-chevron-up cart-bar-arrow"></i> </div> </div> </div> <button class="cart-checkout-btn" id="cartCheckoutBtn"> Finalizuj Zamówienie <i class="fas fa-arrow-right"></i> </button> </div> </div> <script> /** * Cart Drawer - rozszerzenie dla CartManager * Dodaje funkcjonalność pływającego koszyka z szufladą */ (function() { 'use strict'; // Ceny domen (cache) let domainPrices = {}; let pricesLoaded = false; // Pobierz ceny domen z API async function loadDomainPrices() { if (pricesLoaded) return; try { const response = await fetch('/api/get-domain-prices.php'); const data = await response.json(); if (data.result === 'success' && data.pricing) { domainPrices = data.pricing; pricesLoaded = true; } } catch (error) { console.error('[Cart Drawer] Error loading domain prices:', error); } } /** * Extract TLD from domain name, checking WHMCS pricing for multi-part TLDs * e.g. "firma.com.pl" → "com.pl", "firma.pl" → "pl" */ function extractTld(domainName) { const parts = domainName.split('.'); if (parts.length < 2) return null; // Check 2-part TLD first (com.pl, net.pl, org.pl, co.uk, etc.) if (parts.length >= 3) { const twoPartTld = parts.slice(-2).join('.'); if (domainPrices[twoPartTld]) return twoPartTld; } // Single-part TLD return parts[parts.length - 1]; } /** * Get domain price from WHMCS pricing data * @param {string} domainName - Full domain name (e.g. "firma.pl") * @param {string} type - "register", "transfer", or "renew" * @param {number} years - Registration/renewal period (1-10) * @returns {number|null} Brutto price in PLN */ function getDomainPrice(domainName, type, years) { if (!pricesLoaded || !domainPrices) return null; const tld = extractTld(domainName); if (!tld || !domainPrices[tld]) return null; // Map type to WHMCS pricing key let actionKey = 'register'; if (type === 'transfer') actionKey = 'transfer'; else if (type === 'renew') actionKey = 'renew'; const prices = domainPrices[tld][actionKey]; if (!prices) return null; // Use the correct year period (default to 1) const period = String(years || 1); if (prices[period] !== undefined && prices[period] !== null) { return parseFloat(prices[period]); } // Fallback to 1-year price if requested period not available if (prices['1'] !== undefined) { return parseFloat(prices['1']); } return null; } // Stawka VAT const VAT_RATE = 0.23; // Przelicz cenę netto na brutto function netToGross(netPrice) { if (netPrice === null || isNaN(netPrice)) return null; return netPrice * (1 + VAT_RATE); } // Formatuj cenę function formatPrice(price) { if (price === null || isNaN(price)) return '—'; return price.toFixed(2).replace('.', ',') + ' zł'; } // Elementy DOM const wrapper = document.getElementById('cartDrawerWrapper'); const content = document.getElementById('cartDrawerContent'); const floatingBar = document.getElementById('cartFloatingBar'); const itemsList = document.getElementById('cartItemsList'); const countEl = document.getElementById('cartDrawerCount'); const totalEl = document.getElementById('cartDrawerTotal'); const clearBtn = document.getElementById('cartClearBtn'); const checkoutBtn = document.getElementById('cartCheckoutBtn'); const floatIcon = document.getElementById('cartFloatIcon'); const floatBadge = document.getElementById('cartFloatBadge'); // Update floating cart icon visibility function updateFloatIcon(count) { if (!floatIcon || !floatBadge) return; if (count > 0) { floatBadge.textContent = count; floatIcon.classList.add('visible'); // Hide when drawer is expanded if (wrapper && wrapper.classList.contains('expanded')) { floatIcon.classList.add('hidden'); } else { floatIcon.classList.remove('hidden'); } } else { floatIcon.classList.remove('visible'); } } // Toggle drawer open/close function toggleDrawer(forceState) { if (!wrapper) return; if (typeof forceState === 'boolean') { if (forceState) { wrapper.classList.add('expanded'); content.classList.add('open'); if (floatIcon) floatIcon.classList.add('hidden'); } else { wrapper.classList.remove('expanded'); content.classList.remove('open'); if (floatIcon) floatIcon.classList.remove('hidden'); } } else { wrapper.classList.toggle('expanded'); content.classList.toggle('open'); // Sync float icon if (floatIcon) { if (wrapper.classList.contains('expanded')) { floatIcon.classList.add('hidden'); } else { floatIcon.classList.remove('hidden'); } } } } // Aktualizuj UI koszyka drawer async function updateDrawerUI() { if (!wrapper || !window.cartManager) return; // Upewnij się, że ceny są załadowane await loadDomainPrices(); const domains = window.cartManager.getDomains(); const products = window.cartManager.getProducts ? window.cartManager.getProducts() : []; const itemCount = domains.length + products.length; // Update floating cart icon updateFloatIcon(itemCount); if (itemCount > 0) { wrapper.classList.add('visible'); countEl.textContent = itemCount; // Oblicz sumę let total = 0; let itemsHtml = ''; // Renderuj pakiety hostingowe products.forEach(product => { const priceNet = parseFloat(product.price) || 0; const priceGross = netToGross(priceNet); total += priceGross; itemsHtml += ` <div class="cart-row-item" data-product-pid="${product.pid}"> <div class="cart-item-info"> <span class="cart-item-name">${product.name}</span> <span class="cart-item-tag tag-hosting">Hosting</span> </div> <div class="cart-item-actions"> <span class="cart-item-price">${formatPrice(priceGross)}</span> <button class="cart-item-remove" data-product-pid="${product.pid}" title="Usuń"> <i class="fas fa-trash"></i> </button> </div> </div> `; }); // Renderuj domeny // UWAGA: Ceny domen z WHMCS API są już BRUTTO - NIE dodajemy VAT! domains.forEach(domain => { const domainType = domain.type || 'register'; const years = parseInt(domain.regperiod) || 1; const priceGross = getDomainPrice(domain.name, domainType, years); if (priceGross !== null) { total += priceGross; } const typeLabels = { 'register': 'Rejestracja', 'transfer': 'Transfer', 'renew': 'Odnowienie' }; const tagClasses = { 'register': 'tag-reg', 'transfer': 'tag-trans', 'renew': 'tag-renew' }; const typeLabel = typeLabels[domainType] || 'Rejestracja'; const tagClass = tagClasses[domainType] || 'tag-reg'; const yearInfo = years > 1 ? ' (' + years + (years < 5 ? ' lata' : ' lat') + ')' : ''; itemsHtml += ` <div class="cart-row-item" data-domain="${domain.name}"> <div class="cart-item-info"> <span class="cart-item-name">${domain.name}</span> <span class="cart-item-tag ${tagClass}">${typeLabel}${yearInfo}</span> </div> <div class="cart-item-actions"> <span class="cart-item-price">${formatPrice(priceGross)}</span> <button class="cart-item-remove" data-domain="${domain.name}" title="Usuń"> <i class="fas fa-trash"></i> </button> </div> </div> `; }); itemsList.innerHTML = itemsHtml; totalEl.textContent = formatPrice(total); // Dodaj event listeners do przycisków usuwania domen itemsList.querySelectorAll('.cart-item-remove[data-domain]').forEach(btn => { btn.addEventListener('click', function(e) { e.stopPropagation(); const domainName = this.getAttribute('data-domain'); if (domainName && window.cartManager) { window.cartManager.removeDomain(domainName); } }); }); // Dodaj event listeners do przycisków usuwania pakietów itemsList.querySelectorAll('.cart-item-remove[data-product-pid]').forEach(btn => { btn.addEventListener('click', function(e) { e.stopPropagation(); const pid = this.getAttribute('data-product-pid'); if (pid && window.cartManager && window.cartManager.removeProduct) { window.cartManager.removeProduct(parseInt(pid)); } }); }); } else { wrapper.classList.remove('visible'); toggleDrawer(false); } } // Event listeners if (floatingBar) { floatingBar.addEventListener('click', function(e) { // Nie toggle jeśli kliknięto w przycisk checkout if (e.target.closest('.cart-checkout-btn')) return; toggleDrawer(); }); } if (clearBtn) { clearBtn.addEventListener('click', function(e) { e.stopPropagation(); if (window.cartManager) { window.cartManager.clearCart(); } }); } if (checkoutBtn) { checkoutBtn.addEventListener('click', function(e) { e.stopPropagation(); if (window.cartManager) { window.cartManager.goToWHMCSCart(); } }); } // Nasłuchuj na zmiany w koszyku // Nadpisz metody CartManager aby aktualizować drawer function patchCartManager() { if (!window.cartManager) { // Poczekaj na inicjalizację CartManager setTimeout(patchCartManager, 100); return; } const originalUpdateCartUI = window.cartManager.updateCartUI.bind(window.cartManager); window.cartManager.updateCartUI = function() { originalUpdateCartUI(); updateDrawerUI(); }; // Pierwsze wywołanie updateDrawerUI(); } // Nasłuchuj na zmiany w localStorage (backup mechanism) window.addEventListener('storage', function(e) { if (e.key === 'iqhost_cart') { updateDrawerUI(); } }); // Nasłuchuj na custom event (jeśli CartManager go emituje) document.addEventListener('iqhost:cart:updated', function() { updateDrawerUI(); }); // Obserwuj zmiany w DOM koszyka w headerze (fallback) function observeCartBadge() { const cartBadge = document.querySelector('.cart-count'); if (cartBadge) { const observer = new MutationObserver(function() { updateDrawerUI(); }); observer.observe(cartBadge, { childList: true, characterData: true, subtree: true }); } } // Inicjalizacja po załadowaniu DOM if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { patchCartManager(); observeCartBadge(); }); } else { patchCartManager(); observeCartBadge(); } // Expose functions globally for debugging window.cartDrawer = { toggle: toggleDrawer, update: updateDrawerUI, loadPrices: loadDomainPrices }; })(); </script> <!-- Skrypty --> <!-- jQuery - bez defer (dependency dla innych skryptów) --> <script src="https://dev2.iqhost.pl/assets/lib/jquery/jquery-3.6.0.min.js?v=1772125383"></script> <!-- Popper i Bootstrap JS - bez defer (dependency) --> <script src="https://dev2.iqhost.pl/assets/lib/popper/popper.min.js?v=1772125383"></script> <script src="https://dev2.iqhost.pl/assets/lib/bootstrap/bootstrap.min.js?v=1772125383"></script> <!-- AOS - Animate On Scroll Library - BEZ defer (krytyczne dla hero) --> <script src="https://dev2.iqhost.pl/assets/lib/aos/aos.js?v=1772125383"></script> <!-- Particles.js dla tła --> <script defer src="https://dev2.iqhost.pl/assets/lib/particles-js/particles.min.js?v=1772125383"></script> <!-- Header transparent mode (scroll detection) --> <script src="https://dev2.iqhost.pl/assets/js/header-transparent.js?v=1772125383"></script> <!-- Własne skrypty JS --> <script defer src="https://dev2.iqhost.pl/assets/js/particles-init.js?v=1772125383"></script> <script defer src="https://dev2.iqhost.pl/assets/js/site-stats.js?v=1772125383"></script> <script src="https://dev2.iqhost.pl/assets/js/tabs.js?v=1772125383"></script> <script src="https://dev2.iqhost.pl/assets/js/components/faq.js?v=1772125383"></script> <script defer src="https://dev2.iqhost.pl/assets/js/components/faq-global-fix.js?v=1772125383"></script> <script src="https://dev2.iqhost.pl/assets/js/fix-testimonials.js?v=1772125383"></script> <script src="https://dev2.iqhost.pl/assets/js/carousel.js?v=1772125383"></script> <script src="https://dev2.iqhost.pl/assets/js/modals.js?v=1772125383"></script> <script defer src="https://dev2.iqhost.pl/assets/js/migration-modal.js?v=1772125383"></script> <script defer src="https://dev2.iqhost.pl/assets/js/notifications.js?v=1772125383"></script> <script src="https://dev2.iqhost.pl/assets/js/theme.js?v=1772125383"></script> <script defer src="https://dev2.iqhost.pl/assets/js/scroll-top.js?v=1772125383"></script> <script src="https://dev2.iqhost.pl/assets/js/pricing.js?v=1772125383"></script> <script defer src="https://dev2.iqhost.pl/assets/js/misc.js?v=1772125383"></script> <!-- Menu mobilne musi być załadowane na końcu --> <script src="https://dev2.iqhost.pl/assets/js/mobile-menu2.js?v=1772125383"></script> <!-- Menedżer koszyka - globalny --> <script src="https://dev2.iqhost.pl/assets/js/cart-manager.js?v=1772125383"></script> <script src="https://dev2.iqhost.pl/assets/js/blog-sidebar.js?v=1772125383"></script> <!-- Inicjalizacja wszystkich skryptów - BEZ defer (musi być od razu) --> <script src="https://dev2.iqhost.pl/assets/js/init-all.js?v=1772125383"></script> <!-- Google reCAPTCHA v3 --> <script defer src="https://www.google.com/recaptcha/api.js?render=6LeaPwsqAAAAALYV9xE_2tC5d1DUUXBC6SxTPOwV"></script> <script defer src="https://dev2.iqhost.pl/assets/js/recaptcha.js?v=1772125383"></script> <!-- Google Analytics, itp. --> <!-- Tutaj można dodać skrypty do śledzenia --> </body> </html>