PageSourceSearch

https://www.leaderfox.cz/index-en.html

html leaderfox.cz collected 2026-10-01 15:59:25 UTC 97,960 bytes, 2,183 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <link rel="icon" href="/favicon.ico" sizes="any">
7    <link rel="icon" type="image/png" sizes="48x48" href="/favicon-48x48.png">
8    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
9    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
10    <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
11    <link rel="icon" type="image/png" sizes="192x192" href="/android-chrome-192x192.png">
12    <link rel="icon" type="image/png" sizes="512x512" href="/android-chrome-512x512.png">
13    <title>Leader Fox | Traditional Czech bicycle manufacturer</title>
14    <meta name="description" content="Leader Fox – traditional Czech manufacturer of bicycles and e-bikes. Quick access to the e-shop, catalogue, contacts, showroom and dealer network.">
15    <link rel="alternate" hreflang="cs" href="https://www.leaderfox.cz/">
16    <link rel="alternate" hreflang="en" href="https://www.leaderfox.com/">
17    <link rel="alternate" hreflang="x-default" href="https://www.leaderfox.cz/">
18    
18<script src="https://cdn.tailwindcss.com"></script>
18
19    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css">
20    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/MarkerCluster.css">
21    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/MarkerCluster.Default.css">
22
23    <style>
24        html { scroll-behavior: smooth; }
25
26        body {
27            background: #ffffff;
28            color: #18181b;
29        }
30
31        .hero-bg {
32            background-image:
33                linear-gradient(to bottom, rgba(8, 11, 18, 0.22) 0%, rgba(8, 11, 18, 0.12) 28%, rgba(8, 11, 18, 0.56) 100%),
34                url('hlavni-fotka.jpg');
35            background-size: cover;
36            background-position: center top;
37            background-repeat: no-repeat;
38        }
39
40        .nav-blur {
41            background: rgba(10, 10, 10, 0.20);
42            backdrop-filter: blur(14px);
43            -webkit-backdrop-filter: blur(14px);
44        }
45
46        .section-line {
47            background: linear-gradient(90deg, rgba(234,179,8,1) 0%, rgba(234,179,8,0.35) 100%);
48            height: 3px;
49            width: 84px;
50        }
51
52        .card-lift {
53            transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
54        }
55
56        .card-lift:hover {
57            transform: translateY(-4px);
58            box-shadow: 0 24px 60px rgba(0,0,0,0.10);
59        }
60
61        .hero-title-shadow {
62            text-shadow: 0 10px 30px rgba(0,0,0,0.30);
63        }
64
65        .soft-ring {
66            box-shadow: 0 0 0 1px rgba(255,255,255,0.18) inset;
67        }
68
69        #dealer-map-frame {
70            height: 620px;
71            width: 100%;
72            display: block;
73            background: #f4f4f5;
74            z-index: 1;
75        }
76
77        .dealer-map-popup {
78            font-family: Arial, sans-serif;
79            min-width: 220px;
80        }
81
82        .dealer-map-popup-title {
83            font-weight: 900;
84            font-size: 15px;
85            color: #18181b;
86            margin-bottom: 6px;
87        }
88
89        .dealer-map-popup-head {
90            display: flex;
91            align-items: center;
92            justify-content: space-between;
93            gap: 10px;
94            margin-bottom: 6px;
95        }
96
97        .dealer-map-popup-strip {
98            width: 56px;
99            height: 7px;
100            border-radius: 999px;
101            background: var(--partner-strip-color, #86efac);
102            flex: 0 0 auto;
103        }
104
105        .dealer-map-popup-text {
106            font-size: 13px;
107            color: #52525b;
108            line-height: 1.35;
109        }
110
111        .dealer-map-popup-link {
112            display: inline-block;
113            margin-top: 8px;
114            color: #ca8a04;
115            font-weight: 800;
116            text-decoration: none;
117        }
118
119        .marker-cluster-small,
120        .marker-cluster-medium,
121        .marker-cluster-large {
122            background-color: rgba(234, 179, 8, 0.28);
123        }
124
125        .marker-cluster-small div,
126        .marker-cluster-medium div,
127        .marker-cluster-large div {
128            background-color: rgba(234, 179, 8, 0.88);
129            color: #111827;
130            font-weight: 900;
131        }
132
133        .marker-cluster.cluster-gold {
134            background-color: rgba(250, 204, 21, 0.32);
135        }
136
137        .marker-cluster.cluster-gold div {
138            background-color: rgba(250, 204, 21, 0.96);
139            color: #18181b;
140            border: 2px solid #ffffff;
141            box-shadow: 0 10px 28px rgba(250, 204, 21, 0.34);
142        }
143
144        .marker-cluster.cluster-silver {
145            background-color: rgba(212, 212, 216, 0.38);
146        }
147
148        .marker-cluster.cluster-silver div {
149            background-color: rgba(212, 212, 216, 0.96);
150            color: #18181b;
151            border: 2px solid #ffffff;
152            box-shadow: 0 10px 28px rgba(113, 113, 122, 0.28);
153        }
154
155        .marker-cluster.cluster-bronze {
156            background-color: rgba(180, 83, 9, 0.32);
157        }
158
159        .marker-cluster.cluster-bronze div {
160            background-color: rgba(180, 83, 9, 0.96);
161            color: #ffffff;
162            border: 2px solid #ffffff;
163            box-shadow: 0 10px 28px rgba(180, 83, 9, 0.28);
164        }
165
166
167        .dealer-card-active {
168            border-color: rgb(234 179 8) !important;
169            box-shadow: 0 12px 30px rgba(234,179,8,0.18);
170            background: rgba(254, 252, 232, 0.9);
171        }
172
173        .dealer-link {
174            color: #2563eb;
175            text-decoration: underline;
176            text-underline-offset: 2px;
177        }
178
179        .dealer-link:hover {
180            color: #1d4ed8;
181        }
182
183
184
185        .reveal {
186            opacity: 0;
187            transform: translateY(26px);
188            transition: opacity 0.75s ease, transform 0.75s ease;
189        }
190
191        .reveal.is-visible {
192            opacity: 1;
193            transform: translateY(0);
194        }
195
196        .hero-bg {
197            background-attachment: scroll;
198        }
199
200        .premium-surface {
201            background:
202                radial-gradient(circle at 15% 10%, rgba(234,179,8,0.16), transparent 30%),
203                radial-gradient(circle at 85% 70%, rgba(255,255,255,0.06), transparent 28%),
204                linear-gradient(135deg, #050505 0%, #111113 52%, #030303 100%);
205        }
206
207        .category-card {
208            min-height: 360px;
209            position: relative;
210            overflow: hidden;
211            isolation: isolate;
212        }
213
214        .category-card::before {
215            content: '';
216            position: absolute;
217            inset: 0;
218            background:
219                linear-gradient(180deg, rgba(0,0,0,0.05), rgba(0,0,0,0.74)),
220                radial-gradient(circle at 50% 35%, rgba(234,179,8,0.24), transparent 34%);
221            opacity: 0.92;
222            transition: transform 0.45s ease, opacity 0.45s ease;
223            z-index: -1;
224        }
225
226        .category-card::after {
227            content: '';
228            position: absolute;
229            inset: 1px;
230            border-radius: 1.5rem;
231            border: 1px solid rgba(255,255,255,0.10);
232            pointer-events: none;
233        }
234
235        .category-card:hover::before {
236            transform: scale(1.08);
237            opacity: 1;
238        }
239
240        .category-number {
241            font-size: clamp(3.5rem, 8vw, 7rem);
242            line-height: 0.8;
243            letter-spacing: -0.08em;
244        }
245
246        .floating-cta {
247            display: none;
248        }
249
250
251
252        .premium-badge {
253            display: inline-flex;
254            align-items: center;
255            gap: 0.35rem;
256            border-radius: 999px;
257            padding: 0.28rem 0.55rem;
258            font-size: 10px;
259            font-weight: 900;
260            letter-spacing: 0.12em;
261            text-transform: uppercase;
262        }
263
264        .premium-badge.gold {
265            background: #facc15;
266            color: #18181b;
267        }
268
269        .premium-badge.silver {
270            background: #e5e7eb;
271            color: #18181b;
272        }
273
274        .premium-badge.bronze {
275            background: #b45309;
276            color: #ffffff;
277        }
278
279        .dealer-card-premium {
280            border-color: rgba(234,179,8,0.72) !important;
281            box-shadow: 0 16px 42px rgba(234,179,8,0.13);
282        }
283
284        .dealer-card {
285            position: relative;
286            overflow: hidden;
287        }
288
289        .dealer-card::before {
290            content: '';
291            position: absolute;
292            left: 0;
293            top: 0;
294            bottom: 0;
295            width: 7px;
296            background: var(--partner-strip-color, #86efac);
297        }
298
299        .premium-map-marker {
300            border-radius: 999px;
301            border: 2px solid #ffffff;
302            box-shadow: 0 7px 18px rgba(0,0,0,0.22);
303        }
304
305        .dealer-type-icon {
306            width: 38px;
307            height: 38px;
308            border-radius: 999px;
309            display: flex;
310            align-items: center;
311            justify-content: center;
312            background: #2563eb;
313            color: #ffffff;
314            border: 3px solid #ffffff;
315            box-shadow: 0 10px 26px rgba(0,0,0,0.30);
316            font-size: 20px;
317            line-height: 1;
318        }
319
320        .dealer-type-icon.service {
321            background: #18181b;
322        }
323
324        .dealer-type-icon.pickup {
325            background: #16a34a;
326        }
327
328        .dealer-type-icon.gold {
329            background: #facc15;
330            color: #18181b;
331            border-color: #ffffff;
332        }
333
334        .dealer-type-icon.silver {
335            background: #d4d4d8;
336            color: #18181b;
337            border-color: #ffffff;
338        }
339
340        .dealer-type-icon.bronze {
341            background: #b45309;
342            color: #ffffff;
343            border-color: #ffffff;
344        }
345
346        .dealer-type-icon-wrap {
347            background: transparent;
348            border: 0;
349        }
350
351        .czech-region-tooltip {
352            background: rgba(24,24,27,0.88);
353            border: 1px solid rgba(250,204,21,0.38);
354            border-radius: 999px;
355            color: #ffffff;
356            font-size: 11px;
357            font-weight: 800;
358            letter-spacing: 0.04em;
359            padding: 3px 8px;
360            box-shadow: 0 8px 24px rgba(0,0,0,0.22);
361        }
362
363        .gallery-tab.is-active {
364            background: #facc15;
365            color: #18181b;
366            border-color: #facc15;
367        }
368
369        .gallery-thumb {
370            position: relative;
371            display: block;
372            overflow: hidden;
373            border-radius: 1.5rem;
374            background: #18181b;
375            cursor: pointer;
376            min-height: 230px;
377        }
378
379        .gallery-thumb img {
380            width: 100%;
381            height: 100%;
382            min-height: 230px;
383            object-fit: cover;
384            display: block;
385            transform: scale(1.01);
386            transition: transform 0.35s ease, opacity 0.35s ease;
387        }
388
389        .gallery-thumb:hover img {
390            transform: scale(1.06);
391        }
392
393        .gallery-thumb::after {
394            content: '';
395            position: absolute;
396            inset: 0;
397            background: linear-gradient(180deg, transparent 45%, rgba(0,0,0,0.55));
398            opacity: 0;
399            transition: opacity 0.35s ease;
400        }
401
402        .gallery-thumb:hover::after {
403            opacity: 1;
404        }
405
406        .gallery-lightbox {
407            position: fixed;
408            inset: 0;
409            z-index: 100;
410            display: none;
411            align-items: center;
412            justify-content: center;
413            background: rgba(0,0,0,0.92);
414            padding: 24px;
415        }
416
417        .gallery-lightbox.is-open {
418            display: flex;
419        }
420
421        .gallery-lightbox img {
422            max-width: min(1200px, 92vw);
423            max-height: 86vh;
424            object-fit: contain;
425            box-shadow: 0 24px 80px rgba(0,0,0,0.65);
426        }
427
428        .gallery-lightbox-button {
429            position: absolute;
430            border: 1px solid rgba(255,255,255,0.35);
431            background: rgba(255,255,255,0.08);
432            color: #ffffff;
433            width: 44px;
434            height: 44px;
435            border-radius: 999px;
436            font-size: 26px;
437            font-weight: 900;
438            line-height: 1;
439            display: flex;
440            align-items: center;
441            justify-content: center;
442            transition: background 0.2s ease, color 0.2s ease;
443        }
444
445        .gallery-lightbox-button:hover {
446            background: #facc15;
447            color: #18181b;
448        }
449
450        .gallery-lightbox-close {
451            top: 22px;
452            right: 22px;
453        }
454
455        .gallery-lightbox-prev {
456            left: 22px;
457            top: 50%;
458            transform: translateY(-50%);
459        }
460
461        .gallery-lightbox-next {
462            right: 22px;
463            top: 50%;
464            transform: translateY(-50%);
465        }
466
467        .gallery-lightbox-caption {
468            position: absolute;
469            left: 24px;
470            right: 24px;
471            bottom: 18px;
472            text-align: center;
473            color: rgba(255,255,255,0.82);
474            font-size: 13px;
475            font-weight: 800;
476            letter-spacing: 0.16em;
477            text-transform: uppercase;
478        }
479
480
481
482
483        @media (max-width: 767px) {
484            .hero-bg {
485                background-attachment: scroll;
486            }
487
488            .floating-cta {
489                display: grid;
490                grid-template-columns: 1fr 1fr;
491                gap: 8px;
492                position: fixed;
493                left: 12px;
494                right: 12px;
495                bottom: 12px;
496                z-index: 60;
497                padding: 8px;
498                border-radius: 18px;
499                background: rgba(10,10,10,0.72);
500                backdrop-filter: blur(14px);
501                -webkit-backdrop-filter: blur(14px);
502                box-shadow: 0 20px 45px rgba(0,0,0,0.28);
503            }
504
505            body {
506                padding-bottom: 78px;
507            }
508        }
509
510        @media (max-width: 1279px) {
511            #dealer-map-frame {
512                height: 520px;
513            }
514        }
515
516        @media (max-width: 767px) {
517            #dealer-map-frame {
518                height: 420px;
519            }
520        }
521    </style>
522</head>
523<body class="font-sans antialiased">
524
525    <!-- HERO -->
526    <section class="hero-bg min-h-screen flex flex-col relative overflow-hidden">
527        <header class="sticky top-0 z-30">
528            <div class="nav-blur border-b border-white/10">
529                <div class="max-w-7xl mx-auto px-5 md:px-8 py-4 flex items-center justify-end">
530                    <nav class="hidden md:flex items-center gap-7 text-white text-[12px] font-bold uppercase tracking-[0.24em]">
531                        <a href="https://e-shop.leaderfox.com" class="hover:text-yellow-300 transition">E-shop</a>
532                        <a href="#galerie" class="hover:text-yellow-300 transition">Gallery</a>
533                        <a href="https://e-shop.leaderfox.com/dokument/katalog/" class="hover:text-yellow-300 transition">Catalogue</a>
534                        <a href="#kategorie" class="hover:text-yellow-300 transition">Categories</a>
535                        <a href="#rozcestnik" class="hover:text-yellow-300 transition">Quick links</a>
536                        <a href="#partneri" class="hover:text-yellow-300 transition">Dealers</a>
537                        <a href="coverage-map.html" class="hover:text-yellow-300 transition">Coverage map</a>
538                        <a href="https://e-shop.leaderfox.com/dokument/kontakt/" class="hover:text-yellow-300 transition">Contact</a>
539                        <span class="inline-flex items-center gap-2 rounded-full border border-white/25 px-3 py-1 text-[11px] tracking-[0.16em]">
540                            <a href="index.html" class="hover:text-yellow-300 transition">CZ</a>
541                            <span class="text-white/40">|</span>
542                            <span class="text-yellow-300">EN</span>
543                        </span>
544                    </nav>
545                </div>
546            </div>
547        </header>
548
549        <div class="flex-1 relative">
550            <div class="absolute left-0 bottom-0 w-full px-3 md:px-4 pb-4 md:pb-6">
551                <div class="max-w-3xl">
552                    <div class="inline-flex items-center gap-3 mb-5 px-4 py-2 rounded-full bg-white/10 text-white text-[11px] md:text-xs uppercase tracking-[0.28em] font-bold soft-ring">
553                        <span class="h-2 w-2 rounded-full bg-yellow-400"></span>
554                        Traditional Czech manufacturer of bicycles and e-bikes
555                    </div>
556
557                    <h1 class="text-white text-5xl sm:text-6xl md:text-8xl font-semibold italic tracking-tight leading-[0.95] hero-title-shadow">
558                        the good ride
559                    </h1>
560
561                    <div class="mt-8 flex flex-col sm:flex-row gap-4">
562                        <a href="https://e-shop.leaderfox.com"
563                           class="bg-yellow-400 hover:bg-yellow-300 text-black font-black py-4 px-8 uppercase tracking-[0.18em] text-sm transition shadow-2xl text-center">
564                            Go to e-shop
565                        </a>
566                        <a href="#partneri"
567                           class="border border-white/70 text-white hover:bg-white hover:text-black font-black py-4 px-8 uppercase tracking-[0.18em] text-sm transition text-center">
568                            Where to buy and service
569                        </a>
570                    </div>
571                </div>
572            </div>
573        </div>
574    </section>
575
576    <!-- GALERIE -->
577    <section id="galerie" class="bg-white py-20 md:py-24 reveal">
578        <div class="max-w-7xl mx-auto px-5 md:px-8">
579            <div class="max-w-3xl mb-10">
580                <div class="section-line mb-6"></div>
581                <p class="text-xs md:text-sm uppercase tracking-[0.35em] font-black text-yellow-500 mb-4">
582                    Gallery
583                </p>
584           
585            </div>
586
587            <div class="flex flex-wrap gap-3 mb-8">
588                <button type="button" class="gallery-tab is-active rounded-full border border-zinc-300 px-5 py-3 text-xs font-black uppercase tracking-[0.22em] text-zinc-800 transition" data-gallery-set="hero">
589                    Hero
590                </button>
591                <button type="button" class="gallery-tab rounded-full border border-zinc-300 px-5 py-3 text-xs font-black uppercase tracking-[0.22em] text-zinc-800 hover:border-yellow-400 transition" data-gallery-set="alps">
592                    Alps
593                </button>
594            </div>
595
596            <div id="gallery-grid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5"></div>
597
598            <div class="text-center mt-10">
599                <button id="gallery-load-more" type="button" class="inline-flex bg-zinc-900 text-white hover:bg-yellow-400 hover:text-black font-black py-4 px-8 uppercase tracking-[0.18em] text-sm transition">
600                    Load more photos
601                </button>
602            </div>
603        </div>
604    </section>
605
606    <div id="gallery-lightbox" class="gallery-lightbox" aria-hidden="true">
607        <button type="button" id="gallery-lightbox-close" class="gallery-lightbox-button gallery-lightbox-close" aria-label="Close gallery">×</button>
608        <button type="button" id="gallery-lightbox-prev" class="gallery-lightbox-button gallery-lightbox-prev" aria-label="Previous photo">‹</button>
609        <img id="gallery-lightbox-image" src="" alt="">
610        <button type="button" id="gallery-lightbox-next" class="gallery-lightbox-button gallery-lightbox-next" aria-label="Next p
610hoto">›</button>
611        <div id="gallery-lightbox-caption" class="gallery-lightbox-caption"></div>
612    </div>
613
614    <!-- INTRO / O ZNACCE -->
615    <section class="bg-white py-20 md:py-24 reveal">
616        <div class="max-w-7xl mx-auto px-5 md:px-8 grid grid-cols-1 lg:grid-cols-12 gap-10 lg:gap-16 items-center">
617            <div class="lg:col-span-7">
618                <div class="section-line mb-6"></div>
619                <p class="text-xs md:text-sm uppercase tracking-[0.35em] font-black text-yellow-500 mb-4">
620                    Czech tradition since 1996
621                </p>
622                <h2 class="text-3xl md:text-5xl font-black tracking-tight text-zinc-900 leading-tight mb-6">
623                    Bicycles from České Budějovice for the city, sport and everyday riding.
624                </h2>
625                <p class="text-zinc-600 text-base md:text-lg leading-relaxed max-w-3xl">
626                    Leader Fox builds on its own development, careful assembly and proven components.
627                    Here you can find the most important links to the e-shop, catalogues, showroom, contacts
628                    and the partner network of dealers and service points.
629                </p>
630            </div>
631
632            <div class="lg:col-span-5">
633                <div class="grid grid-cols-2 gap-4">
634                    <div class="rounded-3xl border border-zinc-200 bg-zinc-50 p-6 md:p-8">
635                        <div class="text-3xl md:text-4xl font-black text-zinc-900">25+</div>
636                        <div class="mt-2 text-[11px] uppercase tracking-[0.24em] font-bold text-zinc-500">Years of the brand</div>
637                    </div>
638                    <div class="rounded-3xl border border-zinc-900 bg-zinc-900 p-6 md:p-8">
639                        <div class="text-3xl md:text-4xl font-black text-white">100%</div>
640                        <div class="mt-2 text-[11px] uppercase tracking-[0.24em] font-bold text-zinc-400">Focus on own assembly</div>
641                    </div>
642                </div>
643            </div>
644        </div>
645    </section>
646
647    <!-- KATEGORIE E-SHOPU -->
648    <section id="kategorie" class="premium-surface text-white py-20 md:py-28 reveal">
649        <div class="max-w-7xl mx-auto px-5 md:px-8">
650            <div class="grid grid-cols-1 lg:grid-cols-12 gap-10 lg:gap-16 items-end mb-12">
651                <div class="lg:col-span-7">
652                    <div class="section-line mb-6"></div>
653                    <p class="text-xs md:text-sm uppercase tracking-[0.35em] font-black text-yellow-400 mb-4">
654                        E-shop categories
655                    </p>
656                    <h2 class="text-3xl md:text-6xl font-black tracking-tight leading-[0.95]">
657                        Quick access directly to the Leader Fox range.
658                    </h2>
659                </div>
660                <div class="lg:col-span-5">
661                </div>
662            </div>
663
664            <div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-5">
665                <a href="https://e-shop.leaderfox.com/elektrokola-menu-1R30000101.aspx" class="category-card rounded-3xl bg-zinc-900 p-7 flex flex-col justify-between group">
666                    <div class="flex items-start justify-between gap-4">
667                        <div class="text-xl font-bold text-white mb-3">Power for longer rides.</div>
668                        <div class="category-number font-black text-white/10 group-hover:text-yellow-400/20 transition">01</div>
669                    </div>
670                    <div>
671                        <h3 class="text-4xl md:text-5xl font-black tracking-tight mb-4 text-yellow-400">E-bikes</h3>
672                        <p class="text-zinc-300 text-sm leading-relaxed mb-6">Mountain, trekking, city, folding, fat bike and other e-bikes.</p>
673                        <span class="inline-flex text-sm font-black uppercase tracking-[0.18em] text-white">View e-bikes →</span>
674                    </div>
675                </a>
676
677                <a href="https://e-shop.leaderfox.com/jizdni-kola-menu-G510000101.aspx" class="category-card rounded-3xl bg-zinc-900 p-7 flex flex-col justify-between group">
678                    <div class="flex items-start justify-between gap-4">
679                        <div class="text-xl font-bold text-white mb-3">Classic bikes for sport and trips.</div>
680                        <div class="category-number font-black text-white/10 group-hover:text-yellow-400/20 transition">02</div>
681                    </div>
682                    <div>
683                        <h3 class="text-4xl md:text-5xl font-black tracking-tight mb-4 text-yellow-400">Bicycles</h3>
684                        <p class="text-zinc-300 text-sm leading-relaxed mb-6">Mountain, cross, trekking and children’s bikes by riding style.</p>
685                        <span class="inline-flex text-sm font-black uppercase tracking-[0.18em] text-white">View bicycles →</span>
686                    </div>
687                </a>
688
689                <a href="https://e-shop.leaderfox.com/nove-modely-menu-6WG1000101.aspx" class="category-card rounded-3xl bg-zinc-900 p-7 flex flex-col justify-between group">
690                    <div class="flex items-start justify-between gap-4">
691                        <div class="text-xl font-bold text-white mb-3">Current collection.</div>
692                        <div class="category-number font-black text-white/10 group-hover:text-yellow-400/20 transition">03</div>
693                    </div>
694                    <div>
695                        <h3 class="text-4xl md:text-5xl font-black tracking-tight mb-4 text-yellow-400">New models</h3>
696                        <p class="text-zinc-300 text-sm leading-relaxed mb-6">New e-bikes, bicycles, folding bikes and children’s bikes.</p>
697                        <span class="inline-flex text-sm font-black uppercase tracking-[0.18em] text-white">View new models →</span>
698                    </div>
699                </a>
700
701                <a href="https://e-shop.leaderfox.com/cargo-e-kola-menu-1E20000101.aspx" class="category-card rounded-3xl bg-zinc-900 p-7 flex flex-col justify-between group">
702                    <div class="flex items-start justify-between gap-4">
703                        <div class="text-xl font-bold text-white mb-3">For family and cargo.</div>
704                        <div class="category-number font-black text-white/10 group-hover:text-yellow-400/20 transition">04</div>
705                    </div>
706                    <div>
707                        <h3 class="text-4xl md:text-5xl font-black tracking-tight mb-4 text-yellow-400">Cargo e-bikes</h3>
708                        <p class="text-zinc-300 text-sm leading-relaxed mb-6">Practical e-bikes for everyday transport, children and larger loads.</p>
709                        <span class="inline-flex text-sm font-black uppercase tracking-[0.18em] text-white">View cargo e-bikes →</span>
710                    </div>
711                </a>
712
713                <a href="https://e-shop.leaderfox.com/kola-s-vadou-laku-menu-GWJ0000101.aspx" class="category-card rounded-3xl bg-zinc-900 p-7 flex flex-col justify-between group">
714                    <div class="flex items-start justify-between gap-4">
715                        <div class="text-xl font-bold text-white mb-3">Special offer.</div>
716                        <div class="category-number font-black text-white/10 group-hover:text-yellow-400/20 transition">05</div>
717                    </div>
718                    <div>
719                        <h3 class="text-4xl md:text-5xl font-black tracking-tight mb-4 text-yellow-400">Bikes with paint defects</h3>
720                        <p class="text-zinc-300 text-sm leading-relaxed mb-6">E-bikes and bicycles with cosmetic paint defects at a better price.</p>
721                        <span class="inline-flex text-sm font-black uppercase tracking-[0.18em] text-white">View bikes with paint defects →</span>
722                    </div>
723                </a>
724
725                <a href="https://e-shop.leaderfox.com/nahradni-dily-a-merch-menu-4WJ0000101.aspx" class="category-card rounded-3xl bg-zinc-900 p-7 flex flex-col justify-between group">
726                    <div class="flex items-start justify-between gap-4">
727                        <div class="text-xl font-bold text-white mb-3">Bike accessories.</div>
728                        <div class="category-number font-black text-white/10 group-hover:text-yellow-400/20 transition">06</div>
729                    </div>
730                    <div>
731                        <h3 class="text-4xl md:text-5xl font-black tracking-tight mb-4 text-yellow-400">Spare parts and merch</h3>
732                        <p class="text-zinc-300 text-sm leading-relaxed mb-6">Batteries, chargers, brakes, tyres, stands, merch and more.</p>
733                        <span class="inline-flex text-sm font-black uppercase tracking-[0.18em] text-white">View spare parts and merch →</span>
734                    </div>
735                </a>
736            </div>
737        </div>
738    </section>
739
740    <!-- ROZCESTNIK -->
741    <section id="rozcestnik" class="bg-zinc-950 text-white py-20 md:py-24 reveal">
742        <div class="max-w-7xl mx-auto px-5 md:px-8">
743            <div class="flex flex-col md:flex-row md:items-end md:justify-between gap-6 mb-10">
744                <div>
745                    <div class="section-line mb-6"></div>
746                    <p class="text-xs md:text-sm uppercase tracking-[0.35em] font-black text-yellow-400 mb-4">
747                        Quick links
748                    </p>
749                    <h2 class="text-3xl md:text-5xl font-black tracking-tight leading-tight">
750                        Everything important in one place.
751                    </h2>
752                </div>
753      
754            </div>
755
756            <div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-
7565">
757                <a href="https://e-shop.leaderfox.com"
758                   class="card-lift rounded-3xl border border-white/10 bg-white/5 p-7 hover:border-yellow-400/60 hover:bg-white/10 block">
759                    <div class="text-[11px] uppercase tracking-[0.26em] font-black text-yellow-400 mb-4">01</div>
760                    <h3 class="text-2xl font-black tracking-tight mb-3">E-shop</h3>
761                    <p class="text-zinc-300 text-sm leading-relaxed">
762                        Complete range of bicycles, e-bikes and accessories.
763                    </p>
764                </a>
765
766                <a href="https://e-shop.leaderfox.com/dokument/katalog/"
767                   class="card-lift rounded-3xl border border-white/10 bg-white/5 p-7 hover:border-yellow-400/60 hover:bg-white/10 block">
768                    <div class="text-[11px] uppercase tracking-[0.26em] font-black text-yellow-400 mb-4">02</div>
769                    <h3 class="text-2xl font-black tracking-tight mb-3">Catalogue</h3>
770                    <p class="text-zinc-300 text-sm leading-relaxed">
771                        Overview of models, technical specifications and collections.
772                    </p>
773                </a>
774
775                <a href="https://e-shop.leaderfox.com/dokument/znackova-prodejna/"
776                   class="card-lift rounded-3xl border border-white/10 bg-white/5 p-7 hover:border-yellow-400/60 hover:bg-white/10 block">
777                    <div class="text-[11px] uppercase tracking-[0.26em] font-black text-yellow-400 mb-4">03</div>
778                    <h3 class="text-2xl font-black tracking-tight mb-3">Showroom</h3>
779                    <p class="text-zinc-300 text-sm leading-relaxed">
780                        Brand store and direct personal contact in České Budějovice.
781                    </p>
782                </a>
783
784                <a href="https://e-shop.leaderfox.com/dokument/kontakt/"
785                   class="card-lift rounded-3xl border border-white/10 bg-white/5 p-7 hover:border-yellow-400/60 hover:bg-white/10 block">
786                    <div class="text-[11px] uppercase tracking-[0.26em] font-black text-yellow-400 mb-4">04</div>
787                    <h3 class="text-2xl font-black tracking-tight mb-3">Contact</h3>
788                    <p class="text-zinc-300 text-sm leading-relaxed">
789                        Company contacts, service information and other contact details.
790                    </p>
791                </a>
792            </div>
793        </div>
794    </section>
795
796    <!-- PRODEJCI A SERVIS -->
797    <section id="partneri" class="bg-zinc-50 py-20 md:py-24 border-t border-zinc-200 border-b border-zinc-200 reveal">
798        <div class="max-w-7xl mx-auto px-5 md:px-8">
799            <div class="max-w-3xl mb-12">
800                <div class="section-line mb-6"></div>
801                <p class="text-xs md:text-sm uppercase tracking-[0.35em] font-black text-yellow-500 mb-4">
802                    Dealers and service
803                </p>
804                <h2 class="text-3xl md:text-5xl font-black tracking-tight text-zinc-900 leading-tight mb-6">
805                    Where to buy Leader Fox and where to get service.
806                </h2>
807                <p class="text-zinc-600 text-base md:text-lg leading-relaxed">
808                    Choose the type of place, region or country. Results are shown on the map and in a list below.
809                </p>
810            </div>
811
812            <div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-10">
813                <div class="card-lift rounded-3xl bg-white border border-zinc-200 p-8">
814                    <div class="text-[11px] uppercase tracking-[0.24em] font-black text-yellow-500 mb-4">Brand store</div>
815                    <h3 class="text-2xl font-black tracking-tight mb-4">České Budějovice</h3>
816                    <p class="text-zinc-600 leading-relaxed mb-8">
817                        Visit the showroom, choose models and contact the brand directly.
818                    </p>
819                    <a href="https://e-shop.leaderfox.com/dokument/znackova-prodejna/"
820                       class="inline-block bg-zinc-900 text-white hover:bg-black font-black py-4 px-6 uppercase tracking-[0.18em] text-sm transition">
821                        Visit showroom
822                    </a>
823                </div>
824
825                <div class="card-lift rounded-3xl bg-white border border-zinc-200 p-8">
826                    <div class="text-[11px] uppercase tracking-[0.24em] font-black text-yellow-500 mb-4">Partner network</div>
827                    <h3 class="text-2xl font-black tracking-tight mb-4">Dealers in Czechia and abroad</h3>
828                    <p class="text-zinc-600 leading-relaxed mb-8">
829                        Overview of places where you can buy Leader Fox bikes or consult your choice.
830                    </p>
831                    <a href="#dealer-map"
832                       class="inline-block border border-zinc-900 text-zinc-900 hover:bg-zinc-900 hover:text-white font-black py-4 px-6 uppercase tracking-[0.18em] text-sm transition">
833                        Interactive map
834                    </a>
835                </div>
836
837                <div class="card-lift rounded-3xl bg-zinc-900 text-white border border-zinc-900 p-8">
838                    <div class="text-[11px] uppercase tracking-[0.24em] font-black text-yellow-400 mb-4">Cooperation</div>
839                    <h3 class="text-2xl font-black tracking-tight mb-4">Become a dealer</h3>
840                    <p class="text-zinc-300 leading-relaxed mb-8">
841                        Are you interested in offering Leader Fox bikes or expanding the service network?
842                    </p>
843                    <a href="https://e-shop.leaderfox.com/webform4Dealer.aspx"
844                       class="inline-block bg-yellow-400 text-black hover:bg-yellow-300 font-black py-4 px-6 uppercase tracking-[0.18em] text-sm transition">
845                        Contact form
846                    </a>
847                </div>
848            </div>
849
850            <div id="dealer-map" class="rounded-3xl border border-zinc-200 bg-white overflow-hidden">
851                <div class="p-6 md:p-8 border-b border-zinc-200">
852                    <div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-5 ga
852p-4">
853
854                        <div>
855                            <label for="dealer-country" class="block text-[11px] uppercase tracking-[0.22em] font-black text-zinc-500 mb-2">Country</label>
856                            <select id="dealer-country" class="w-full rounded-2xl border border-zinc-300 px-4 py-3 text-sm bg-white focus:outline-none focus:ring-2 focus:ring-yellow-400 focus:border-yellow-400">
857                                <option value="">All countries</option>
858                            </select>
859                        </div>
860
861
862
863                        <div>
864                            <label for="dealer-scope" class="block text-[11px] uppercase tracking-[0.22em] font-black text-zinc-500 mb-2">Czech region</label>
865                            <select id="dealer-scope" disabled class="w-full rounded-2xl border border-zinc-300 px-4 py-3 text-sm bg-zinc-100 text-zinc-400 cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-yellow-400 focus:border-yellow-400">
866                                <option value="">All Czechia</option>
867                                <option value="region:Praha">— Praha</option>
868                                <option value="region:Středočeský kraj">— Středočeský kraj</option>
869                                <option value="region:Jihočeský kraj">— Jihočeský kraj</option>
870                                <option value="region:Plzeňský kraj">— Plzeňský kraj</option>
871                                <option value="region:Karlovarský kraj">— Karlovarský kraj</option>
872                                <option value="region:Ústecký kraj">— Ústecký kraj</option>
873                                <option value="region:Liberecký kraj">— Liberecký kraj</option>
874                                <option value="region:Královéhradecký kraj">— Královéhradecký kraj</option>
875                                <option value="region:Pardubický kraj">— Pardubický kraj</option>
876                                <option value="region:Kraj Vysočina">— Kraj Vysočina</option>
877                                <option value="region:Jihomoravský kraj">— Jihomoravský kraj</option>
878                                <option value="region:Olomoucký kraj">— Olomoucký kraj</option>
879                                <option value="region:Moravskoslezský kraj">— Moravskoslezský kraj</option>
880                                <option value="region:Zlínský kraj">— Zlínský kraj</option>
881                            </select>
882                        </div>
883
884
885
886                        <div>
887                            <label for="dealer-type" class="block text-[11px] uppercase tracking-[0.22em] font-black text-zinc-500 mb-2">Type of place</label>
888                            <select id="dealer-type" class="w-full rounded-2xl border border-zinc-300 px-4 py-3 text-sm bg-white focus:outline-none focus:ring-2 focus:ring-yellow-400 focus:border-yellow-400">
889                                <option value="">All</option>
890                                <option value="dealer">Dealers</option>
891                                <option value="service">Service points</option>
892                                <option value="pickup">Pickup points</option>
893                            </select>
894                        </div>
895
896
897                        <div class="xl:col-span-2">
898                            <label for="dealer-search" class="block text-[11px] uppercase tracking-[0.22em] font-black text-zinc-500 mb-2">Search</label>
899                            <input id="dealer-search" type="text" placeholder="Name, city, region, country..." class="w-full rounded-2xl border border-zinc-300 px-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-yellow-400 focus:border-yellow-400">
900                        </div>
901                    </div>
902
903                    <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-3 mt-5">
904                        <div id="dealer-count" class="text-sm text-zinc-500">Loading data…</div>
905                        <button id="dealer-reset" type="button" class="text-sm font-bold text-zinc-700 hover:text-black transition text-left md:text-right">
906                            Reset filters
907                        </button>
908                    </div>
909                    <div id="dealer-status" class="mt-3 text-sm text-zinc-500"></div>
910                </div>
911
912                <div id="dealer-map-frame" aria-label="Mapa prodejců a servisních places"></div>
913
914                <div class="p-4 md:p-6 border-t border-zinc-200 bg-zinc-50 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
915                    <div class="text-sm text-zinc-600">
916                        The map shows currently filtered dealers and service points with coordinates.
917                    </div>
918                    <a id="dealer-map-external" href="https://www.google.com/maps?q=Czechia" target="_blank" rel="noopener" class="inline-flex items-center justify-center rounded-xl border border-zinc-900 px-4 py-2 text-sm font-black text-zinc-900 hover:bg-zinc-900 hover:text-white transition">
919                        Open in large map
920                    </a>
921                </div>
922
923                <div class="p-6 md:p-8 border-t border-zinc-200">
924                    <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-3 mb-6">
925                        <h3 class="text-xl font-black tracking-tight text-zinc-900">Results</h3>
926                        <div class="text-sm text-zinc-500">Click the icon to zoom the map to the location detail</div>
927                    </div>
928
929                    <div id="dealer-list" class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-5"></div>
930
931                    <div class="flex items-center justify-between mt-8 pt-6 border-t border-zinc-200">
932                        <button id="dealer-prev" type="button" class="rounded-xl border border-zinc-300 px-4 py-2 text-sm font-bold text-zinc-700 disabled:opacity-40 disabled:cursor-not-allowed">Previous</button>
933                        <div id="dealer-page-info" class="text-sm text-zinc-500">Page 1</div>
934                        <button id="dealer-next" type="button" class="rounded-xl border border-zinc-300 px-4 py-2 text-sm font-bold text-zinc-700 disabled:opacity-40 disabled:cursor-not-allowed">Next</button>
935                    </div>
936                </div>
937            </div>
938        </div>
939    </section>
940
941    <!-- BLOG -->
942    <section id="blog" class="bg-white py-20 md:py-24">
943        <div class="max-w-7xl mx-auto px-5 md:px-8">
944            <div class="max-w-3xl mx-auto text-center mb-12">
945                <div class="section-line mx-auto mb-6"></div>
946                <p class="text-xs md:text-sm uppercase tracking-[0.35em] font-black text-yellow-500 mb-4">
947                    News and inspiration
948                </p>
949                <h2 class="text-3xl md:text-5xl font-black tracking-tight text-zinc-900 mb-6">
950                    Follow news from the world of Leader Fox.
951                </h2>
952                <p class="text-zinc-600 text-base md:text-lg leading-relaxed">
953                    New model introductions, trip tips, brand updates and more content for cycling fans.
954                </p>
955            </div>
956
957            <div id="blog-preview" class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-10"></div>
958
959            <div id="blog-fallback" class="hidden text-center mb-10">
960                <p class="text-zinc-500 text-sm">
961                    You can find current articles directly in the e-shop blog.
962                </p>
963            </div>
964
965            <div class="text-center">
966                <a href="https://e-shop.leaderfox.com/aktualita/"
967                   class="inline-block bg-zinc-900 text-white hover:bg-yellow-400 hover:text-black font-black py-4 px-8 uppercase tracking-[0.18em] text-sm transition">
968                    Go to blog
969                </a>
970            </div>
971        </div>
972    </section>
973
974    <!-- FOOTER -->
975    <footer class="bg-black text-white">
976        <div class="max-w-7xl mx-auto px-5 md:px-8 pt-16 pb-10">
977            <div class="grid grid-cols-1 md:grid-cols-3 gap-10 border-b border-zinc-800 pb-12">
978                <div>
979                    <div class="text-3xl font-black uppercase italic tracking-tight leading-none">LEADER FOX</div>
980                    <div class="mt-3 text-[11px] uppercase tracking-[0.35em] text-zinc-500 font-bold">
981                        the good ride
982                    </div>
983                </div>
984
985                <div>
986                    <div class="text-[11px] uppercase tracking-[0.26em] font-black text-zinc-500 mb-4">Quick links</div>
987                    <div class="space-y-3 text-sm text-zinc-300">
988                        <div><a href="https://e-shop.leaderfox.com" class="hover:text-white transition">E-shop</a></div>
989                        <div><a href="https://e-shop.leaderfox.com/dokument/katalog/" class="hover:text-white transition">Catalogue</a></div>
990                        <div><a href="https://e-shop.leaderfox.com/dokument/znackova-prodejna/" class="hover:text-white transition">Showroom</a></div>
991                        <div><a href="https://e-shop.leaderfox.com/dokument/kontakt/" class="hover:text-white transition">Contact</a></div>
992                    </div>
993                </div>
994
995                <div>
996                    <div class="text-[11px] uppercase tracking-[0.26em] font-black text-zinc-500 mb-4">For partners</div>
997                    <div class="space-y-3 text-sm text-zinc-300">
998                        <div><a href="#partneri" class="hover:text-white transition">Dealers and service</a></div>
999                        <div><a href="https://e-shop.leaderfox.com/webform4Dealer.aspx" class="hover:text-white transition">Become a dealer</a></div>
1000                        <div><a href="https://e-shop.leaderfox.com/aktualita/" class="hover:text-white transition">Blog</a></div>
1001                    </div>
1002                </div>
1003            </div>
1004
1005            <div class="pt-8 text-center text-[10px] uppercase tracking-[0.28em] text-zinc-600">
1006                © 2026 Leader Fox | Bohemia Bike s.r.o. | Made in Czech Republic
1007            </div>
1008        </div>
1009    </footer>
1010
1011
1012
1013    <!-- MOBILNI RYCHLE VOLBY -->
1014    <div class="floating-cta" aria-label="Rychlé volby">
1015        <a href="https://e-shop.leaderfox.com" class="rounded-xl bg-yellow-400 px-4 py-3 text-center text-xs font-black uppercase tracking-[0.16em] text-black">
1016            E-shop
1017        </a>
1018        <a href="#partneri" class="rounded-xl border border-white/30 px-4 py-3 text-center text-xs font-black uppercase tracking-[0.16em] text-white">
1019            Dealers
1020        </a>
1021    </div>
1022
1023
1024    
1024<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
1024
1025    
1025<script src="https://unpkg.com/[email protected]/dist/leaflet.markercluster.js"></script>
1025
1026
1027    
1027<script>
1028        const revealObserver = new IntersectionObserver((entries) => {
1029            entries.forEach(entry => {
1030                if (entry.isIntersecting) {
1031                    entry.target.classList.add('is-visible');
1032                    revealObserver.unobserve(entry.target);
1033                }
1034            });
1035        }, { threshold: 0.12 });
1036
1037        document.querySelectorAll('.reveal').forEach(element => revealObserver.observe(element));
1038
1039        /*
1040         * Jemnější rolování kolečkem myši.
1041         * Nemění obsah stránky, menu ani funkce prodejců.
1042         * Platí jen pro desktop / myš; mobilní touch scroll zůstává nativní.
1043         */
1044        function initGentleWheelScroll() {
1045            const isDesktopPointer = window.matchMedia('(min-width: 768px) and (pointer: fine)').matches;
1046            const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
1047
1048            if (!isDesktopPointer || reducedMotion) return;
1049
1050            let targetY = window.scrollY;
1051            let currentY = window.scrollY;
1052            let isAnimating = false;
1053
1054            const maxScroll = () => Math.max(0, document.documentElement.scrollHeight - window.innerHeight);
1055
1056            function normalizeWheelDelta(event) {
1057                if (event.deltaMode === 1) return event.deltaY * 16;
1058                if (event.deltaMode === 2) return event.deltaY * window.innerHeight;
1059                return event.deltaY;
1060            }
1061
1062            function animateScroll() {
1063                currentY += (targetY - currentY) * 0.22;
1064
1065                if (Math.abs(targetY - currentY) < 0.5) {
1066                    currentY = targetY;
1067                    isAnimating = false;
1068                }
1069
1070                window.scrollTo(0, currentY);
1071
1072                if (isAnimating) {
1073                    requestAnimationFrame(animateScroll);
1074                }
1075            }
1076
1077            window.addEventListener('wheel', (event) => {
1078                const tagName = event.target && event.target.tagName ? event.target.tagName.toLowerCase() : '';
1079                const isFormControl = ['input', 'textarea', 'select', 'option'].includes(tagName);
1080                const isEmbeddedMap = event.target && event.target.closest && event.target.closest('#dealer-map-frame');
1081
1082                if (isFormControl || isEmbeddedMap || event.ctrlKey) return;
1083
1084                event.preventDefault();
1085
1086                const delta = normalizeWheelDelta(event);
1087                targetY = Math.max(0, Math.min(maxScroll(), targetY + delta * 0.48));
1088
1089                if (!isAnimating) {
1090                    currentY = window.scrollY;
1091                    isAnimating = true;
1092                    requestAnimationFrame(animateScroll);
1093                }
1094            }, { passive: false });
1095
1096            window.addEventListener('scroll', () => {
1097                if (!isAnimating) {
1098                    targetY = window.scrollY;
1099                    currentY = window.scrollY;
1100                }
1101            }, { passive: true });
1102        }
1103
1104        initGentleWheelScroll();
1105
1106
1107        let dealerData = [];
1108        let filteredData = [];
1109        let currentPage = 1;
1110        const PAGE_SIZE = 12;
1111        let activeCardId = null;
1112        let searchFilledFromMarker = false;
1113
1114        const $search = document.getElementById('dealer-search');
1115        const $type = document.getElementById('dealer-type');
1116        const $scope = document.getElementById('dealer-scope');
1117        const $country = document.getElementById('dealer-country');
1118        const $count = document.getElementById('dealer-count');
1119        const $list = document.getElementById('dealer-list');
1120        const $pageInfo = document.getElementById('dealer-page-info');
1121        const $prev = document.getElementById('dealer-prev');
1122        const $next = document.getElementById('dealer-next');
1123        const $reset = document.getElementById('dealer-reset');
1124        const $status = document.getElementById('dealer-status');
1125        const $mapExternal = document.getElementById('dealer-map-external');
1126
1127        let dealerMap = null;
1128        let dealerCluster = null;
1129        let dealerMarkers = new Map();
1130        let czechRegionLayer = null;
1131        let czechRegionLoadStarted = false;
1132
1133        const CZECH_REGION_BOUNDARY_PATHS = [
1134            'kraje.json',
1135            'data/kraje.json',
1136            'https://raw.githubusercontent.com/siwekm/czech-geojson/master/kraje.json'
1137        ];
1138
1139
1140        const CZECH_REGIONAL_HUBS = [
1141            { name: 'Praha a Střední Čechy', point: [14.4378, 50.0755] },
1142            { name: 'České Budějovice / Jižní Čechy', point: [14.4743, 48.9745] },
1143            { name: 'Plzeň / Západní Čechy', point: [13.3776, 49.7384] },
1144            { name: 'Karlovy Vary / Chebsko', point: [12.8712, 50.2319] },
1145            { name: 'Ústí nad Labem / Severozápad', point: [14.0323, 50.6607] },
1146            { name: 'Liberec / Severní Čechy', point: [15.0543, 50.7663] },
1147            { name: 'Hradec Králové / Východní Čechy', point: [15.8328, 50.2092] },
1148            { name: 'Pardubice / Východní Čechy', point: [15.7792, 50.0343] },
1149            { name: 'Jihlava / Vysočina', point: [15.5903, 49.3961] },
1150            { name: 'Brno / Jižní Morava', point: [16.6068, 49.1951] },
1151            { name: 'Zlín / Východní Morava', point: [17.6660, 49.2244] },
1152            { name: 'Olomouc / Střední Morava', point: [17.2518, 49.5938] },
1153            { name: 'Ostrava / Severní Morava', point: [18.2625, 49.8209] }
1154        ];
1155
1156        const CITY_POINTS_FOR_REGION = {
1157            'Praha': [14.4378, 50.0755], 'Brno': [16.6068, 49.1951], 'České Budějovice': [14.4743, 48.9745],
1158            'Plzeň': [13.3776, 49.7384], 'Ostrava': [18.2625, 49.8209], 'Olomouc': [17.2518, 49.5938],
1159            'Zlín': [17.6660, 49.2244], 'Liberec': [15.0543, 50.7663], 'Pardubice': [15.7792, 50.0343],
1160            'Hradec Králové': [15.8328, 50.2092], 'Jihlava': [15.5903, 49.3961], 'Karlovy Vary': [12.8712, 50.2319],
1161            'Ústí Nad Labem': [14.0323, 50.6607], 'Tábor': [14.6578, 49.4144], 'Třebíč': [15.8817, 49.2149],
1162            'Prostějov': [17.1118, 49.4719], 'Rokycany': [13.5946, 49.7427], 'Jablonec Nad Nisou': [15.1681, 50.7243],
1163            'Mladá Boleslav': [14.9032, 50.4114], 'Strakonice': [13.9024, 49.2615], 'Prachatice': [13.9976, 49.0129],
1164            'Chomutov': [13.4178, 50.4605], 'Studénka': [18.0787, 49.7234], 'Vlašim': [14.8988, 49.7063],
1165            'Znojmo': [16.0488, 48.8555], 'Sušice': [13.5202, 49.2311], 'Ivančice': [16.3775, 49.1014],
1166            'Kyjov': [17.1225, 49.0102], 'Český Krumlov': [14.3152, 48.8127], 'Písek': [14.1475, 49.3088],
1167            'Klatovy': [13.2951, 49.3955], 'Hodonín': [17.1324, 48.8489], 'Břeclav': [16.8820, 48.7589],
1168            'Kolín': [15.2006, 50.0281], 'Kadaň': [13.2713, 50.3833], 'Žďár Nad Sázavou': [15.9392, 49.5626],
1169            'Litoměřice': [14.1318, 50.5335], 'Opava': [17.9026, 49.9387], 'Karviná': [18.5417, 49.8540],
1170            'Přerov': [17.4509, 49.4551], 'Uherské Hradiště': [17.4597, 49.0698], 'Vrchlabí': [15.6094, 50.6269]
1171        };
1172
1173        function normalizeCountryForRegion(value) {
1174            const raw = String(value || '').trim();
1175            const lower = raw.toLowerCase();
1176            const aliases = {
1177                'cz': 'Czechia',
1178                'čr': 'Czechia',
1179                'czechia': 'Czechia',
1180                'czech republic': 'Czechia'
1181            };
1182            return aliases[lower] || raw;
1183        }
1184
1185        function normalizeCityForRegion(value) {
1186            let city = String(value || '').trim().replace(/\s+/g, ' ');
1187            if (!city) return '';
1188            city = city.replace(/\s*\(.*?\)\s*/g, ' ');
1189            city = city.replace(/\s*-\s*.*$/g, '');
1190            city = city.trim().replace(/\s+/g, ' ');
1191            const lower = city.toLowerCase();
1192            if (lower.startsWith('praha')) return 'Praha';
1193            if (lower.startsWith('brno')) return 'Brno';
1194            if (lower.startsWith('plzeň') || lower.startsWith('plzen')) return 'Plzeň';
1195            if (lower.startsWith('ostrava')) return 'Ostrava';
1196            if (lower.startsWith('hradec králové') || lower.startsWith('hradec kralove')) return 'Hradec Králové';
1197            if (lower.startsWith('české budějovice') || lower.startsWith('ceske budejovice')) return 'České Budě
1197jovice';
1198            if (lower.startsWith('znojmo')) return 'Znojmo';
1199            if (lower.startsWith('břeclav') || lower.startsWith('breclav')) return 'Břeclav';
1200            if (lower.startsWith('ústí nad labem') || lower.startsWith('usti nad labem')) return 'Ústí Nad Labem';
1201            return city.toLowerCase().split(' ').filter(Boolean).map(part => part.charAt(0).toUpperCase() + part.slice(1)).join(' ');
1202        }
1203
1204        function distanceSquaredForRegion(pointA, pointB) {
1205            const lonDiff = pointA[0] - pointB[0];
1206            const latDiff = pointA[1] - pointB[1];
1207            return lonDiff * lonDiff + latDiff * latDiff;
1208        }
1209
1210        function nearestRegionalHubForIndex(point) {
1211            if (!point) return null;
1212            let bestHub = null;
1213            let bestDistance = Infinity;
1214            CZECH_REGIONAL_HUBS.forEach(hub => {
1215                const distance = distanceSquaredForRegion(point, hub.point);
1216                if (distance < bestDistance) {
1217                    bestDistance = distance;
1218                    bestHub = hub;
1219                }
1220            });
1221            return bestHub;
1222        }
1223
1224        function itemRegionalHubName(item) {
1225            if (normalizeCountryForRegion(item.country) !== 'Czechia') return '';
1226            const city = normalizeCityForRegion(item.city);
1227            const point = hasCoordinates(item) ? [Number(item.lon), Number(item.lat)] : CITY_POINTS_FOR_REGION[city];
1228            const hub = nearestRegionalHubForIndex(point);
1229            return hub ? hub.name : '';
1230        }
1231
1232        function normalizeWebsite(url) {
1233            if (!url) return '';
1234            const value = String(url).trim();
1235            if (!value) return '';
1236            if (/^https?:\/\//i.test(value)) return value;
1237            return 'https://' + value.replace(/^\/+/, '');
1238        }
1239
1240        function normalizePhone(phone) {
1241            if (!phone) return '';
1242            return String(phone).replace(/[^\d+]/g, '');
1243        }
1244
1245        function escapeHtml(value) {
1246            return String(value || '')
1247                .replace(/&/g, '&amp;')
1248                .replace(/</g, '&lt;')
1249                .replace(/>/g, '&gt;')
1250                .replace(/"/g, '&quot;')
1251                .replace(/'/g, '&#39;');
1252        }
1253
1254
1255        function normalizeSearchText(value) {
1256            return String(value || '')
1257                .toLowerCase()
1258                .normalize('NFD')
1259                .replace(/[\u0300-\u036f]/g, '')
1260                .replace(/\s+/g, ' ')
1261                .trim();
1262        }
1263
1264        function isCzechCountry(value) {
1265            const normalized = normalizeSearchText(value);
1266            return ['ceska republika', 'czech republic', 'czechia', 'cz', 'cr'].includes(normalized);
1267        }
1268
1269        function selectedCountryIsCzechRepublic() {
1270            return isCzechCountry($country.value);
1271        }
1272
1273        function updateCzechRegionFilterState() {
1274            const enabled = selectedCountryIsCzechRepublic();
1275
1276            $scope.disabled = !enabled;
1277            $scope.classList.toggle('bg-zinc-100', !enabled);
1278            $scope.classList.toggle('text-zinc-400', !enabled);
1279            $scope.classList.toggle('cursor-not-allowed', !enabled);
1280            $scope.classList.toggle('bg-white', enabled);
1281            $scope.classList.toggle('text-zinc-900', enabled);
1282
1283            if (!enabled) {
1284                $scope.value = '';
1285            }
1286        }
1287
1288        function itemSearchHaystack(item) {
1289            return normalizeSearchText([
1290                item.name,
1291                item.city,
1292                item.country,
1293                item.street,
1294                item.person,
1295                item.email,
1296                item.web,
1297                item.addressLabel,
1298                item.geoQuery,
1299                item.geocodeDisplayName,
1300                item.isPickupPoint ? 'výdejní placeso vydejni misto pickup point' : ''
1301            ].filter(Boolean).join(' '));
1302        }
1303
1304        function buildExternalMapUrl(item) {
1305            if (item && hasCoordinates(item)) {
1306                return `https://www.google.com/maps?q=${encodeURIComponent(Number(item.lat) + ',' + Number(item.lon))}`;
1307            }
1308
1309            return `https://www.google.com/maps?q=${encodeURIComponent(buildMapQuery(item))}`;
1310        }
1311
1312        function getBadge(itemOrType, scope) {
1313            const item = typeof itemOrType === 'object' && itemOrType ? itemOrType : null;
1314            const labels = [];
1315
1316            if (item) {
1317                labels.push('Dealer');
1318                if (item.isServicePoint || item.type === 'service') labels.push('Service point');
1319                if (item.isPickupPoint) labels.push('Pickup point');
1320
1321                const scopeLabel = item.scope === 'foreign' ? 'abroad' : 'Czechia';
1322                return `${labels.join(' • ')} • ${scopeLabel}`;
1323            }
1324
1325            const typeLabel = itemOrType === 'service'
1326                ? 'Service point'
1327                : (itemOrType === 'pickup' ? 'Pickup point' : 'Dealer');
1328            const scopeLabel = scope === 'foreign' ? 'abroad' : 'Czechia';
1329            return `${typeLabel} • ${scopeLabel}`;
1330        }
1331
1332        function buildAddress(item) {
1333            return [item.street, item.city, item.country].filter(
1333Boolean).join(', ');
1334        }
1335
1336        function buildMapQuery(item) {
1337            if (!item) return 'Czechia';
1338            const parts = [item.name, item.street, item.city, item.country].filter(Boolean);
1339            return parts.join(', ');
1340        }
1341
1342        function hasCoordinates(item) {
1343            return Number.isFinite(Number(item.lat)) && Number.isFinite(Number(item.lon));
1344        }
1345
1346
1347        function clusterTier(markers) {
1348            const tiers = markers
1349                .map(marker => marker.options && marker.options.leaderfoxTier)
1350                .filter(Boolean);
1351
1352            if (tiers.includes('gold')) return 'gold';
1353            if (tiers.includes('silver')) return 'silver';
1354            if (tiers.includes('bronze')) return 'bronze';
1355            return 'standard';
1356        }
1357
1358        function clusterIconCreate(cluster) {
1359            const markers = cluster.getAllChildMarkers();
1360            const tier = clusterTier(markers);
1361            const count = cluster.getChildCount();
1362            const sizeClass = count < 10 ? 'marker-cluster-small' : (count < 100 ? 'marker-cluster-medium' : 'marker-cluster-large');
1363            const tierClass = tier !== 'standard' ? ` cluster-${tier}` : '';
1364
1365            return L.divIcon({
1366                html: `<div><span>${count}</span></div>`,
1367                className: `marker-cluster ${sizeClass}${tierClass}`,
1368                iconSize: L.point(40, 40)
1369            });
1370        }
1371
1372        function regionNameFromFeature(feature) {
1373            const props = feature && feature.properties ? feature.properties : {};
1374            return props.NAZEV ||
1375                props.NAZEV_KRAJ ||
1376                props.NAZ_CZNUTS3 ||
1377                props.name ||
1378                props.NAME ||
1379                props.nazev ||
1380                props.KOD_NUTS3 ||
1381                '';
1382        }
1383
1384        function styleCzechRegionBoundary() {
1385            return {
1386                color: '#a16207',
1387                weight: 2.4,
1388                opacity: 0.95,
1389                fillColor: '#a16207',
1390                fillOpacity: 0.035,
1391                dashArray: '',
1392                interactive: true
1393            };
1394        }
1395
1396        async function loadCzechRegionBoundaries() {
1397            if (!dealerMap || czechRegionLoadStarted) return;
1398            czechRegionLoadStarted = true;
1399
1400            for (const path of CZECH_REGION_BOUNDARY_PATHS) {
1401                try {
1402                    const response = await fetch(path + (path.includes('?') ? '&' : '?') + 'v=' + Date.now());
1403
1404                    if (!response.ok) continue;
1405
1406                    const geojson = await response.json();
1407
1408                    if (dealerMap.getPane('czech-regions-pane') === undefined) {
1409                        dealerMap.createPane('czech-regions-pane');
1410                        dealerMap.getPane('czech-regions-pane').style.zIndex = 420;
1411                        dealerMap.getPane('czech-regions-pane').style.pointerEvents = 'auto';
1412                    }
1413
1414                    czechRegionLayer = L.geoJSON(geojson, {
1415                        pane: 'czech-regions-pane',
1416                        style: styleCzechRegionBoundary,
1417                        onEachFeature: (feature, layer) => {
1418                            const regionName = regionNameFromFeature(feature);
1419
1420                            if (regionName) {
1421                                layer.bindTooltip(regionName, {
1422                                    sticky: true,
1423                                    direction: 'top',
1424                                    className: 'czech-region-tooltip'
1425                                });
1426                            }
1427
1428                            layer.on('mouseover', () => {
1429                                layer.setStyle({
1430                                    color: '#854d0e',
1431                                    weight: 3.6,
1432                                    opacity: 1,
1433                                    fillOpacity: 0.10
1434                                });
1435                            });
1436
1437                            layer.on('mouseout', () => {
1438                                czechRegionLayer.resetStyle(layer);
1439                            });
1440                        }
1441                    }).addTo(dealerMap);
1442
1443                    return;
1444                } catch (e) {}
1445            }
1446
1447            console.warn('Hranice krajů ČR se nepodařilo načíst.');
1448        }
1449
1450        function initDealerMap() {
1451            if (dealerMap) return;
1452
1453            dealerMap = L.map('dealer-map-frame', {
1454                scrollWheelZoom: false
1455            }).setView([49.8, 15.5], 7);
1456
1457            L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
1458                maxZoom: 19,
1459                attribution: '&copy; OpenStreetMap'
1460            }).addTo(dealerMap);
1461
1462            dealerCluster = L.markerClusterGroup({
1463                showCoverageOnHover: false,
1464                spiderfyOnMaxZoom: true,
1465                maxClusterRadius: 48,
1466                iconCreateFunction: clusterIconCreate
1467            });
1468
1469            dealerMap.addLayer(dealerCluster);
1470            loadCzechRegionBoundaries();
1471        }
1472
1473
1474        function getPremiumLabel(item) {
1475            if (!item || !item.isPremiumDealer) return '';
1476            if (item.leaderfoxTierLabel) return item.leaderfoxTierLabel;
1477            if (item.leaderfoxTier === 'gold') return 'Zlatý partner';
1478            if (item.leaderfoxTier === 'silver') return 'Stříbrný partner';
1479            if (item.leaderfoxTier === 'bronze') return 'Bronzový partner';
1480            return 'Prémiový partner';
1481        }
1482
1483        function getPremiumBadgeHtml(item) {
1484            const label = getPremiumLabel(item);
1485            if (!label) return '';
1486            const tier = item.leaderfoxTier || 'premium';
1487            return `<span class="premium-badge ${escapeHtml(tier)}">${escapeHtml(label)}</span>`;
1488        }
1489
1490        function premiumFilterMatches(item, value) {
1491            if (!value) return true;
1492            if (value === 'premium') return !!item.isPremiumDealer;
1493            return item.leaderfoxTier === value;
1494        }
1495
1496        function sortDealerItems(items) {
1497            return [...items].sort((a, b) => {
1498                const ar = Number.isFinite(Number(a.leaderfoxRank)) ? Number(a.leaderfoxRank) : 999999;
1499                const br = Number.isFinite(Number(b.leaderfoxRank)) ? Number(b.leaderfoxRank) : 999999;
1500                if (ar !== br) return ar - br;
1501                return String(a.name || '').localeCompare(String(b.name || ''), 'cs');
1502            });
1503        }
1504
1505        function markerIcon(item) {
1506            const iconSymbol = (item.isServicePoint || item.type === 'service') ? '🔧' : (item.isPickupPoint ? '📦' : '🚲');
1507            let className = (item.isServicePoint || item.type === 'service') ? 'service' : (item.isPickupPoint ? 'pickup' : 'dealer');
1508
1509            if (item.isPremiumDealer && item.leaderfoxTier === 'gold') {
1510                className = 'gold';
1511            } else if (item.isPremiumDealer && item.leaderfoxTier === 'silver') {
1512                className = 'silver';
1513            } else if (item.isPremiumDealer && item.leaderfoxTier === 'bronze') {
1514                className = 'bronze';
1515            }
1516
1517            return L.divIcon({
1518                className: 'dealer-type-icon-wrap',
1519                html: `<span class="dealer-type-icon ${escapeHtml(className)}" aria-hidden="true">${iconSymbol}</span>`,
1520                iconSize: [38, 38],
1521                iconAnchor: [19, 19],
1522                popupAnchor: [0, -22]
1523            });
1524        }
1525
1526        function popupHtml(item) {
1527            const address = buildAddress(item);
1528            const website = normalizeWebsite(item.web);
1529            const phone = normalizePhone(item.phone);
1530
1531            return `
1532                <div class="dealer-map-popup">
1533                    <div class="dealer-map-popup-head">
1534                        <div class="dealer-map-popup-title">${escapeHtml(item.name || '')}</div>
1535                        <div class="dealer-map-popup-strip" style="--partner-strip-color:${partnerStripColor(item)}"></div>
1536                    </div>
1537                    ${address ? `<div class="dealer-map-popup-text">${escapeHtml(address)}</div>` : ''}
1538                    ${item.phone ? `<div class="dealer-map-popup-text">Tel.: <a href="tel:${escapeHtml(phone)}">${escapeHtml(item.phone)}</a></div>` : ''}
1539                    ${item.email ? `<div class="dealer-map-popup-text">E-mail: <a href="mailto:${escapeHtml(item.email)}">${escapeHtml(item.email)}</a></div>` : ''}
1540                    ${website ? `<div class="dealer-map-popup-text">Web: <a href="${escapeHtml(website)}" target="_blank" rel="noopener">${escapeHtml(website.replace(/^https?:\/\//, ''))}</a></div>` : ''}
1541                    <div style="display:flex; flex-direction:column; gap:6px; margin-top:8px;">
1542                        <a href="${escapeHtml(buildExternalMapUrl(item))}" target="_blank" rel="noopener" class="dealer-map-popup-link">Open in maps</a>
1543                        <a href="#dealer-list" class="dealer-map-popup-link" data-popup-id="${escapeHtml(item.id)}">Show in list</a>
1544                    </div>
1545                </div>
1546            `;
1547        }
1548
1549        function renderDealerMap(items, focusItem = null, labelText = '', globalDefault = false) {
1550            initDealerMap();
1551
1552            dealerCluster.clearLayers();
1553            dealerMarkers.clear();
1554
1555            const itemsWithCoordinates = items.filter(hasCoordinates);
1556
1557            itemsWithCoordinates.forEach(item => {
1558                const marker = L.marker([Number(item.lat), Number(item.lon)], {
1559                    icon: markerIcon(item),
1560                    leaderfoxTier: item.isPremiumDealer ? item.leaderfoxTier : ''
1561                });
1562                marker.bindPopup(popupHtml(item));
1563                marker.on('click', () => {
1564                    filteredData = [item];
1565                    currentPage = 1;
1566                    $search.value = item.name || '';
1567                    searchFilledFromMarker = true;
1568                    $type.value = '';
1569                    $scope.value = '';
1570                    $country.value = '';
1571        
1572                    renderCurrentPage();
1573                    renderDealerMap([item], item, `The map and list show the company: ${item.name || ''}`);
1574                    setActiveCard(item.id);
1575
1576                    dealerMap.setView([Number(item.lat), Number(item.lon)], Math.max(dealerMap.getZoom(), 16));
1577                    $mapExternal.href = buildExternalMapUrl(item);
1578
1579                    const markerAfterRender = dealerMarkers.get(item.id);
1580                    if (markerAfterRender) {
1581                        markerAfterRender.openPopup();
1582                    }
1583
1584                    document.getElementById('dealer-map').scrollIntoView({ behavior: 'smooth', block: 'start' });
1585                });
1586                marker.on('dblclick', () => {
1587                    const itemIndex = filteredData.findIndex(found => found.id === item.id);
1588
1589                    if (itemIndex >= 0) {
1590                        currentPage = Math.floor(itemIndex / PAGE_SIZE) + 1;
1591                        renderCurrentPage();
1592
1593                        setTimeout(() => {
1594                            setActiveCard(item.id);
1595                            const card = document.querySelector(`.dealer-card[data-id="${CSS.escape(item.id)}"]`);
1596
1597                            if (card) {
1598                                card.scrollIntoView({ behavior: 'smooth', block: 'center' });
1599                                card.classList.add('ring-4','ring-yellow-400');
1600                                setTimeout(() => card.classList.remove('ring-4','ring-yellow-400'), 2000);
1601                            }
1602                        }, 120);
1603                    }
1604                });
1605                dealerMarkers.set(item.id, marker);
1606                dealerCluster.addLayer(marker);
1607            });
1608
1609            if (focusItem && hasCoordinates(focusItem)) {
1610                const marker = dealerMarkers.get(focusItem.id);
1611                dealerMap.setView([Number(focusItem.lat), Number(focusItem.lon)], 15);
1612                if (marker) marker.openPopup();
1613                $mapExternal.href = buildExternalMapUrl(focusItem);
1614            } else if (itemsWithCoordinates.length) {
1615                if (globalDefault) {
1616                    dealerMap.setView([20, 0], 2);
1617                    $mapExternal.href = 'https://www.google.com/maps?q=world';
1618                } else {
1619                    const bounds = L.latLngBounds(itemsWithCoordinates.map(item => [Number(item.lat), Number(item.lon)]));
1620                    dealerMap.fitBounds(bounds, { padding: [36, 36], maxZoom: 13 });
1621                    const first = itemsWithCoordinates[0];
1622                    $mapExternal.href = buildExternalMapUrl(first);
1623                }
1624            } else {
1625                dealerMap.setView([20, 0], 2);
1626                $mapExternal.href = 'https://www.google.com/maps?q=world';
1627            }
1628
1629            const withoutCoordinates = items.length - itemsWithCoordinates.length;
1630            if (labelText) {
1631                $status.textContent = labelText;
1632            } else if (itemsWithCoordinates.length) {
1633                $status.textContent = `The map shows ${itemsWithCoordinates.length} places with coordinates.` + (withoutCoordinates ? ` ${withoutCoordinates} places do not yet have coordinates.` : '');
1634            } else {
1635                $status.textContent = 'The current selection does not yet contain any records with coordinates.';
1636            }
1637        }
1638
1639        function fillCountryFilter(data) {
1640            const countries = [...new Set(data.map(item => item.country).filter(Boolean))].sort((a, b) => a.localeCompare(b, 'cs'));
1641            $country.innerHTML = '<option value="">All countries</option>' + countries.map(country => `<option value="${escapeHtml(country)}">${escapeHtml(country)}</option>`).join('');
1642        }
1643
1644        function partnerStripColor(item) {
1645            if (item && item.isPremiumDealer && item.leaderfoxTier === 'gold') return '#facc15';
1646            if (item && item.isPremiumDealer && item.leaderfoxTier === 'silver') return '#d4d4d8';
1647            if (item && item.isPremiumDealer && item.leaderfoxTier === 'bronze') return '#b45309';
1648            return '#86efac';
1649        }
1650
1651        function pickupPointBadgeHtml(item) {
1652            return '';
1653        }
1654
1655        function itemCardHtml(item) {
1656            const address = buildAddress(item);
1657            const website = normalizeWebsite(item.web);
1658            const phone = normalizePhone(item.phone);
1659
1660            return `
1661                <div class="dealer-card w-full rounded-3xl border border-zinc-200 bg-white p-5 pl-7 hover:border-yellow-400 hover:bg-yellow-50/40 transition ${item.isPremiumDealer ? 'dealer-card-premium' : ''}" data-id="${escapeHtml(item.id)}" style="--partner-strip-color:${partnerStripColor(item)}">
1662                    <div class="flex flex-wrap items-center gap-2 mb-2"><span class="text-[11px] uppercase tracking-[0.18em] font-black text-yellow-600">${escapeHtml(getBadge(item))}</span>${pickupPointBadgeHtml(item)}</div>
1663                    <div class="text-lg font-black text-zinc-900 leading-tight mb-2">${escapeHtml(item.name || '')}</div>
1664                    ${address ? `<div class="text-sm text-zinc-600 mb-3">${escapeHtml(address)}</div>` : ''}
1665
1666                    <div class="space-y-1 text-sm text-zinc-500 mb-4">
1667                        ${item.person ? `<div>${escapeHtml(item.person)}</div>` : ''}
1668                        ${item.phone ? `<div>Tel.: <a class="dealer-link" href="tel:${escapeHtml(phone)}">${escapeHtml(item.phone)}</a></div>` : ''}
1669                        ${item.email ? `<div>E-mail: <a class="dealer-link" href="mailto:${escapeHtml(item.email)}">${escapeHtml(item.email)}</a></div>` : ''}
1670                        ${website ? `<div>Web: <a class="dealer-link" href="${escapeHtml(website)}" target="_blank" rel="noopener">${escapeHtml(website.replace(/^https?:\/\//, ''))}</a></div>` : ''}
1671                    </div>
1672
1673                    <button type="button" class="dealer-focus inline-flex items-center justify-center rounded-xl border border-zinc-900 px-4 py-2 text-sm font-black text-zinc-900 hover:bg-zinc-900 hover:text-white transition" data-id="${escapeHtml(item.id)}">
1674                        Show on map
1675                    </button>
1676                </div>
1677            `;
1678        }
1679
1680        function clearActiveCards() {
1681            document.querySelectorAll('.dealer-card').forEach(card => card.classList.remove('dealer-card-active'));
1682        }
1683
1684        function setActiveCard(itemId) {
1685            activeCardId = itemId;
1686            clearActiveCards();
1687            const card = document.querySelector(`.dealer-card[data-id="${CSS.escape(itemId)}"]`);
1688            if (card) {
1689                card.classList.add('dealer-card-active');
1690            }
1691        }
1692
1693        function getPageItems() {
1694            const start = (currentPage - 1) * PAGE_SIZE;
1695            return filteredData.slice(start, start + PAGE_SIZE);
1696        }
1697
1698        function showDealerOnMap(itemId, scrollToMap = false) {
1699            const item = dealerData.find(x => x.id === itemId);
1700            if (!item) return;
1701
1702            renderDealerMap(filteredData, item, hasCoordinates(item)
1703                ? `The map shows the company: ${item.name || ''}`
1704                : `Firma ${item.name || ''} does not yet have lat/lon coordinates in the JSON.`);
1705
1706            setActiveCard(itemId);
1707
1708            if (scrollToMap) {
1709                document.getElementById('dealer-map').scrollIntoView({ behavior: 'smooth', block: 'start' });
1710            }
1711        }
1712
1713        function applyFilters() {
1714            const q = normalizeSearchText(($search.value || '').trim());
1715            const type = $type.value;
1716            const scope = $scope.value;
1717            const country = $country.value;
1718            const selectedRegion = scope && scope.startsWith('region:') ? scope.slice(7) : '';
1719            const selectedRegionNormalized = normalizeSearchText(selectedRegion);
1720
1721            filteredData = dealerData.filter(item => {
1722                const haystack = itemSearchHaystack(item);
1723
1724                if (q && !haystack.includes(q)) return false;
1725                if (type === 'pickup' && !item.isPickupPoint) return false;
1726                if (type === 'service' && !(item.isServicePoint || item.type === 'service')) return false;
1727                if (type === 'dealer' && item.type !== 'dealer') return false;
1728                if (country && item.country !== country) return false;
1729
1730                if (selectedRegion && selectedCountryIsCzechRepublic()) {
1731                    if (!isCzechCountry(item.country)) return false;
1732                    if (!haystack.includes(selectedRegionNormalized)) return false;
1733                }
1734
1735
1736                return true;
1737            });
1738
1739            filteredData = sortDealerItems(filteredData);
1740            currentPage = 1;
1741            renderCurrentPage();
1742        }
1743
1744        function renderCurrentPage() {
1745            activeCardId = null;
1746
1747            const total = filteredData.length;
1748            const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));
1749
1750            if (currentPage > totalPages) currentPage = totalPages;
1751
1752            const pageItems = getPageItems();
1753
1754            $count.textContent = total ? `Found ${total} places` : 'No places found';
1755            $pageInfo.textContent = `Page ${currentPage} z ${totalPages}`;
1756            $prev.disabled = currentPage <= 1;
1757            $next.disabled = currentPage >= totalPages;
1758
1759            if (!pageItems.length) {
1760                $list.innerHTML = '<div class="md:col-span-2 xl:col-span-3 rounded-2xl border border-dashed border-zinc-300 p-5 text-sm text-zinc-500">No places were found for the selected filter.</div>';
1761                renderDealerMap([], null, 'No places were found for the selected filter.');
1762                return;
1763            }
1764
1765            $list.innerHTML = pageItems.map(item => itemCardHtml(item)).join('');
1766
1767            document.querySelectorAll('.dealer-focus').forEach(button => {
1768                button.addEventListener('click', (event) => {
1769                    event.preventDefault();
1770                    event.stopPropagation();
1771                    showDealerOnMap(button.dataset.id, true);
1772                });
1773            });
1774
1775            const firstItem = pageItems[0];
1776            if (firstItem) {
1777                const hasActiveFilter = Boolean(
1778                    $search.value.trim() ||
1779                    $type.value ||
1780                    $scope.value ||
1781                    $country.value
1782                );
1783
1784                if (hasActiveFilter) {
1785                    renderDealerMap(filteredData, null);
1786                    setActiveCard(firstItem.id);
1787                } else {
1788                    renderDealerMap(filteredData, null, 'The map is currently not filtered and shows the overall overview.', true);
1789                    clearActiveCards();
1790                }
1791            }
1792        }
1793
1794        async function loadDealerData() {
1795            const paths = [
1796                'data/leaderfox-locations.json',
1797                'leaderfox-locations.json'
1798            ];
1799
1800            for (const path of paths) {
1801                try {
1802                    const response = await fetch(path + '?v=' + Date.now());
1803                    if (response.ok) {
1804                        return await response.json();
1805                    }
1806                } catch (e) {}
1807            }
1808
1809            throw new Error('The partner data file was not found.');
1810        }
1811
1812        async function initDealers() {
1813            try {
1814                dealerData = sortDealerItems(await loadDealerData());
1815                fillCountryFilter(dealerData);
1816                updateCzechRegionFilterState();
1817                filteredData = sortDealerItems(dealerData);
1818
1819                const params = new URLSearchParams(window.location.search);
1820                const partnerSearch = params.get('partnerSearch');
1821                const partnerRegion = params.get('partnerRegion');
1822                const partnerType = params.get('partnerType');
1823
1824                if (partnerType && $type) {
1825                    $type.value = partnerType;
1826                }
1827
1828                if (partnerRegion) {
1829                    const czechCountryOption = Array.from($country.options).find(option => isCzechCountry(option.value));
1830
1831                    if (czechCountryOption) {
1832                        $country.value = czechCountryOption.value;
1833                    }
1834
1835                    updateCzechRegionFilterState();
1836
1837                    const regionOption = Array.from($scope.options).find(option => option.value === 'region:' + partnerRegion);
1838
1839                    if (regionOption && !$scope.disabled) {
1840                        $scope.value = regionOption.value;
1841                        applyFilters();
1842                    } else {
1843                        $search.value = partnerRegion;
1844                        filteredData = sortDealerItems(dealerData.filter(item => {
1845                            if (itemRegionalHubName(item) !== partnerRegion) return false;
1846                            if (partnerType === 'pickup' && !item.isPickupPoint) return false;
1847                            if (partnerType === 'service' && !(item.isServicePoint || item.type === 'service')) return false;
1848                            if (partnerType === 'dealer' && item.type !== 'dealer') return false;
1849                            return true;
1850                        }));
1851                        currentPage = 1;
1852                        renderCurrentPage();
1853                    }
1854
1855                    setTimeout(() => {
1856                        document.getElementById('partneri').scrollIntoView({
1857                            behavior: 'smooth',
1858                            block: 'start'
1859                        });
1860                    }, 250);
1861                } else if (partnerSearch) {
1862                    $search.value = partnerSearch;
1863                    applyFilters();
1864
1865                    setTimeout(() => {
1866                        document.getElementById('partneri').scrollIntoView({
1867                            behavior: 'smooth',
1868                            block: 'start'
1869                        });
1870                    }, 250);
1871                } else {
1872                    renderCurrentPage();
1873                }
1874            } catch (e) {
1875                console.error(e);
1876                $count.textContent = 'Partner data could not be loaded.';
1877                $status.textContent = '';
1878                $list.innerHTML = '<div class="md:col-span-2 xl:col-span-3 rounded-2xl border border-dashed border-red-300 p-5 text-sm text-red-600">The leaderfox-locations.json file could not be loaded.</div>';
1879                if (dealerMap) renderDealerMap([], null, '');
1880            }
1881        }
1882
1883        document.addEventListener('click', (event) => {
1884            const link = event.target.closest('[data-popup-id]');
1885            if (!link) return;
1886
1887            event.preventDefault();
1888            const itemId = link.getAttribute('data-popup-id');
1889            const itemIndex = filteredData.findIndex(item => item.id === itemId);
1890
1891            if (itemIndex >= 0) {
1892                const item = filteredData[itemIndex];
1893                filteredData = [item];
1894                currentPage = 1;
1895                $search.value = item.name || '';
1896                renderCurrentPage();
1897
1898                setTimeout(() => {
1899                    setActiveCard(itemId);
1900                    const card = document.querySelector(`.dealer-card[data-id="${CSS.escape(itemId)}"]`);
1901                    if (card) {
1902                        card.scrollIntoView({ behavior: 'smooth', block: 'center' });
1903                    }
1904                }, 80);
1905            }
1906        });
1907
1908                $search.addEventListener('input', () => {
1909            searchFilledFromMarker = false;
1910            applyFilters();
1911        });
1912        function applyFiltersAfterSelectChange() {
1913            if ($search.value) {
1914                $search.value = '';
1915            }
1916
1917            searchFilledFromMarker = false;
1918            updateCzechRegionFilterState();
1919            applyFilters();
1920        }
1921
1922        $type.addEventListener('change', applyFiltersAfterSelectChange);
1923        $scope.addEventListener('change', applyFiltersAfterSelectChange);
1924        $country.addEventListener('change', applyFiltersAfterSelectChange);
1925
1926        $prev.addEventListener('click', () => {
1927            if (currentPage > 1) {
1928                currentPage--;
1929                renderCurrentPage();
1930            }
1931        });
1932
1933        $next.addEventListener('click', () => {
1934            const totalPages = Math.max(1, Math.ceil(filteredData.length / PAGE_SIZE));
1935            if (currentPage < totalPages) {
1936                currentPage++;
1937                renderCurrentPage();
1938            }
1939        });
1940
1941        $reset.addEventListener('click', () => {
1942            $search.value = '';
1943            searchFilledFromMarker = false;
1944            $type.value = '';
1945            $scope.value = '';
1946            $country.value = '';
1947            updateCzechRegionFilterState();
1948            filteredData = sortDealerItems(dealerData);
1949            currentPage = 1;
1950            renderCurrentPage();
1951        });
1952
1953
1954        const GALLERY_SETS = {
1955            hero: {
1956                title: 'Hero',
1957                path: 'images/hero/',
1958                prefix: 'HERO',
1959                count: 9,
1960                extension: '.jpg'
1961            },
1962            alps: {
1963                title: 'Alps',
1964                path: 'images/alps/',
1965                prefix: 'ALPS',
1966                count: 149,
1967                extension: '.jpg'
1968            }
1969        };
1970
1971        let currentGallerySet = 'hero';
1972        let currentGalleryVisible = 9;
1973        let currentGalleryImages = [];
1974        let currentGalleryIndex = 0;
1975
1976        function galleryFileName(config, index) {
1977            return `${config.prefix}${String(index).padStart(3, '0')}${config.extension}`;
1978        }
1979
1980        function buildGalleryImages(setName) {
1981            const config = GALLERY_SETS[setName];
1982            return Array.from({ length: config.count }, (_, index) => {
1983                const number = index + 1;
1984                const fileName = galleryFileName(config, number);
1985                return {
1986                    set: setName,
1987                    title: `${config.title} ${String(number).padStart(3, '0')}`,
1988                    src: config.path + fileName
1989                };
1990            });
1991        }
1992
1993        function galleryThumbHtml(image, index) {
1994            return `
1995                <button type="button" class="gallery-thumb card-lift" data-gallery-index="${index}" aria-label="Open photo ${escapeHtml(image.title)}">
1996                    <img src="${escapeHtml(image.src)}" alt="${escapeHtml(image.title)}" loading="lazy" onerror="this.closest('.gallery-thumb').remove();">
1997                </button>
1998            `;
1999        }
2000
2001        function renderGallery() {
2002            const $galleryGrid = document.getElementById('gallery-grid');
2003            const $loadMore = document.getElementById('gallery-load-more');
2004
2005            if (!$galleryGrid || !$loadMore) return;
2006
2007            currentGalleryImages = buildGalleryImages(currentGallerySet);
2008            const visibleImages = currentGalleryImages.slice(0, currentGalleryVisible);
2009
2010            $galleryGrid.innerHTML = visibleImages.map(galleryThumbHtml).join('');
2011            $loadMore.classList.toggle('hidden', currentGalleryVisible >= currentGalleryImages.length);
2012
2013            document.querySelectorAll('.gallery-thumb').forEach(button => {
2014                button.addEventListener('click', () => {
2015                    openGalleryLightbox(Number(button.dataset.galleryIndex || 0));
2016                });
2017            });
2018        }
2019
2020        function setGallerySet(setName) {
2021            if (!GALLERY_SETS[setName]) return;
2022
2023            currentGallerySet = setName;
2024            currentGalleryVisible = setName === 'hero' ? 9 : 12;
2025
2026            document.querySelectorAll('.gallery-tab').forEach(tab => {
2027                const isActive = tab.dataset.gallerySet === setName;
2028                tab.classList.toggle('is-active', isActive);
2029            });
2030
2031            renderGallery();
2032        }
2033
2034        function openGalleryLightbox(index) {
2035            const $lightbox = document.getElementById('gallery-lightbox');
2036            const $image = document.getElementById('gallery-lightbox-image');
2037            const $caption = document.getElementById('gallery-lightbox-caption');
2038
2039            if (!$lightbox || !$image || !$caption || !currentGalleryImages.length) return;
2040
2041            currentGalleryIndex = Math.max(0, Math.min(index, currentGalleryImages.length - 1));
2042            const image = currentGalleryImages[currentGalleryIndex];
2043
2044            $image.src = image.src;
2045            $image.alt = image.title;
2046            $caption.textContent = `${image.title} / ${currentGalleryIndex + 1} z ${currentGalleryImages.length}`;
2047            $lightbox.classList.add('is-open');
2048            $lightbox.setAttribute('aria-hidden', 'false');
2049            document.body.style.overflow = 'hidden';
2050        }
2051
2052        function closeGalleryLightbox() {
2053            const $lightbox = document.getElementById('gallery-lightbox');
2054            const $image = document.getElementById('gallery-lightbox-image');
2055
2056            if (!$lightbox || !$image) return;
2057
2058            $lightbox.classList.remove('is-open');
2059            $lightbox.setAttribute('aria-hidden', 'true');
2060            $image.src = '';
2061            document.body.style.overflow = '';
2062        }
2063
2064        function moveGalleryLightbox(step) {
2065            if (!currentGalleryImages.length) return;
2066            const nextIndex = (currentGalleryIndex + step + currentGalleryImages.length) % currentGalleryImages.length;
2067            openGalleryLightbox(nextIndex);
2068        }
2069
2070        function initGallery() {
2071            const $loadMore = document.getElementById('gallery-load-more');
2072            const $close = document.getElementById('gallery-lightbox-close');
2073            const $prev = document.getElementById('gallery-lightbox-prev');
2074            const $next = document.getElementById('gallery-lightbox-next');
2075            const $lightbox = document.getElementById('gallery-lightbox');
2076
2077            if (!document.getElementById('gallery-grid')) return;
2078
2079            document.querySelectorAll('.gallery-tab').forEach(tab => {
2080                tab.addEventListener('click', () => setGallerySet(tab.dataset.gallerySet));
2081            });
2082
2083            if ($loadMore) {
2084                $loadMore.addEventListener('click', () => {
2085                    currentGalleryVisible += 12;
2086                    renderGallery();
2087                });
2088            }
2089
2090            if ($close) $close.addEventListener('click', closeGalleryLightbox);
2091            if ($prev) $prev.addEventListener('click', () => moveGalleryLightbox(-1));
2092            if ($next) $next.addEventListener('click', () => moveGalleryLightbox(1));
2093
2094            if ($lightbox) {
2095                $lightbox.addEventListener('click', (event) => {
2096                    if (event.target === $lightbox) closeGalleryLightbox();
2097                });
2098            }
2099
2100            document.addEventListener('keydown', (event) => {
2101                const $box = document.getElementById('gallery-lightbox');
2102                if (!$box || !$box.classList.contains('is-open')) return;
2103
2104                if (event.key === 'Escape') closeGalleryLightbox();
2105                if (event.key === 'ArrowLeft') moveGalleryLightbox(-1);
2106                if (event.key === 'ArrowRight') moveGalleryLightbox(1);
2107            });
2108
2109            setGallerySet('hero');
2110        }
2111
2112
2113        function blogCardHtml(post) {
2114            const title = escapeHtml(post.title || '');
2115            const text = escapeHtml(post.text || '');
2116            const url = escapeHtml(post.url || 'https://e-shop.leaderfox.com/aktualita/');
2117            const image = escapeHtml(post.image || '');
2118            const date = escapeHtml(post.date || '');
2119
2120            return `
2121                <article class="card-lift rounded-3xl border border-zinc-200 bg-white overflow-hidden text-left">
2122                    ${image ? `
2123                        <a href="${url}" target="_blank" rel="noopener" class="block bg-zinc-100">
2124                            <img src="${image}" alt="${title}" class="w-full h-52 object-cover">
2125                        </a>
2126                    ` : `
2127                        <a href="${url}" target="_blank" rel="noopener" class="block h-52 bg-zinc-900 relative overflow-hidden">
2128                            <div class="absolute inset-0 bg-gradient-to-br from-zinc-900 via-zinc-800 to-yellow-500/40"></div>
2129                            <div class="absolute left-6 bottom-6 text-white text-[11px] uppercase tracking-[0.28em] font-black">Leader Fox</div>
2130                        </a>
2131                    `}
2132                    <div class="p-6">
2133                        ${date ? `<div class="text-[11px] uppercase tracking-[0.22em] font-black text-yellow-500 mb-3">${date}</div>` : ''}
2134                        <h3 class="text-xl font-black tracking-tight text-zinc-900 mb-3 leading-tight">
2135                            <a href="${url}" target="_blank" rel="noopener" class="hover:text-yellow-600 transition">${title}</a>
2136                        </h3>
2137                        ${text ? `<p class="text-sm text-zinc-600 leading-relaxed mb-5">${text}</p>` : ''}
2138                        <a href="${url}" target="_blank" rel="noopener" class="inline-flex text-sm font-black uppercase tracking-[0.18em] text-zinc-900 hover:text-yellow-600 transition">
2139                            Read more →
2140                        </a>
2141                    </div>
2142                </article>
2143            `;
2144        }
2145
2146        async function initBlogPreview() {
2147            const $blogPreview = document.getElementById('blog-preview');
2148            const $blogFallback = document.getElementById('blog-fallback');
2149
2150            if (!$blogPreview) return;
2151
2152            try {
2153                const response = await fetch('blog-posts-en.json?v=' + Date.now());
2154
2155                if (!response.ok) {
2156                    throw new Error('The blog-posts-en.json file was not found.');
2157                }
2158
2159                const posts = await response.json();
2160                const visiblePosts = Array.isArray(posts)
2161                    ? posts.filter(post => post && post.title && post.url).slice(0, 3)
2162                    : [];
2163
2164                if (!visiblePosts.length) {
2165                    throw new Error('The blog-posts-en.json file does not contain any articles.');
2166                }
2167
2168                $blogPreview.innerHTML = visiblePosts.map(blogCardHtml).join('');
2169                if ($blogFallback) $blogFallback.classList.add('hidden');
2170            } catch (e) {
2171                $blogPreview.innerHTML = '';
2172                if ($blogFallback) $blogFallback.classList.remove('hidden');
2173            }
2174        }
2175
2176        initGallery();
2177        initBlogPreview();
2178
2179
2180                initDealers();
2181    </script>
2181
2182</body>
2183</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.