PageSourceSearch

https://iptvbridge.vercel.app/

html iptvbridge.vercel.app collected 2026-10-03 07:07:57 UTC 34,592 bytes, 467 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  <title>IPTV Bridge — Cinema for your Stremio & Nuvio</title>
7  <meta name="description" content="Connect Xtream Codes or M3U IPTV to Stremio & Nuvio with TMDB matching, global search and clean categories. Serverless, free, Vercel-ready." />
8  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
9  
9<script src="https://cdn.tailwindcss.com"></script>
9
10  <link rel="preconnect" href="https://fonts.googleapis.com" />
11  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
12  <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
13  
13<script src="https://unpkg.com/lucide@latest"></script>
13
14  
14<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
14
15  
15<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ScrollTrigger.min.js"></script>
15
16  
16<script>
17    tailwind.config = { theme: { extend: { fontFamily: {
18      serif: ['"Instrument Serif"','serif'], sans: ['"Space Grotesk"','sans-serif'], mono: ['"JetBrains Mono"','monospace'] } } } };
19  </script>
19
20  <link rel="stylesheet" href="/theme.css" />
21</head>
22<body class="antialiased">
23  <div class="grain"></div>
24  <div class="vignette"></div>
25  <div id="cursor"></div>
26
27  <!-- NAV -->
28  <nav id="nav" class="fixed top-0 inset-x-0 z-50 px-5 sm:px-10 py-4 flex items-center justify-between transition-all duration-300">
29    <a href="/" class="flex items-center gap-2.5" data-cursor>
30      <img src="/logo.svg" class="w-7 h-7 rounded-lg" alt="IPTV Bridge" />
31      <span class="font-sans font-semibold tracking-tight">IPTV Bridge</span>
32    </a>
33    <div class="hidden md:flex items-center gap-8 text-sm text-[var(--paper)]/70 font-sans">
34      <a href="#how" class="ul" data-cursor>Method</a>
35      <a href="#features" class="ul" data-cursor>Features</a>
36      <a href="#stack" class="ul" data-cursor>Stack</a>
37      <a href="/docs" class="ul" data-cursor>Docs</a>
38      <a href="#faq" class="ul" data-cursor>FAQ</a>
39    </div>
40    <a href="/configure" class="text-sm font-semibold ember px-4 py-2 rounded-full font-sans inline-flex items-center gap-1.5 leading-none" data-cursor><span>Configure</span> <i data-lucide="arrow-right" class="w-3.5 h-3.5"></i></a>
41  </nav>
42
43  <!-- HERO -->
44  <header class="relative z-10 min-h-screen flex flex-col justify-center px-5 sm:px-10 pt-24 pb-16 overflow-hidden">
45    <div class="max-w-[1400px] mx-auto w-full relative z-10">
46      <div class="flex items-center gap-3 mb-8 flex-wrap">
47        <span data-hero-tag class="text-xs font-sans tracking-[0.25em] uppercase text-[var(--muted)]">Serverless</span>
48        <span class="w-8 h-px bg-[var(--line)]"></span>
49        <span data-hero-tag class="text-xs font-sans tracking-[0.25em] uppercase text-[var(--muted)]">Stremio · Nuvio</span>
50        <span class="w-8 h-px bg-[var(--line)]"></span>
51        <span data-hero-tag class="text-xs font-sans tracking-[0.25em] uppercase text-[var(--muted)]">Free on Vercel</span>
52      </div>
53
54      <h1 class="display text-[16vw] sm:text-[12vw] lg:text-[10.5vw]">
55        <span class="line-mask"><span data-hero-line>Turn your IPTV</span></span>
56        <span class="line-mask"><span data-hero-line>into a <span class="italic-accent">cinema.</span></span></span>
57      </h1>
58
59      <div class="mt-10 grid md:grid-cols-[1.4fr_1fr] gap-8 items-end">
60        <p data-hero-sub class="text-lg sm:text-xl text-[var(--paper)]/70 max-w-xl leading-relaxed font-sans">
61          Xtream Codes or an M3U link becomes organized catalogs, global search, and automatic TMDB matching — every film and show resolves straight to your own sources.
62        </p>
63        <div data-hero-cta class="flex flex-col sm:flex-row md:justify-end gap-3">
64          <a href="/configure" class="ember px-7 py-4 rounded-full font-sans font-semibold text-sm inline-flex items-center justify-center gap-2 leading-none" data-magnetic data-cursor-big>
65            <span>Configure</span> <i data-lucide="arrow-up-right" class="w-4 h-4"></i>
66          </a>
67          <a href="#how" class="glass-btn px-7 py-4 rounded-full font-sans font-semibold text-sm inline-flex items-center justify-center gap-2 leading-none" data-cursor>
68            <span>The method</span>
69          </a>
70        </div>
71      </div>
72    </div>
73
74    <div data-hero-scroll class="absolute bottom-8 left-1/2 -translate-x-1/2 flex flex-col items-center gap-2 text-[var(--muted)]">
75      <span class="text-[10px] font-sans tracking-[0.3em] uppercase">Scroll</span>
76      <span class="w-px h-10 bg-gradient-to-b from-[var(--accent)] to-transparent"></span>
77    </div>
78  </header>
79
80  <!-- MARQUEE -->
81  <section class="relative z-10 border-y border-[var(--line)] py-6 overflow-hidden">
82    <div id="marquee-track" class="marquee items-center gap-12"></div>
83  </section>
84
85  <!-- STATS -->
86  <section class="relative z-10 px-5 sm:px-10 py-20 border-b border-[var(--line)]">
87    <div class="max-w-[1400px] mx-auto">
88      <div class="grid grid-cols-2 lg:grid-cols-4 rounded-3xl overflow-hidden border border-[var(--line)] divide-x divide-y lg:divide-y-0 divide-[var(--line)]">
89        <div class="stat group relative p-7 sm:p-9" data-reveal data-cursor>
90          <div class="flex items-center gap-2 mb-5 text-[var(--muted)]">
91            <i data-lucide="plug-zap" class="w-4 h-4"></i>
92            <span class="text-[11px] font-sans uppercase tracking-[0.2em]">Inputs</span>
93          </div>
94          <p class="display text-6xl sm:text-7xl text-[var(--accent)] leading-none">2</p>
95          <p class="text-sm text-[var(--paper)]/70 font-sans mt-3 font-medium">Provider formats</p>
96          <p class="text-xs text-[var(--muted)] font-sans mt-1">Xtream Codes &amp; M3U / M3U8</p>
97        </div>
98        <div class="stat group relative p-7 sm:p-9" data-reveal data-cursor>
99          <div class="flex items-center gap-2 mb-5 text-[var(--muted)]">
100            <i data-lucide="layout-grid" class="w-4 h-4"></i>
101            <span class="text-[11px] font-sans uppercase tracking-[0.2em]">Catalogs</span>
102          </div>
103          <p class="display text-6xl sm:text-7xl leading-none group-hover:text-[var(--accent)] transition-colors">3</p>
104          <p class="text-sm text-[var(--paper)]/70 font-sans mt-3 font-medium">Content types</p>
105          <p class="text-xs text-[var(--muted)] font-sans mt-1">Live TV · Movies · Series</p>
106        </div>
107        <div class="stat group relative p-7 sm:p-9" data-reveal data-cursor>
108          <div class="flex items-center gap-2 mb-5 text-[var(--muted)]">
109            <i data-lucide="database" class="w-4 h-4"></i>
110            <span class="text-[11px] font-sans uppercase tracking-[0.2em]">Infra</span>
111          </div>
112          <p class="display text-6xl sm:text-7xl leading-none group-hover:text-[var(--accent)] transition-colors">0</p>
113          <p class="text-sm text-[var(--paper)]/70 font-sans mt-3 font-medium">Databases or servers</p>
114          <p class="text-xs text-[var(--muted)] font-sans mt-1">Fully stateless &amp; serverless</p>
115        </div>
116        <div class="stat group relative p-7 sm:p-9" data-reveal data-cursor>
117          <div class="flex items-center gap-2 mb-5 text-[var(--muted)]">
118            <i data-lucide="wallet" class="w-4 h-4"></i>
119            <span class="text-[11px] font-sans uppercase tracking-[0.2em]">Cost</span>
120          </div>
121          <p class="display text-6xl sm:text-7xl leading-none group-hover:text-[var(--accent)] transition-colors">$0</p>
122          <p class="text-sm text-[var(--paper)]/70 font-sans mt-3 font-medium">Hosting on Vercel</p>
123          <p class="text-xs text-[var(--muted)] font-sans mt-1">Runs on the free tier</p>
124        </div>
125      </div>
126    </div>
127  </section>
128
129  <!-- PROVIDER FORMATS -->
130  <section class="relative z-10 px-5 sm:px-10 py-24 border-b border-[var(--line)]">
131    <div class="max-w-[1400px] mx-auto">
132      <div class="flex items-end justify-between mb-12 flex-wrap gap-4">
133        <div>
134          <p class="text-xs font-sans tracking-[0.25em] uppercase text-[var(--muted)] mb-3" data-reveal>Two ways in</p>
135          <h2 class="display text-5xl sm:text-7xl" data-reveal>Bring your own source</h2>
136        </div>
137        <a href="/configure" class="ghost px-5 py-3 rounded-full font-sans text-sm flex items-center gap-2" data-cursor data-reveal>
138          Connect now <i data-lucide="arrow-up-right" class="w-4 h-4"></i>
139        </a>
140      </div>
141
142      <div class="grid md:grid-cols-2 gap-4">
143        <div class="format-card group relative border border-[var(--line)] rounded-3xl p-7 sm:p-9 overflow-hidden" data-reveal data-cursor>
144          <div class="flex items-center justify-between mb-6">
145            <div class="w-12 h-12 rounded-2xl bg-[rgba(255,94,43,0.1)] border border-[rgba(255,94,43,0.25)] grid place-items-center">
146              <i data-lucide="key-round" class="w-5 h-5 text-[var(--accent)]"></i>
147            </div>
148            <span class="text-[11px] font-sans uppercase tracking-[0.2em] text-[var(--muted)] px-3 py-1 rounded-full border border-[var(--line)]">Recommended</span>
149          </div>
150          <h3 class="text-2xl font-sans font-semibold mb-2">Xtream Codes API</h3>
151          <p class="text-sm text-[var(--paper)]/60 font-sans leading-relaxed mb-6">Host, username and password. We pull live, VOD and series categories directly — the cleanest, richest experience.</p>
152          <ul class="space-y-2.5 text-sm font-sans">
153            <li class="flex items-center gap-2.5 text-[var(--paper)]/75"><i data-lucide="check" class="w-4 h-4 text-[var(--accent)]"></i>
153 Native category structure</li>
154            <li class="flex items-center gap-2.5 text-[var(--paper)]/75"><i data-lucide="check" class="w-4 h-4 text-[var(--accent)]"></i> Per-episode series resolution</li>
155            <li class="flex items-center gap-2.5 text-[var(--paper)]/75"><i data-lucide="check" class="w-4 h-4 text-[var(--accent)]"></i> Account status &amp; expiry check</li>
156          </ul>
157        </div>
158
159        <div class="format-card group relative border border-[var(--line)] rounded-3xl p-7 sm:p-9 overflow-hidden" data-reveal data-cursor>
160          <div class="flex items-center justify-between mb-6">
161            <div class="w-12 h-12 rounded-2xl bg-[rgba(244,240,232,0.05)] border border-[var(--line)] grid place-items-center">
162              <i data-lucide="link-2" class="w-5 h-5 text-[var(--paper)]/80"></i>
163            </div>
164            <span class="text-[11px] font-sans uppercase tracking-[0.2em] text-[var(--muted)] px-3 py-1 rounded-full border border-[var(--line)]">Universal</span>
165          </div>
166          <h3 class="text-2xl font-sans font-semibold mb-2">M3U / M3U8 Playlist</h3>
167          <p class="text-sm text-[var(--paper)]/60 font-sans leading-relaxed mb-6">Any single playlist URL. We parse group titles, logos and TVG metadata, then organize everything automatically.</p>
168          <ul class="space-y-2.5 text-sm font-sans">
169            <li class="flex items-center gap-2.5 text-[var(--paper)]/75"><i data-lucide="check" class="w-4 h-4 text-[var(--accent)]"></i> Works with any provider</li>
170            <li class="flex items-center gap-2.5 text-[var(--paper)]/75"><i data-lucide="check" class="w-4 h-4 text-[var(--accent)]"></i> Auto group &amp; type detection</li>
171            <li class="flex items-center gap-2.5 text-[var(--paper)]/75"><i data-lucide="check" class="w-4 h-4 text-[var(--accent)]"></i> Logo &amp; metadata extraction</li>
172          </ul>
173        </div>
174      </div>
175    </div>
176  </section>
177
178  <!-- HOW / METHOD -->
179  <section id="how" class="relative z-10 px-5 sm:px-10 py-28 sm:py-40">
180    <div class="max-w-[1400px] mx-auto">
181      <div class="flex items-baseline justify-between mb-14 flex-wrap gap-4">
182        <div>
183          <p class="text-xs font-sans tracking-[0.25em] uppercase text-[var(--muted)] mb-3" data-reveal>How it works</p>
184          <h2 class="display text-6xl sm:text-8xl" data-reveal>The method</h2>
185        </div>
186        <span class="text-sm font-sans text-[var(--muted)] max-w-xs" data-reveal>Three moving parts, one clean result inside your player.</span>
187      </div>
188      <div id="method-grid" class="grid md:grid-cols-3 gap-4">
189        <div class="method-card group relative border border-[var(--line)] rounded-3xl p-8 sm:p-9 overflow-hidden">
190          <div class="flex items-center justify-between mb-8">
191            <span class="method-num display text-6xl text-[var(--paper)]/15 group-hover:text-[var(--accent)] transition-colors duration-500">01</span>
192            <i data-lucide="plug-zap" class="w-5 h-5 text-[var(--accent)]"></i>
193          </div>
194          <h3 class="text-2xl mb-3 font-sans font-semibold">Connect</h3>
195          <p class="text-[var(--paper)]/60 leading-relaxed font-sans text-sm">Drop in Xtream credentials or an M3U URL. We parse channels, movies and series in one pass and cache them warm.</p>
196        </div>
197        <div class="method-card group relative border border-[var(--line)] rounded-3xl p-8 sm:p-9 overflow-hidden">
198          <div class="flex items-center justify-between mb-8">
199            <span class="method-num display text-6xl text-[var(--paper)]/15 group-hover:text-[var(--accent)] transition-colors duration-500">02</span>
200            <i data-lucide="clapperboard" class="w-5 h-5 text-[var(--accent)]"></i>
201          </div>
202          <h3 class="text-2xl mb-3 font-sans font-semibold">Resolve</h3>
203          <p class="text-[var(--paper)]/60 leading-relaxed font-sans text-sm">Titles are cleaned of release tags and matched to TMDB — posters, years, ratings and IMDB/TMDB IDs all line up.</p>
204        </div>
205        <div class="method-card group relative border border-[var(--line)] rounded-3xl p-8 sm:p-9 overflow-hidden">
206          <div class="flex items-center justify-between mb-8">
207            <span class="method-num display text-6xl text-[var(--paper)]/15 group-hover:text-[var(--accent)] transition-colors duration-500">03</span>
208            <i data-lucide="play" class="w-5 h-5 text-[var(--accent)]"></i>
209          </div>
210          <h3 class="text-2xl mb-3 font-sans font-semibold">Stream</h3>
211          <p class="text-[var(--paper)]/60 leading-relaxed font-sans text-sm">Search anything in Stremio or Nuvio and your own IPTV source appears as a playable stream. One tap, it plays.</p>
212        </div>
213      </div>
214    </div>
215  </section>
216
217  <!-- FEATURES -->
218  <section id="features" class="relative z-10 px-5 sm:px-10 py-20 border-t border-[var(--line)]">
219    <div class="max-w-[1400px] mx-auto">
220      <p class="text-sm font-sans tracking-[0.25em] uppercase text-[var(--muted)] mb-10" data-reveal>What you get</p>
221      <ul id="feature-list" class="divide-y divide-[var(--line)] overflow-hidden">
222        <li class="feature-row py-7 flex items-center justify-between gap-6 group" data-side="left" data-cursor><span class="display text-4xl sm:text-6xl transition-transform duration-500 group-hover:translate-x-3">Clean categories</span><span class="text-[var(--muted)] text-sm font-sans max-w-xs text-right hidden sm:block">Live, Movies & Series sorted into tidy catalogs.</span></li>
223        <li class="feature-row py-7 flex items-center justify-between gap-6 group" data-side="right" data-cursor><span class="display text-4xl sm:text-6xl transition-transform duration-500 group-hover:translate-x-3">Global search</span><span class="text-[var(--muted)] text-sm font-sans max-w-xs text-right hidden sm:block">Find any title, stream from your provider.</span></li>
224        <li class="feature-row py-7 flex items-center justify-between gap-6 group" data-side="left" data-cursor><span class="display text-4xl sm:text-6xl transition-transform duration-500 group-hover:translate-x-3">TMDB matching</span><span class="text-[var(--muted)] text-sm font-sans max-w-xs text-right hidden sm:block">Posters, ratings, IMDB & TMDB resolution.</span></li>
225        <li class="feature-row py-7 flex items-center justify-between gap-6 group" data-side="right" data-cursor><span class="display text-4xl sm:text-6xl transition-transform duration-500 group-hover:translate-x-3">Zero servers</span><span class="text-[var(--muted)] text-sm font-sans max-w-xs text-right hidden sm:block">Credentials live in your link. Nothing stored.</span></li>
226      </ul>
227    </div>
228  </section>
229
230  <!-- ARCHITECTURE / STACK -->
231  <section id="stack" class="relative z-10 px-5 sm:px-10 py-20 border-t border-[var(--line)]">
232    <div class="max-w-[1400px] mx-auto">
233      <div class="flex items-center justify-between mb-12 flex-wrap gap-4">
234        <div>
235          <p class="text-xs font-sans tracking-[0.25em] uppercase text-[var(--muted)] mb-3" data-reveal>Architecture</p>
236          <h2 class="display text-5xl sm:text-7xl" data-reveal>Under the hood</h2>
237        </div>
238        <a href="https://github.com/jozphe/IPTV-BRIDGE" target="_blank" rel="noreferrer" class="source-link" data-cursor data-reveal>
239          <span class="source-link-icon" aria-hidden="true">
240            <svg viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
241              <path d="M12 2C6.477 2 2 6.588 2 12.253c0 4.532 2.865 8.376 6.839 9.733.5.095.682-.222.682-.493 0-.244-.009-.889-.014-1.744-2.782.619-3.369-1.374-3.369-1.374-.455-1.184-1.11-1.499-1.11-1.499-.908-.637.069-.624.069-.624 1.003.073 1.531 1.056 1.531 1.056.892 1.567 2.341 1.114 2.91.852.091-.663.349-1.114.635-1.37-2.221-.259-4.556-1.139-4.556-5.067 0-1.119.39-2.034 1.029-2.751-.103-.259-.446-1.302.098-2.712 0 0 .84-.276 2.75 1.051A9.37 9.37 0 0 1 12 6.99
2411a9.36 9.36 0 0 1 2.504.346c1.909-1.327 2.748-1.051 2.748-1.051.546 1.41.202 2.453.1 2.712.64.717 1.028 1.632 1.028 2.751 0 3.938-2.339 4.805-4.567 5.058.359.317.679.944.679 1.903 0 1.373-.012 2.481-.012 2.819 0 .274.18.593.688.492C19.138 20.626 22 16.784 22 12.253 22 6.588 17.523 2 12 2Z"/>
242            </svg>
243          </span>
244          <span class="source-link-label">View source</span>
245          <i data-lucide="arrow-up-right" class="source-link-arrow"></i>
246        </a>
247      </div>
248
249      <!-- Horizontal signal flow with a travelling ember pulse -->
250      <div id="flow" class="relative mb-4 overflow-x-auto" data-reveal>
251        <div class="relative min-w-[720px] py-6">
252          <span class="flow-line absolute left-[8%] right-[8%] top-1/2 h-px bg-[var(--line)]"></span>
253          <span class="flow-pulse absolute top-1/2 w-24 h-px"></span>
254          <div class="relative grid grid-cols-5">
255            <div class="flow-node group flex flex-col items-center text-center px-2">
256              <span class="fdot w-14 h-14 rounded-2xl border border-[var(--line)] bg-[var(--ink)] grid place-items-center mb-3 transition-all duration-300 group-hover:border-[var(--accent)]"><i data-lucide="key-round" class="w-5 h-5 text-[var(--accent)]"></i></span>
257              <span class="text-[10px] font-mono text-[var(--muted)] mb-1">01</span>
258              <p class="font-sans font-semibold text-sm">Source</p>
259              <p class="text-[11px] text-[var(--muted)] font-sans">Xtream / M3U</p>
260            </div>
261            <div class="flow-node group flex flex-col items-center text-center px-2">
262              <span class="fdot w-14 h-14 rounded-2xl border border-[var(--line)] bg-[var(--ink)] grid place-items-center mb-3 transition-all duration-300 group-hover:border-[var(--accent)]"><i data-lucide="filter" class="w-5 h-5 text-[var(--accent)]"></i></span>
263              <span class="text-[10px] font-mono text-[var(--muted)] mb-1">02</span>
264              <p class="font-sans font-semibold text-sm">Parse &amp; cache</p>
265              <p class="text-[11px] text-[var(--muted)] font-sans">Clean · warm TTL</p>
266            </div>
267            <div class="flow-node group flex flex-col items-center text-center px-2">
268              <span class="fdot w-14 h-14 rounded-2xl border border-[var(--line)] bg-[var(--ink)] grid place-items-center mb-3 transition-all duration-300 group-hover:border-[var(--accent)]"><i data-lucide="clapperboard" class="w-5 h-5 text-[var(--accent)]"></i></span>
269              <span class="text-[10px] font-mono text-[var(--muted)] mb-1">03</span>
270              <p class="font-sans font-semibold text-sm">Resolve</p>
271              <p class="text-[11px] text-[var(--muted)] font-sans">IMDB / TMDB</p>
272            </div>
273            <div class="flow-node group flex flex-col items-center text-center px-2">
274              <span class="fdot w-14 h-14 rounded-2xl border border-[var(--line)] bg-[var(--ink)] grid place-items-center mb-3 transition-all duration-300 group-hover:border-[var(--accent)]"><i data-lucide="git-compare" class="w-5 h-5 text-[var(--accent)]"></i></span>
275              <span class="text-[10px] font-mono text-[var(--muted)] mb-1">04</span>
276              <p class="font-sans font-semibold text-sm">Match</p>
277              <p class="text-[11px] text-[var(--muted)] font-sans">Strict scoring</p>
278            </div>
279            <div class="flow-node group flex flex-col items-center text-center px-2">
280              <span class="fdot fdot-end w-14 h-14 rounded-2xl border border-[var(--accent)] bg-[rgba(255,94,43,0.1)] grid place-items-center mb-3 transition-all duration-300"><i data-lucide="play" class="w-5 h-5 text-[var(--accent)]"></i></span>
281              <span class="text-[10px] font-mono text-[var(--accent)] mb-1">05</span>
282              <p class="font-sans font-semibold text-sm">Play</p>
283              <p class="text-[11px] text-[var(--muted)] font-sans">Stremio / Nuvio</p>
284            </div>
285          </div>
286        </div>
287      </div>
288
289      <!-- Bento grid of capabilities -->
290      <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3">
291        <!-- Feature hero -->
292        <div class="bento group relative col-span-1 sm:col-span-2 lg:row-span-2 rounded-3xl border border-[var(--line)] p-7 overflow-hidden flex flex-col justify-between min-h-[220px]" data-reveal data-cursor>
293          <div class="flex items-start justify-between">
294            <span class="display text-6xl text-[var(--paper)]/12 group-hover:text-[var(--accent)] transition-colors duration-500">01</span>
295            <i data-lucide="server-cog" class="w-6 h-6 text-[var(--accent)]"></i>
296          </div>
297          <div>
298            <h3 class="display text-3xl mb-2">Serverless by nature</h3>
299            <p class="text-sm text-[var(--paper)]/60 font-sans leading-relaxed max-w-md">Node + TypeScript compiled to a single Vercel function. No always-on server, no database, no ops — it scales to zero and costs nothing at rest.</p>
300          </div>
301        </div>
302
303        <div class="bento group relative rounded-3xl border border-[var(--line)] p-6 overflow-hidden" data-reveal data-cursor>
304          <i data-lucide="database-zap" class="w-5 h-5 text-[var(--accent)] mb-4"></i>
305          <h4 class="font-sans font-semibold text-sm mb-1">Fully stateless</h4>
306          <p class="text-xs text-[var(--paper)]/55 font-sans leading-relaxed">Config rides inside the manifest URL. Nothing stored.</p>
307        </div>
308
309        <div class="bento group relative rounded-3xl border border-[var(--line)] p-6 overflow-hidden" data-reveal data-cursor>
310          <i data-lucide="scan-search" class="w-5 h-5 text-[var(--accent)] mb-4"></i>
311          <h4 class="font-sans font-semibold text-sm mb-1">Precise matching</h4>
312          <p class="text-xs text-[var(--paper)]/55 font-sans leading-relaxed">Strict scoring returns only the exact title.</p>
313        </div>
314
315        <div class="bento group relative rounded-3xl border border-[var(--line)] p-6 overflow-hidden" data-reveal data-cursor>
316          <i data-lucide="shield-check" class="w-5 h-5 text-[var(--accent)] mb-4"></i>
317          <h4 class="font-sans font-semibold text-sm mb-1">Private by design</h4>
318          <p class="text-xs text-[var(--paper)]/55 font-sans leading-relaxed">Credentials never touch a datastore.</p>
319        </div>
320
321        <div class="bento group relative rounded-3xl border border-[var(--line)] p-6 overflow-hidden" data-reveal data-cursor>
322          <i data-lucide="plug" class="w-5 h-5 text-[var(--accent)] mb-4"></i>
323          <h4 class="font-sans font-semibold text-sm mb-1">Protocol-native</h4>
324          <p class="text-xs text-[var(--paper)]/55 font-sans leading-relaxed">Stremio v3: catalog, meta &amp; stream.</p>
325        </div>
326
327        <!-- Tech tag strip -->
328        <div class="bento-tags col-span-1 sm:col-span-2 lg:col-span-4 rounded-3xl border border-[var(--line)] p-5 flex flex-wrap items-center gap-2.5" data-reveal>
329          <span class="text-[11px] font-mono uppercase tracking-[0.15em] text-[var(--muted)] mr-2">Built with</span>
330          <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">TypeScript</span>
331          <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">Node · Express</span>
332          <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">Vercel</span>
333          <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">TMDB API</span>
334          <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">Xtream Codes</span>
335          <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">M3U / M3U8</span>
336          <span class="text-[11px] font-mono px-3 py-1.5 rounded-full border border-[var(--line)] text-[var(--paper)]/70">LZ-String</span>
337        </div>
338      </div>
339    </div>
340  </section>
341
342  <!-- FAQ -->
343  <section id="faq" class="relative z-10 px-5 sm:px-10 py-28 border-t border-[var(--line)]">
344    <div class="max-w-[900px] mx-auto">
345      <h2 class="display text-6xl sm:text-8xl mb-14" data-reveal>Questions</h2>
346      <div class="divide-y divide-[var(--line)]">
347        <details class="py-6 group" data-reveal><summary class="flex items-center justify-between cursor-pointer list-none font-sans font-semibold text-lg" data-cursor>Do I need a TMDB key?<i data-lucide="plus" class="w-5 h-5 text-[var(--accent)] group-open:rotate-45 transition-transform"></i></summary><p class="text-sm text-[var(--paper)]/60 font-sans mt-3 leading-relaxed">It's optional but recommended. A free TMDB v3 key powers poster art, ratings and the IMDB/TMDB resolution that lets global search map any title to your IPTV sources.</p></details>
348        <details class="py-6 group" data-reveal><summary class="flex items-center justify-between cursor-pointer list-none font-sans font-semibold text-lg" data-cursor>Where are my credentials stored?<i data-lucide="plus" class="w-5 h-5 text-[var(--accent)] group-open:rotate-45 transition-transform"></i></summary><p class="text-sm text-[var(--paper)]/60 font-sans mt-3 leading-relaxed">Nowhere on a server. They're LZ-compressed into the manifest URL you generate, so the addon is fully stateless and portable.</p></details>
349        <details class="py-6 group" data-reveal><summary class="flex items-center justify-between cursor-pointer list-none font-sans font-semibold text-lg" data-cursor>Does it work in Nuvio as well as Stremio?<i data-lucide="plus" class="w-5 h-5 text-[var(--accent)] group-open:rotate-45 transition-transform"></i></summary><p class="text-sm text-[var(--paper)]/60 font-sans mt-3 leading-relaxed">Yes. Both speak the Stremio v3 addon protocol. Use the one-click Stremio install, or paste the manifest URL into Nuvio's add-addon field.</p></details>
350        <details class="py-6 group" data-reveal><summary class="flex items-center justify-between cursor-pointer list-none font-sans font-semibold text-lg" data-cursor>Is hosting really free?<i data-lucide="plus" class="w-5 h-5 text-[var(--accent)] group-open:rotate-45 transition-transform"></i></summary><p class="text-sm text-[var(--paper)]/60 font-sans mt-3 leading-relaxed">The whole thing runs as one serverless function that fits comfortably in Vercel's free tier. No database, no always-on server.</p></details>
351      </div>
352    </div>
353  </section>
354
355  <!-- CTA / FOOTER -->
356  <footer class="relative z-10 px-5 sm:px-10 pt-24 pb-10 border-t border-[var(--line)]">
357    <div class="max-w-[1400px] mx-auto">
358      <a href="/configure" class="block group" data-cursor>
359        <h2 class="display text-[13vw] leading-[0.9] mb-4 group-hover:text-[var(--accent)] transition-colors">Press play.</h2>
360      </a>
361
362      <!-- Columns -->
363      <div class="grid grid-cols-2 md:grid-cols-4 gap-8 py-14 border-t border-[var(--line)] mt-10">
364        <div class="col-span-2 md:col-span-1">
365          <div class="flex items-center gap-2.5 mb-4">
366            <img src="/logo.svg" class="w-8 h-8 rounded-lg" alt="" />
367            <span class="font-sans font-semibold">IPTV Bridge</span>
368          </div>
369          <p class="text-sm text-[var(--muted)] font-sans leading-relaxed max-w-xs">Turn any Xtream or M3U source into a beautifully organized Stremio & Nuvio experience.</p>
370        </div>
371        <div>
372          <p class="text-xs uppercase tracking-[0.2em] text-[var(--muted)] font-sans mb-4">Product</p>
373          <ul class="space-y-2.5 text-sm font-sans text-[var(--paper)]/70">
374            <li><a href="#how" class="ul" data-cursor>Method</a></li>
375            <li><a href="#features" class="ul" data-cursor>Features</a></li>
376            <li><a href="#stack" class="ul" data-cursor>Architecture</a></li>
377            <li><a href="/configure" class="ul" data-cursor>Configure your addon</a></li>
378          </ul>
379        </div>
380        <div>
381          <p class="text-xs uppercase tracking-[0.2em] text-[var(--muted)] font-sans mb-4">Resources</p>
382          <ul class="space-y-2.5 text-sm font-sans text-[var(--paper)]/70">
383            <li><a href="/docs" class="ul" data-cursor>Documentation</a></li>
384            <li><a href="#faq" class="ul" data-cursor>FAQ</a></li>
385            <li><a href="https://www.themoviedb.org/settings/api" target="_blank" class="ul" data-cursor>Get a TMDB key</a></li>
386            <li><a href="https://www.stremio.com" target="_blank" class="ul" data-cursor>Stremio</a></li>
387            <li><a href="https://github.com/jozphe/IPTV-BRIDGE" target="_blank" class="ul" data-cursor>Source on GitHub</a></li>
388          </ul>
389        </div>
390        <div>
391          <p class="text-xs uppercase tracking-[0.2em] text-[var(--muted)] font-sans mb-3">Ready when you are</p>
392          <a href="/configure" class="ember inline-flex items-center justify-center gap-2 px-6 py-3.5 rounded-full font-sans font-semibold text-sm leading-none w-full sm:w-auto" data-magnetic data-cursor-big>
393            <span>Configure now</span> <i data-lucide="arrow-up-right" class="w-4 h-4"></i>
394          </a>
395          <p class="text-xs text-[var(--muted)] font-sans mt-3 flex items-center gap-1.5"><i data-lucide="check" class="w-3.5 h-3.5 text-[var(--accent)]"></i> Free · Serverless · Vercel-ready</p>
396        </div>
397      </div>
398
399      <div class="flex flex-wrap items-center justify-between gap-4 pt-8 border-t border-[var(--line)] text-xs text-[var(--muted)] font-sans">
400        <span>© <span id="year"></span> IPTV Bridge · Built for the Stremio & Nuvio v3 addon protocol.</span>
401        <span>Made for people who just want their stuff to play.</span>
402      </div>
403    </div>
404  </footer>
405
406  
406<script src="/theme.js"></script>
406
407  
407<script>
408    /* Marquee */
409    (function(){
410      const words=['Xtream Codes','M3U','TMDB','IMDB','Live TV','Movies','Series','Global Search','Serverless','Nuvio','Stremio','Vercel'];
411      const seq=words.concat(words);
412      document.getElementById('marquee-track').innerHTML=seq.map(w=>'<span class="flex items-center gap-12"><span class="display text-4xl text-[var(--paper)]/80">'+w+'</span><span class="w-2 h-2 rounded-full bg-[var(--accent)]"></span></span>').join('');
413    })();
414
415    /* Reveal + intro animations */
416    document.addEventListener('DOMContentLoaded', function () {
417      lucide.createIcons();
418      var y = document.getElementById('year'); if (y) y.textContent = new Date().getFullYear();
419
420      var hasIO = 'IntersectionObserver' in window;
421
422      // Generic reveals: one-shot CSS transition, no flash, no re-trigger.
423      var revealEls = document.querySelectorAll('[data-reveal]');
424      if (hasIO) {
425        var io = new IntersectionObserver(function (entries) {
426          entries.forEach(function (entry) {
427            if (entry.isIntersecting) { entry.target.classList.add('shown'); io.unobserve(entry.target); }
428          });
429        }, { rootMargin: '0px 0px -8% 0px', threshold: 0.12 });
430        revealEls.forEach(function (el) { io.observe(el); });
431      } else {
432        revealEls.forEach(function (el) { el.classList.add('shown'); });
433      }
434
435      // Staggered class-toggle groups (method cards, feature rows). Runs once.
436      function batchReveal(selector, triggerSelector, stagger) {
437        var els = Array.prototype.slice.call(document.querySelectorAll(selector));
438        if (!els.length) return;
439        var play = function () { els.forEach(function (el, i) { setTimeout(function () { el.classList.add('in'); }, i * stagger); }); };
440        if (!hasIO) { play(); return; }
441        var trigger = document.querySelector(triggerSelector) || els[0];
442        var obs = new IntersectionObserver(function (entries) {
443          for (var i = 0; i < entries.length; i++) {
444            if (entries[i].isIntersecting) { play(); obs.disconnect(); break; }
445          }
446        }, { rootMargin: '0px 0px -12% 0px', threshold: 0.1 });
447        obs.observe(trigger);
448      }
449      batchReveal('.method-card', '#method-grid', 110);
450      batchReveal('.feature-row', '#feature-list', 100);
451
452      // Hero intro timeline only (runs once on load).
453      if (!window.gsap) return;
454      gsap.registerPlugin(ScrollTrigger);
455      ScrollTrigger.config({ limitCallbacks: true, ignoreMobileResize: true });
456      var tl = gsap.timeline({ defaults: { ease: 'power4.out' } });
457      gsap.set('[data-hero-line]', { yPercent: 110 });
458      tl.to('[data-hero-line]', { yPercent: 0, duration: 1.1, stagger: 0.12 }, 0.15)
459        .from('[data-hero-tag]', { opacity: 0, y: 12, stagger: 0.08, duration: 0.6 }, 0.2)
460        .from('[data-hero-sub]', { opacity: 0, y: 20, duration: 0.8 }, 0.6)
461        .from('[data-hero-cta]', { opacity: 0, y: 20, duration: 0.8 }, 0.72)
462        .from('[data-hero-scroll]', { opacity: 0, duration: 0.8 }, 0.9);
463    });
464
465  </script>
465
466</body>
467</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.