<!doctype html><html lang="cs"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Horliko podlahářství | Dlažba • Lino • Koberce</title><meta name="description" content="Podlahářství: pokládka dlažby, lina a koberců. Poradenství, zaměření, realizace. Kontaktujte nás." /><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"><link rel="icon" type="image/png" href="assets/logo.png" /><link rel="stylesheet" href="styles.css?v=20260103161416" /></head><body><a class="skip-link" href="#main">Přeskočit na obsah</a><header class="header" id="top"><div class="container header__inner"><a class="brand" href="#top" aria-label="Horliko podlahářství"><span class="brand__text"><span class="brand__name">Horliko</span><span class="brand__tag">podlahářství</span></span></a><button class="nav-toggle" id="navToggle" aria-expanded="false" aria-controls="siteNav"><span class="nav-toggle__icon" aria-hidden="true"></span><span class="sr-only">Menu</span></button><nav class="nav" id="siteNav"><a href="#sluzby">Služby</a><a href="#realizace">Realizace</a><a href="#o-nas">Postup realizace</a><a href="#kontakt">Kontakt</a><a class="btn btn--small" href="#kontakt">Nezávazná poptávka</a></nav></div></header><main id="main"><section class="hero"><div class="container hero__grid"><div class="hero__content"><img src="assets/logo.png" alt="Horliko podlahářství – logo" class="hero__mobile-logo" /><p class="badge">Dlažba • Lino • Koberce</p><h1>Profesionální <span class="accent">pokládka podlahových krytin</span></h1><p class="lead">
            Pomůžeme s výběrem materiálu, zaměřením i realizací. Děláme čistě, přesně a v domluveném termínu.
          </p><div class="hero__cta"><div class="hero__slogan">Rychle • kvalitně • levně</div><a class="btn" href="#kontakt">Chci cenovou nabídku</a><a class="btn btn--ghost" href="#sluzby">Co nabízíme?</a></div><ul class="stats" aria-label="Rychlé informace"><li><strong>Rychlá reakce</strong><span>do 24 hodin</span></li><li><strong>Férové ceny</strong><span>transparentní položky</span></li><li><strong>Záruka</strong><span>na provedení</span></li></ul></div><div class="hero__card" role="presentation"><div class="hero__card-inner"><div class="shine" aria-hidden="true"></div><img class="hero__image hero__image--logo" src="assets/logo.png" alt="Horliko podlahářství – logo" loading="eager" /><h2 class="hero__card-title">Nejčastější realizace</h2><div class="chips" aria-label="Typické projekty"><span class="chip">Byty a domy</span><span class="chip">Kanceláře</span><span class="chip">Schodiště</span><span class="chip">Chodby</span></div><div class="checklist" aria-label="Postup"><div class="checklist__item"><span class="check" aria-hidden="true">✓</span><span><strong>Zaměření</strong> a doporučení vhodné skladby podlahy</span></div><div class="checklist__item"><span class="check" aria-hidden="true">✓</span><span><strong>Příprava podkladu</strong> (stěrka, nivelace, penetrace)</span></div><div class="checklist__item"><span class="check" aria-hidden="true">✓</span><span><strong>Pokládka</strong> + lišty, přechodové profily a detailní dokončení</span></div></div><div class="hero__center-cta"><a class="btn btn--small" href="#kontakt">Domluvit termín</a></div></div></div></div><div class="hero__bg" aria-hidden="true"></div></section><section class="section" id="sluzby"><div class="container"><div class="section__head"><h2>Služby</h2><p>Kompletní pokládka podlahových krytin na klíč</p></div><div class="cards"><article class="card reveal"><div class="card__icon" aria-hidden="true">▦</div><h3>Dlažba</h3><p>
              Pokládka dlažby a obkladů, spárování, řezy na míru, hydroizolace v koupelnách a sprchových koutech.
            </p><ul class="card__list"><li>rovina a spáry na laser</li><li>práce s velkoformátem</li><li>pořádek během realizace</li></ul></article><article class="card reveal"><div class="card__icon" aria-hidden="true">▭</div><h3>Lino (PVC / vinyl)</h3><p>
              Lepené i plovoucí systémy. Příprava podkladu, nivelace, svařování spojů a montáž soklů.
            </p><ul class="card__list"><li>odolné pro domácnost i provoz</li><li>precizní napojení</li><li>rychlá realizace</li></ul></article><article class="card reveal"><div class="card__icon" aria-hidden="true">≋</div><h3>Koberce</h3><p>
              Bytové i zátěžové koberce. Pokládka na pásku i celoplošně, napínání, lemování a prahy.
            </p><ul class="card__list"><li>komfortní a tiché</li><li>kanceláře i byty</li><li>čisté zakončení</li></ul></article></div><div class="banner reveal"><div><h3>Příprava podkladu je základ</h3><p>Rádi posoudíme stav, navrhneme správný postup a vysvětlíme položky v rozpočtu.</p></div><a class="btn btn--small" href="#kontakt">Napsat poptávku</a></div></div></section><section class="section section--alt" id="realizace"><div class="container"><div class="section__head"><h2>Realizace</h2><p>Ilustrační obrázky (můžete nahradit vlastními fotkami v <code>assets/</code>).</p></div><div class="filters" role="tablist" aria-label="Filtr realizací"><button class="filter is-active" data-filter="all" role="tab" aria-selected="true">Vše</button><button class="filter" data-filter="dlazba" role="tab" aria-selected="false">Dlažba</button><button class="filter" data-filter="pvc" role="tab" aria-selected="false">PVC</button><button class="filter" data-filter="koberec" role="tab" aria-selected="false">Koberec</button></div><div id="galleryFilters" aria-label="Filtr kategorií galerie"></div>
<div class="gallery" id="gallery" id="galleryGrid"><!-- Galerie se načítá dynamicky z api/gallery.php --></div></div></section><section class="section" id="o-nas"><div class="container split"><div class="split__left reveal"><h2>Postup realizace</h2><p>
            Jsme podlahářství zaměřené na kvalitní materiály a precizní detail. Zakázky řešíme lidsky a na rovinu —
            řekneme, co dává smysl a kde se nevyplatí šetřit.
          </p><div class="pill-row" aria-label="Výhody"><span class="pill">Zaměření</span><span class="pill">Doprava materiálu</span><span class="pill">Příprava podkladu</span><span class="pill">Pokládka podlahové krytiny</span><span class="pill">Úklid po práci</span></div><div class="quote"><p>„Řemeslo není o rychlosti, ale o kvalitě provedení. U podlah to platí dvojnásob.“</p><span>— Horliko podlahářství</span></div></div><div class="split__right reveal"><div class="info-card"><h3>Rychlý kontakt</h3><dl class="dl"><div><dt>Telefon</dt><dd><a href="tel:+420312589208">+420 312 589 208</a></dd></div><div><dt>E-mail</dt><dd><a href="mailto:hornik34@seznam.cz">hornik34@seznam.cz</a></dd></div><div><dt>Lokalita</dt><dd>Kladno, Praha a okolí (dle domluvy)</dd></div></dl><div class="mini available" id="availability"><span class="dot" aria-hidden="true"></span><span id="availabilityText">Aktuálně přijímáme nové zakázky</span></div><div class="center-cta"><a class="btn btn--small btn--ghost" href="#kontakt">Poptat realizaci</a></div></div></div></div></section><section class="section section--alt" id="kontakt"><div class="container"><div class="section__head"><h2>Kontakt</h2><p>Napište nám. Ozveme se co nejdříve.</p></div><div class="contact-grid contact-grid--single"><form class="form reveal" id="contactForm" novalidate action="api/contact_send.php" method="POST" enctype="multipart/form-data"><!-- Odesílání přes vlastní PHP (bez přesměrování) --><input type="text" name="_honeypot" style="display:none" tabindex="-1" autocomplete="off" /><div class="field"><label for="name">Jméno *</label><input id="name" name="name" autocomplete="name" required placeholder="Jan Novák" /><small class="error" data-for="name"></small></div><div class="field"><label for="email">E-mail *</label><input id="email" name="email" type="email" autocomplete="email" required placeholder="jan@novak.cz" /><small class="error" data-for="email"></small></div><div class="field"><label for="phone">Telefon</label><input id="phone" name="phone" autocomplete="tel" placeholder="+420 312 589 208" /><small class="hint">Volitelné – urychlí domluvu.</small></div><div class="field"><label for="service">O co máte zájem? *</label><select id="service" name="service" required><option value="">Vyberte…</option><option>Dlažba / obklady</option><option>Lino (PVC / vinyl)</option><option>Koberce</option><option>Poradenství / zaměření</option></select><small class="error" data-for="service"></small></div><div class="field"><label for="message">Popis zakázky *</label><textarea id="message" name="message" rows="5" required
                placeholder="Např. 40 m² vinyl do bytu + lišty, termín leden…"></textarea><small class="error" data-for="message"></small></div><div class="field">
  <label for="attachments">Přílohy (fotky nebo PDF)</label>
  <input id="attachments" type="file" name="attachments[]" accept="image/jpeg, image/png, application/pdf" multiple>
  <small class="hint">Můžeš přiložit více souborů. Celkový limit je 5&nbsp;MB.</small>
</div>
<label class="consent"><input type="checkbox" id="gdpr" name="gdpr" required /><span>Souhlasím se zpracováním údajů za účelem vyřízení poptávky. *</span></label><small class="error" data-for="gdpr"></small><div class="form__actions"><button class="btn" type="submit">Odeslat</button><span class="form__status" id="formStatus" role="status" aria-live="polite"></span></div><p class="fineprint"></p></form></div></div></section></main><footer class="footer">
  <div class="container footer__inner" style="justify-content:center;text-align:center;">
    © <span id="year"></span> Horliko podlahářství
  </div>
</footer><script src="script.js?v=20260103161416"></script><script>
(() => {
  const STATUS_POLL_URL = "api/status_get.php?ts=";
  const GALLERY_POLL_URL = "api/gallery_get.php?ts=";
  const STREAM_URL = "api/stream.php";
  const CONFIG_URL = "api/config_get.php?ts=";
  let configCategories = null;


  let lastStatusHash = "";
  let lastGalleryHash = "";

  
  let activeCategory = "Vše";

  function getCategoryLabel(cat){
    const c = (cat || "").toString().trim();
    return c ? c : "Bez kategorie";
  }

  function buildFilters(items){
    const wrap = document.getElementById("galleryFilters");
    if (!wrap) return;

    const cats = new Map();
    filtered.forEach(it => {
      const label = getCategoryLabel(it.category);
      cats.set(label, true);
    });

    let labelsDyn = ["Vše", ...Array.from(cats.keys()).sort((a,b)=>a.localeCompare(b, "cs"))];
    if (Array.isArray(configCategories) && configCategories.length){
      // use admin-configured order, keep only categories that exist
      const set = new Set(labelsDyn.map(x=>x));
      const ordered = configCategories.filter(c=>set.has(c));
      // if config includes categories with no photos yet, still show them
      const extras = configCategories.filter(c=>!set.has(c) && c !== "Vše");
      labelsDyn = ["Vše", ...ordered.filter(c=>c!=="Vše"), ...extras];
    }
    const labels = labelsDyn;

    // preserve activeCategory if it still exists
    if (!labels.includes(activeCategory)) activeCategory = "Vše";

    wrap.innerHTML = "";
    labels.forEach(label => {
      const btn = document.createElement("button");
      btn.type = "button";
      btn.className = "gallery-filter-btn" + (label === activeCategory ? " is-active" : "");
      btn.textContent = label;
      btn.addEventListener("click", () => {
        activeCategory = label;
        // update active styles
        wrap.querySelectorAll(".gallery-filter-btn").forEach(b => b.classList.toggle("is-active", b.textContent === activeCategory));
        // rerender with last payload
        renderGallery(lastGalleryPayload);
      });
      wrap.appendChild(btn);
    });
  }

  let lastGalleryPayload = null;
function setStatus(data) {
    const wrap = document.getElementById("availability");
    const textEl = document.getElementById("availabilityText");
    if (!wrap || !textEl || !data) return;

    const txt = (typeof data.text === "string") ? data.text : "";
    const st = (typeof data.status === "string") ? data.status :
               (typeof data.statusClass === "string") ? data.statusClass : "";

    const hash = JSON.stringify([st, txt]);
    if (hash === lastStatusHash) return;
    lastStatusHash = hash;

    if (txt) textEl.textContent = txt;
    wrap.classList.remove("available","limited","unavailable");
    if (st) wrap.classList.add(st);
  }

  function getGalleryGrid() {
    return document.getElementById("galleryGrid")
        || document.querySelector("[data-gallery-grid]")
        || document.querySelector(".gallery-grid")
        || document.querySelector(".gallery")
        || document.querySelector(".galerie");
  }

  function normalizeGalleryPayload(payload) {
    if (!payload) return [];
    if (Array.isArray(payload)) return payload;
    if (Array.isArray(payload.items)) return payload.items;
    if (Array.isArray(payload.images)) return payload.images;
    if (Array.isArray(payload.photos)) return payload.photos;
    return [];
  }

  function normalizeItem(it) {
    if (!it || typeof it !== "object") return null;
    const url = it.url || it.src || it.image || it.path || it.file || it.href;
    if (!url) return null;
    return { url, caption: it.caption || it.popisek || it.title || "", category: (it.category || it.kategorie || it.cat || it.kat || "").toString().trim() };
  }

  function renderGallery(payload) {
    lastGalleryPayload = payload;
    const grid = getGalleryGrid();
    if (!grid) return;

    const items = normalizeGalleryPayload(payload).map(normalizeItem).filter(Boolean);
    buildFilters(items);

    const filtered = (activeCategory === "Vše")
      ? items
      : items.filter(it => getCategoryLabel(it.category) === activeCategory);
const hash = JSON.stringify(filtered);
    if (hash === lastGalleryHash) return;
    lastGalleryHash = hash;

    grid.innerHTML = "";
    filtered.forEach(it => {
      const a = document.createElement("a");
      a.href = it.url;
      a.target = "_blank";
      a.rel = "noopener";
      a.className = "gallery-item";

      const img = document.createElement("img");
      img.src = it.url;
      img.alt = it.caption || "Fotka";
      img.loading = "lazy";
      a.appendChild(img);

      if (it.caption) {
        const cap = document.createElement("div");
        cap.className = "gallery-caption";
        cap.textContent = it.caption;
        a.appendChild(cap);
      }

      grid.appendChild(a);
    });
  }

  async function pollOnce() {
    try {
      const sRes = await fetch(STATUS_POLL_URL + Date.now(), { cache: "no-store" });
      if (sRes.ok) setStatus(await sRes.json());
    } catch(e) {}

    try {
      const gRes = await fetch(GALLERY_POLL_URL + Date.now(), { cache: "no-store" });
      if (gRes.ok) renderGallery(await gRes.json());
    } catch(e) {}
  }

  function startPollingFallback() {
    pollOnce();
    setInterval(pollOnce, 3000);
  }

  function startSSE() {
    try {
      const es = new EventSource(STREAM_URL);
      es.addEventListener("status", (e) => {
        try { setStatus(JSON.parse(e.data)); } catch(_) {}
      });
      es.addEventListener("gallery", (e) => {
        try { renderGallery(JSON.parse(e.data)); } catch(_) {}
      });
      es.onerror = () => {
        // If SSE is blocked by hosting/proxy, fallback to polling.
        try { es.close(); } catch(_) {}
        startPollingFallback();
      };
      // also do one poll immediately as insurance
      pollOnce();
    } catch(e) {
      startPollingFallback();
    }
  }

  document.addEventListener("DOMContentLoaded", () => { fetchConfig(); startSSE(); });
})();
</script>
<div id="lightbox" aria-hidden="true">
  <img id="lightboxImg" alt="">
</div>
<script>
(() => {
  const lb = document.getElementById("lightbox");
  const lbImg = document.getElementById("lightboxImg");

  function openLightbox(src, alt="") {
    if (!lb || !lbImg) return;
    lbImg.src = src;
    lbImg.alt = alt || "";
    lb.classList.add("is-open");
    lb.setAttribute("aria-hidden","false");
    document.body.classList.add("lb-lock");
  }

  function closeLightbox() {
    if (!lb || !lbImg) return;
    lb.classList.remove("is-open");
    lb.setAttribute("aria-hidden","true");
    document.body.classList.remove("lb-lock");
    // clear src to stop downloading huge images if user closes quickly
    lbImg.src = "";
  }

  // Open on click (works for dynamically rendered gallery)
  document.addEventListener("click", (e) => {
    const img = e.target.closest("#galleryGrid img");
    if (img) {
      e.preventDefault();
      openLightbox(img.currentSrc || img.src, img.alt || "");
      return;
    }
    if (e.target === lb || e.target === lbImg) {
      closeLightbox();
    }
  });

  // Close on ESC
  document.addEventListener("keydown", (e) => {
    if (e.key === "Escape") closeLightbox();
  });
})();
</script>
</body></html>
