mison2264 commited on
Commit
a77f7db
Β·
verified Β·
1 Parent(s): 0f35a07

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +978 -388
index.html CHANGED
@@ -1,453 +1,1043 @@
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>TikTokSaver PRO β€” #1 TikTok Video Downloader (No Watermark, HD & 4K)</title>
7
- <meta name="description" content="Download TikTok videos without watermark in HD & 4K. Fast, free, secure. Choose any resolution and save instantly." />
8
- <script src="https://cdn.tailwindcss.com"></script>
9
- <script>
10
- tailwind.config = {
11
- theme: {
12
- extend: {
13
- colors: {
14
- ink: "#0B132B",
15
- canvas: "#F5F8FC",
16
- magenta: "#FF5393",
17
- royal: "#3B82F6",
18
- },
19
- fontFamily: { sans: ["Inter", "ui-sans-serif", "system-ui", "sans-serif"] },
20
- keyframes: {
21
- floaty: { "0%,100%": { transform: "translateY(0)" }, "50%": { transform: "translateY(-14px)" } },
22
- floatySlow: { "0%,100%": { transform: "translateY(0)" }, "50%": { transform: "translateY(18px)" } },
23
- shine: { "0%": { backgroundPosition: "0% 50%" }, "100%": { backgroundPosition: "200% 50%" } },
24
- popIn: { "0%": { opacity: "0", transform: "translateY(16px) scale(.98)" }, "100%": { opacity: "1", transform: "translateY(0) scale(1)" } },
25
- pulseRing: { "0%": { transform: "scale(.9)", opacity: ".7" }, "100%": { transform: "scale(1.6)", opacity: "0" } },
26
- marquee: { "0%": { transform: "translateX(0)" }, "100%": { transform: "translateX(-50%)" } },
27
- },
28
- animation: {
29
- floaty: "floaty 6s ease-in-out infinite",
30
- floatySlow: "floatySlow 8s ease-in-out infinite",
31
- shine: "shine 3s linear infinite",
32
- popIn: "popIn .5s cubic-bezier(.22,1,.36,1) forwards",
33
- pulseRing: "pulseRing 1.6s ease-out infinite",
34
- marquee: "marquee 22s linear infinite",
35
- },
36
- },
37
- },
38
- };
39
- </script>
40
- <link rel="preconnect" href="https://fonts.googleapis.com" />
41
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
42
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet" />
43
- <style>
44
- html { scroll-behavior: smooth; }
45
- body { font-family: "Inter", sans-serif; }
46
-
47
- /* Ambient blobs kept INSIDE the frame via overflow-hidden wrapper */
48
- .blob { position: absolute; border-radius: 9999px; filter: blur(70px); opacity: .55; z-index: 0; pointer-events: none; }
49
-
50
- .grad-text {
51
- background: linear-gradient(90deg, #FF5393, #8B5CF6, #3B82F6, #FF5393);
52
- background-size: 200% auto;
53
- -webkit-background-clip: text; background-clip: text; color: transparent;
54
- animation: shine 4s linear infinite;
55
- }
56
- .glass { background: rgba(255,255,255,.7); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); }
57
- .spin { animation: spin .7s linear infinite; }
58
- @keyframes spin { to { transform: rotate(360deg); } }
59
- .card-hover { transition: transform .25s ease, box-shadow .25s ease; }
60
- .card-hover:hover { transform: translateY(-4px); box-shadow: 0 18px 40px -12px rgba(59,130,246,.25); }
61
- .btn-grad { background: linear-gradient(90deg,#FF5393,#7C3AED,#3B82F6); background-size: 200% auto; transition: background-position .4s ease, transform .1s ease; }
62
- .btn-grad:hover { background-position: right center; }
63
- .btn-grad:active { transform: scale(.985); }
64
- .no-scrollbar::-webkit-scrollbar { display: none; }
65
- .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
66
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  </head>
68
- <body class="bg-canvas text-ink antialiased">
69
-
70
- <!-- ======================= APP FRAME ======================= -->
71
- <div class="relative mx-auto w-full max-w-[520px] md:max-w-2xl xl:max-w-3xl min-h-screen overflow-hidden shadow-2xl md:my-6 md:rounded-[36px] bg-canvas border border-white">
72
-
73
- <!-- Ambient mesh (contained) -->
74
- <div class="blob bg-pink-400 w-72 h-72 -top-24 -left-16 animate-floaty"></div>
75
- <div class="blob bg-indigo-400 w-72 h-72 -top-20 -right-16 animate-floatySlow"></div>
76
- <div class="blob bg-purple-300 w-64 h-64 top-[38%] -left-24 animate-floatySlow"></div>
77
- <div class="blob bg-sky-300 w-64 h-64 bottom-10 -right-24 animate-floaty"></div>
78
-
79
- <!-- Content -->
80
- <div class="relative z-10 px-5 md:px-10 py-6">
81
-
82
- <!-- ======= 1. NAV HEADER ======= -->
83
- <header class="flex items-center justify-between">
84
- <div class="flex items-center gap-2.5">
85
- <div class="relative w-10 h-10 rounded-2xl bg-black flex items-center justify-center shadow-lg">
86
- <span class="absolute inset-0 rounded-2xl ring-2 ring-magenta/40 animate-pulseRing"></span>
87
- <svg viewBox="0 0 24 24" class="w-5 h-5 relative" fill="white"><path d="M16.5 3c.3 2.1 1.5 3.6 3.5 3.9v2.4c-1.3.1-2.5-.3-3.6-1v6.1c0 3-2.2 5.6-5.5 5.6A5.4 5.4 0 0 1 5.4 14a5.4 5.4 0 0 1 6.2-5.4v2.5a2.9 2.9 0 0 0-3.6 2.9 2.9 2.9 0 0 0 5.8.1V3h2.7z"/></svg>
 
88
  </div>
89
- <div class="flex items-center gap-2">
90
- <span class="text-2xl font-extrabold tracking-tight"><span class="text-black">TikTok</span><span class="text-royal">Saver</span></span>
91
- <span class="text-[10px] font-bold text-white bg-gradient-to-r from-purple-500 to-indigo-500 px-2 py-0.5 rounded-full tracking-widest shadow">PRO</span>
 
 
 
 
 
 
 
92
  </div>
93
  </div>
94
- <button aria-label="Menu" class="p-2 rounded-xl text-slate-500 hover:bg-white/60 hover:text-slate-800 transition">
95
- <svg viewBox="0 0 24 24" class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="4" y1="7" x2="20" y2="7"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="17" x2="20" y2="17"/></svg>
96
- </button>
97
- </header>
98
-
99
- <!-- ======= 2. SOCIAL MEDIA ROW (top) ======= -->
100
- <div class="mt-5 flex items-center justify-center gap-2.5">
101
- <span class="text-[11px] font-medium text-slate-400 mr-1">Works with</span>
102
- <!-- TikTok -->
103
- <a href="#" class="w-9 h-9 rounded-full bg-black text-white flex items-center justify-center shadow-md card-hover" aria-label="TikTok"><svg viewBox="0 0 24 24" class="w-4 h-4" fill="currentColor"><path d="M16.5 3c.3 2.1 1.5 3.6 3.5 3.9v2.4c-1.3.1-2.5-.3-3.6-1v6.1c0 3-2.2 5.6-5.5 5.6A5.4 5.4 0 0 1 5.4 14a5.4 5.4 0 0 1 6.2-5.4v2.5a2.9 2.9 0 0 0-3.6 2.9 2.9 2.9 0 0 0 5.8.1V3h2.7z"/></svg></a>
104
- <!-- Instagram -->
105
- <a href="#" class="w-9 h-9 rounded-full text-white flex items-center justify-center shadow-md card-hover" style="background:linear-gradient(45deg,#F58529,#DD2A7B,#8134AF)" aria-label="Instagram"><svg viewBox="0 0 24 24" class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="1" fill="currentColor"/></svg></a>
106
- <!-- YouTube -->
107
- <a href="#" class="w-9 h-9 rounded-full bg-red-600 text-white flex items-center justify-center shadow-md card-hover" aria-label="YouTube"><svg viewBox="0 0 24 24" class="w-4 h-4" fill="currentColor"><path d="M23 12s0-3.5-.4-5c-.2-.9-.9-1.6-1.8-1.8C19 5 12 5 12 5s-7 0-8.8.2C2.3 5.4 1.6 6.1 1.4 7 1 8.5 1 12 1 12s0 3.5.4 5c.2.9.9 1.6 1.8 1.8C5 19 12 19 12 19s7 0 8.8-.2c.9-.2 1.6-.9 1.8-1.8.4-1.5.4-5 .4-5zM10 15V9l5 3-5 3z"/></svg></a>
108
- <!-- Facebook -->
109
- <a href="#" class="w-9 h-9 rounded-full bg-[#1877F2] text-white flex items-center justify-center shadow-md card-hover" aria-label="Facebook"><svg viewBox="0 0 24 24" class="w-4 h-4" fill="currentColor"><path d="M14 8h2V5h-2c-2 0-3 1.3-3 3v2H9v3h2v6h3v-6h2.2l.3-3H14V8.2c0-.1.1-.2.2-.2z"/></svg></a>
110
- <!-- Twitter/X -->
111
- <a href="#" class="w-9 h-9 rounded-full bg-black text-white flex items-center justify-center shadow-md card-hover" aria-label="X"><svg viewBox="0 0 24 24" class="w-3.5 h-3.5" fill="currentColor"><path d="M17.5 3h3l-6.6 7.6L21.8 21h-6l-4.7-6.1L5.6 21H2.5l7.1-8.1L2.3 3h6.1l4.3 5.6L17.5 3zm-1.1 16h1.7L7.7 4.8H5.9l10.5 14.2z"/></svg></a>
112
- </div>
113
 
114
- <!-- ======= 3. HERO ======= -->
115
- <section class="text-center mt-7">
116
- <div class="inline-flex items-center gap-1.5 glass border border-white/70 text-pink-600 text-xs font-semibold px-3.5 py-1.5 rounded-full shadow-sm">
117
- <svg viewBox="0 0 24 24" class="w-3.5 h-3.5" fill="currentColor"><path d="M12 2l2.4 4.9 5.4.8-3.9 3.8.9 5.4L12 14.9 7.2 17l.9-5.4L4.2 7.7l5.4-.8L12 2z"/></svg>
118
- #1 TikTok Downloader β€’ Trusted by 10M+
119
- </div>
120
 
121
- <h1 class="mt-5 text-5xl md:text-6xl font-black leading-[1.03] tracking-tight">
122
- Download <span class="grad-text">TikTok</span><br class="md:hidden"/> Videos in One Click
 
 
 
 
 
 
 
 
123
  </h1>
124
- <p class="mt-4 text-slate-500 text-base md:text-lg leading-relaxed max-w-md mx-auto">
125
- Fast, free and easy to use. Save TikTok videos <b class="text-slate-700">without watermark</b> in HD & 4K quality β€” pick any resolution and download instantly.
126
  </p>
127
-
128
- <!-- micro trust badges -->
129
- <div class="mt-5 flex items-center justify-center gap-2 flex-wrap">
130
- <span class="inline-flex items-center gap-1 text-[11px] font-medium text-slate-600 glass border border-white/70 px-2.5 py-1.5 rounded-full shadow-sm"><svg viewBox="0 0 24 24" class="w-3.5 h-3.5 text-red-500" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3s6 5 6 10a6 6 0 0 1-12 0c0-5 6-10 6-10z"/></svg>No Watermark</span>
131
- <span class="inline-flex items-center gap-1 text-[11px] font-medium text-slate-600 glass border border-white/70 px-2.5 py-1.5 rounded-full shadow-sm"><svg viewBox="0 0 24 24" class="w-3.5 h-3.5 text-indigo-500" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="5" width="18" height="12" rx="2"/><path d="M8 21h8"/></svg>HD Quality</span>
132
- <span class="inline-flex items-center gap-1 text-[11px] font-medium text-slate-600 glass border border-white/70 px-2.5 py-1.5 rounded-full shadow-sm"><svg viewBox="0 0 24 24" class="w-3.5 h-3.5 text-sky-500" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"><path d="M13 2 4 14h7l-1 8 9-12h-7l1-8z"/></svg>Super Fast</span>
133
- <span class="inline-flex items-center gap-1 text-[11px] font-medium text-slate-600 glass border border-white/70 px-2.5 py-1.5 rounded-full shadow-sm"><svg viewBox="0 0 24 24" class="w-3.5 h-3.5 text-emerald-500" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3l7 3v5c0 5-3.5 8-7 9-3.5-1-7-4-7-9V6l7-3z"/><path d="m9 12 2 2 4-4"/></svg>100% Safe</span>
134
- </div>
135
  </section>
136
 
137
- <!-- ======= 4. PASTE BOX + DOWNLOAD (top) ======= -->
138
- <section class="mt-6 glass border border-white/80 rounded-3xl shadow-xl p-4 md:p-5 animate-popIn">
139
- <div class="flex items-center gap-2 bg-white/80 border border-slate-100 rounded-2xl px-3 py-1.5">
140
- <svg viewBox="0 0 24 24" class="w-5 h-5 text-royal shrink-0" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M10 13a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1 1"/><path d="M14 11a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1-1"/></svg>
141
- <input id="urlInput" type="text" inputmode="url" autocomplete="off" placeholder="Paste TikTok video URL here..." class="flex-1 bg-transparent outline-none text-sm md:text-base text-slate-700 placeholder:text-slate-400 py-2.5" />
142
- <button id="pasteBtn" class="flex items-center gap-1 text-xs font-semibold text-slate-500 bg-slate-50 hover:bg-slate-100 border border-slate-100 px-3 py-2 rounded-xl transition">
143
- <svg viewBox="0 0 24 24" class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2"><rect x="8" y="8" width="12" height="12" rx="2"/><path d="M4 16V4a2 2 0 0 1 2-2h10"/></svg>Paste
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  </button>
145
  </div>
146
 
147
- <button id="downloadBtn" class="btn-grad mt-4 w-full flex items-center justify-center gap-2 text-white font-bold text-lg md:text-xl py-4 md:py-5 rounded-2xl shadow-lg shadow-pink-500/25">
148
- <span id="btnIcon"><svg viewBox="0 0 24 24" class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v12"/><path d="m7 11 5 5 5-5"/><path d="M5 21h14"/></svg></span>
149
- <span id="btnText">Download Now</span>
150
- </button>
151
- <p id="errorMsg" class="hidden mt-3 text-center text-sm text-red-500 font-medium"></p>
152
- <p class="mt-3 text-center text-[11px] text-slate-400">πŸ”’ No login required β€’ Unlimited downloads β€’ 100% free</p>
153
-
154
- <!-- LIVE RESULT (resolutions appear here after download) -->
155
- <div id="resultCard" class="hidden mt-5 bg-white rounded-2xl border border-slate-100 shadow-sm p-4 animate-popIn">
156
- <div class="flex gap-3">
157
- <div class="relative w-24 h-32 md:w-28 md:h-36 rounded-2xl overflow-hidden bg-slate-100 shrink-0">
158
- <img id="resThumb" alt="Video thumbnail" class="w-full h-full object-cover" />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  </div>
160
- <div class="flex-1 min-w-0">
161
- <p id="resTitle" class="text-sm md:text-base font-semibold text-ink line-clamp-3">Loading...</p>
162
- <div class="flex items-center gap-1.5 mt-2">
163
- <div class="w-6 h-6 rounded-full bg-slate-200 overflow-hidden shrink-0"><img id="resAvatar" alt="" class="w-full h-full object-cover" /></div>
164
- <span id="resAuthor" class="text-xs text-slate-500 truncate">@user</span>
165
- <svg class="w-3.5 h-3.5 text-sky-500 shrink-0" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l2.2 1.6 2.7-.2 1 2.5 2.5 1-.2 2.7L22 12l-1.6 2.2.2 2.7-2.5 1-1 2.5-2.7-.2L12 22l-2.2-1.6-2.7.2-1-2.5-2.5-1 .2-2.7L2 12l1.6-2.2-.2-2.7 2.5-1 1-2.5 2.7.2L12 2z"/><path d="M10.5 14.6l-2-2 1-1 1 1 3.4-3.4 1 1z" fill="white"/></svg>
166
  </div>
167
- <div id="resStats" class="flex items-center gap-3 mt-2 text-[11px] text-slate-400"></div>
 
 
 
 
 
 
 
 
168
  </div>
169
  </div>
170
- <p class="mt-4 mb-2 text-xs font-semibold text-slate-400 uppercase tracking-wide">Select resolution</p>
171
- <div id="resolutionList" class="space-y-2"></div>
172
  </div>
173
  </section>
174
 
175
- <!-- ======= 5. HOW IT WORKS (3 steps) ======= -->
176
- <section class="mt-8">
177
- <h2 class="text-center text-xl md:text-2xl font-extrabold">Download in <span class="grad-text">3 easy steps</span></h2>
178
- <div class="mt-4 grid grid-cols-3 gap-3">
179
- <div class="glass border border-white/80 rounded-2xl p-3 text-center card-hover">
180
- <div class="mx-auto w-9 h-9 rounded-full btn-grad text-white font-bold flex items-center justify-center">1</div>
181
- <p class="mt-2 text-xs font-semibold text-ink">Copy link</p>
182
- <p class="text-[10px] text-slate-400 leading-tight">Copy the TikTok video URL</p>
 
 
 
 
 
 
183
  </div>
184
- <div class="glass border border-white/80 rounded-2xl p-3 text-center card-hover">
185
- <div class="mx-auto w-9 h-9 rounded-full btn-grad text-white font-bold flex items-center justify-center">2</div>
186
- <p class="mt-2 text-xs font-semibold text-ink">Paste it</p>
187
- <p class="text-[10px] text-slate-400 leading-tight">Paste in the box above</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  </div>
189
- <div class="glass border border-white/80 rounded-2xl p-3 text-center card-hover">
190
- <div class="mx-auto w-9 h-9 rounded-full btn-grad text-white font-bold flex items-center justify-center">3</div>
191
- <p class="mt-2 text-xs font-semibold text-ink">Save</p>
192
- <p class="text-[10px] text-slate-400 leading-tight">Pick quality & download</p>
 
 
 
 
 
 
193
  </div>
 
194
  </div>
195
  </section>
196
 
197
- <!-- ======= 6. FEATURE GRID (2x2) ======= -->
198
- <section class="mt-8">
199
- <h2 class="text-center text-xl md:text-2xl font-extrabold">Why <span class="grad-text">TikTokSaver PRO</span>?</h2>
200
- <div class="mt-4 grid grid-cols-2 gap-3 md:gap-4">
201
- <div class="bg-white border border-slate-100/80 rounded-2xl shadow-sm p-4 card-hover">
202
- <div class="w-10 h-10 rounded-xl bg-pink-50 flex items-center justify-center"><svg viewBox="0 0 24 24" class="w-5 h-5 text-red-500" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3s6 5 6 10a6 6 0 0 1-12 0c0-5 6-10 6-10z"/></svg></div>
203
- <h3 class="mt-3 text-sm md:text-base font-bold">No Watermark</h3>
204
- <p class="mt-0.5 text-xs md:text-sm text-slate-500 leading-snug">Download clean videos without any watermark.</p>
 
 
 
 
205
  </div>
206
- <div class="bg-white border border-slate-100/80 rounded-2xl shadow-sm p-4 card-hover">
207
- <div class="w-10 h-10 rounded-xl bg-indigo-50 flex items-center justify-center"><svg viewBox="0 0 24 24" class="w-5 h-5 text-indigo-500" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="5" width="18" height="12" rx="2"/><path d="M8 21h8M12 17v4"/></svg></div>
208
- <h3 class="mt-3 text-sm md:text-base font-bold">HD Quality</h3>
209
- <p class="mt-0.5 text-xs md:text-sm text-slate-500 leading-snug">Save videos in HD quality up to 1080p.</p>
 
 
 
 
210
  </div>
211
- <div class="bg-white border border-slate-100/80 rounded-2xl shadow-sm p-4 card-hover">
212
- <div class="w-10 h-10 rounded-xl bg-sky-50 flex items-center justify-center"><svg viewBox="0 0 24 24" class="w-5 h-5 text-sky-500" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"><path d="M13 2 4 14h7l-1 8 9-12h-7l1-8z"/></svg></div>
213
- <h3 class="mt-3 text-sm md:text-base font-bold">Super Fast</h3>
214
- <p class="mt-0.5 text-xs md:text-sm text-slate-500 leading-snug">Lightning fast download servers worldwide.</p>
 
 
 
 
215
  </div>
216
- <div class="bg-white border border-slate-100/80 rounded-2xl shadow-sm p-4 card-hover">
217
- <div class="w-10 h-10 rounded-xl bg-emerald-50 flex items-center justify-center"><svg viewBox="0 0 24 24" class="w-5 h-5 text-emerald-500" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3l7 3v5c0 5-3.5 8-7 9-3.5-1-7-4-7-9V6l7-3z"/><path d="m9 12 2 2 4-4"/></svg></div>
218
- <h3 class="mt-3 text-sm md:text-base font-bold">100% Safe</h3>
219
- <p class="mt-0.5 text-xs md:text-sm text-slate-500 leading-snug">Secure and private. Your data is always safe.</p>
 
 
 
 
220
  </div>
221
  </div>
222
  </section>
223
 
224
- <!-- ======= 7. STATS ======= -->
225
- <section class="mt-8 glass border border-white/80 rounded-3xl shadow-md p-5">
226
- <div class="grid grid-cols-4 gap-2 text-center">
227
- <div><p class="text-lg md:text-2xl font-black grad-text">50M+</p><p class="text-[10px] md:text-xs text-slate-400 leading-tight">Videos Downloaded</p></div>
228
- <div><p class="text-lg md:text-2xl font-black grad-text">10M+</p><p class="text-[10px] md:text-xs text-slate-400 leading-tight">Happy Users</p></div>
229
- <div><p class="text-lg md:text-2xl font-black grad-text">99.9%</p><p class="text-[10px] md:text-xs text-slate-400 leading-tight">Uptime</p></div>
230
- <div><p class="text-lg md:text-2xl font-black grad-text">4.9/5</p><p class="text-[10px] md:text-xs text-slate-400 leading-tight">User Rating</p></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  </div>
232
  </section>
233
 
234
- <!-- ======= 8. PREMIUM BANNER ======= -->
235
- <section class="mt-8 relative bg-gradient-to-br from-purple-100 via-indigo-100 to-sky-100 border border-purple-100 rounded-3xl shadow-lg p-5 overflow-hidden">
236
- <span class="absolute top-0 right-0 bg-magenta text-white text-[10px] font-bold px-3 py-1 rounded-bl-2xl tracking-widest">PRO</span>
237
- <div class="flex items-start gap-4">
238
- <div class="w-16 h-16 shrink-0 flex items-center justify-center bg-gradient-to-br from-purple-500 to-indigo-600 shadow-lg shadow-purple-500/30" style="clip-path: polygon(30% 0,70% 0,100% 30%,100% 70%,70% 100%,30% 100%,0 70%,0 30%); border-radius:14px;">
239
- <svg viewBox="0 0 24 24" class="w-8 h-8 text-yellow-300" fill="currentColor"><path d="M3 8l4 4 5-7 5 7 4-4v9H3V8z"/></svg>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  </div>
241
- <div class="flex-1 pr-8">
242
- <h3 class="text-lg md:text-xl font-extrabold">Upgrade to TikTok<span class="text-royal">Saver</span> PRO</h3>
243
- <p class="mt-1 text-xs md:text-sm text-slate-600 leading-snug">Unlock 4K quality, batch download, audio-only extraction &amp; more premium features.</p>
 
 
 
 
244
  </div>
 
 
 
 
 
245
  </div>
246
- <button class="btn-grad mt-4 w-full flex items-center justify-center gap-2 text-white font-semibold text-sm md:text-base py-3.5 rounded-2xl shadow-lg shadow-purple-500/25">
247
- Get TikTokSaver PRO
248
- <svg viewBox="0 0 24 24" class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
249
- </button>
250
  </section>
251
 
252
- <!-- ======= 9. TESTIMONIALS MARQUEE ======= -->
253
- <section class="mt-8">
254
- <h2 class="text-center text-xl md:text-2xl font-extrabold">Loved by <span class="grad-text">creators</span></h2>
255
- <div class="mt-4 overflow-hidden no-scrollbar">
256
- <div class="flex gap-3 w-max animate-marquee">
257
- <!-- duplicate set for seamless loop -->
258
- <div class="w-64 glass border border-white/80 rounded-2xl p-4 shadow-sm shrink-0"><div class="flex items-center gap-1 text-amber-400 mb-2">β˜…β˜…β˜…β˜…β˜…</div><p class="text-xs text-slate-600">"Fastest downloader I've used. No watermark and crystal clear HD!"</p><p class="mt-2 text-[11px] font-semibold text-slate-400">β€” Aisha, Content Creator</p></div>
259
- <div class="w-64 glass border border-white/80 rounded-2xl p-4 shadow-sm shrink-0"><div class="flex items-center gap-1 text-amber-400 mb-2">β˜…β˜…β˜…β˜…β˜…</div><p class="text-xs text-slate-600">"I download dozens of clips daily. This never lets me down."</p><p class="mt-2 text-[11px] font-semibold text-slate-400">β€” Rafi, Video Editor</p></div>
260
- <div class="w-64 glass border border-white/80 rounded-2xl p-4 shadow-sm shrink-0"><div class="flex items-center gap-1 text-amber-400 mb-2">β˜…β˜…β˜…β˜…β˜…</div><p class="text-xs text-slate-600">"Choosing the resolution before download is a game changer."</p><p class="mt-2 text-[11px] font-semibold text-slate-400">β€” Mei, Influencer</p></div>
261
- <div class="w-64 glass border border-white/80 rounded-2xl p-4 shadow-sm shrink-0"><div class="flex items-center gap-1 text-amber-400 mb-2">β˜…β˜…β˜…β˜…β˜…</div><p class="text-xs text-slate-600">"Fastest downloader I've used. No watermark and crystal clear HD!"</p><p class="mt-2 text-[11px] font-semibold text-slate-400">β€” Aisha, Content Creator</p></div>
262
- <div class="w-64 glass border border-white/80 rounded-2xl p-4 shadow-sm shrink-0"><div class="flex items-center gap-1 text-amber-400 mb-2">β˜…β˜…β˜…β˜…β˜…</div><p class="text-xs text-slate-600">"I download dozens of clips daily. This never lets me down."</p><p class="mt-2 text-[11px] font-semibold text-slate-400">β€” Rafi, Video Editor</p></div>
263
- <div class="w-64 glass border border-white/80 rounded-2xl p-4 shadow-sm shrink-0"><div class="flex items-center gap-1 text-amber-400 mb-2">β˜…β˜…β˜…β˜…β˜…</div><p class="text-xs text-slate-600">"Choosing the resolution before download is a game changer."</p><p class="mt-2 text-[11px] font-semibold text-slate-400">β€” Mei, Influencer</p></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  </div>
265
  </div>
266
  </section>
267
 
268
- <!-- ======= 10. PREVIEW (bottom, as requested) ======= -->
269
- <section class="mt-8">
270
- <h2 class="text-center text-xl md:text-2xl font-extrabold">See a <span class="grad-text">preview</span></h2>
271
- <div class="mt-4 bg-white border border-slate-100/80 rounded-3xl shadow-md p-4 card-hover">
272
- <div class="flex gap-3">
273
- <div class="relative w-28 h-36 md:w-32 md:h-44 rounded-2xl overflow-hidden bg-gradient-to-br from-pink-200 to-purple-200 shrink-0">
274
- <div class="absolute top-2 left-2 w-6 h-6 rounded-md bg-black/70 flex items-center justify-center"><svg viewBox="0 0 24 24" class="w-3.5 h-3.5" fill="white"><path d="M16.5 3c.3 2.1 1.5 3.6 3.5 3.9v2.4c-1.3.1-2.5-.3-3.6-1v6.1c0 3-2.2 5.6-5.5 5.6A5.4 5.4 0 0 1 5.4 14a5.4 5.4 0 0 1 6.2-5.4v2.5a2.9 2.9 0 0 0-3.6 2.9 2.9 2.9 0 0 0 5.8.1V3h2.7z"/></svg></div>
275
- <span class="absolute bottom-2 left-2 text-[10px] font-semibold text-white bg-black/70 px-1.5 py-0.5 rounded">00:15</span>
276
- <div class="absolute inset-0 flex items-center justify-center"><span class="w-11 h-11 rounded-full bg-white/80 flex items-center justify-center shadow"><svg viewBox="0 0 24 24" class="w-5 h-5 text-royal" fill="currentColor"><path d="M8 5v14l11-7z"/></svg></span></div>
 
 
277
  </div>
278
- <div class="flex-1 min-w-0">
279
- <p class="text-sm md:text-base font-semibold leading-snug">Good vibes only ✨ #fyp #tiktok</p>
280
- <div class="flex items-center gap-1.5 mt-2">
281
- <div class="w-6 h-6 rounded-full bg-gradient-to-br from-pink-300 to-purple-300"></div>
282
- <span class="text-xs text-slate-500">@happyvibes</span>
283
- <svg class="w-3.5 h-3.5 text-sky-500" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l2.2 1.6 2.7-.2 1 2.5 2.5 1-.2 2.7L22 12l-1.6 2.2.2 2.7-2.5 1-1 2.5-2.7-.2L12 22l-2.2-1.6-2.7.2-1-2.5-2.5-1 .2-2.7L2 12l1.6-2.2-.2-2.7 2.5-1 1-2.5 2.7.2L12 2z"/><path d="M10.5 14.6l-2-2 1-1 1 1 3.4-3.4 1 1z" fill="white"/></svg>
284
  </div>
285
- <div class="flex items-center gap-4 mt-3 text-xs text-slate-500">
286
- <span class="flex items-center gap-1"><svg viewBox="0 0 24 24" class="w-3.5 h-3.5" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>8.6M</span>
287
- <span class="flex items-center gap-1"><svg viewBox="0 0 24 24" class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 21s-7-4.5-9-9c-1.5-3.5 1-6.5 4-6.5 2 0 3.5 1.5 5 3 1.5-1.5 3-3 5-3 3 0 5.5 3 4 6.5-2 4.5-9 9-9 9z"/></svg>863K</span>
288
- <span class="flex items-center gap-1"><svg viewBox="0 0 24 24" class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12a8 8 0 0 1-11.5 7.2L3 21l1.8-6.5A8 8 0 1 1 21 12z"/></svg>2.1K</span>
 
 
 
 
 
 
 
 
 
289
  </div>
 
 
290
  </div>
291
  </div>
292
- <button class="mt-4 w-full flex items-center justify-center gap-2 border border-slate-200 text-slate-600 font-medium text-sm py-3 rounded-2xl hover:bg-slate-50 transition">
293
- <svg viewBox="0 0 24 24" class="w-4 h-4 text-royal" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"/><path d="M10 9l5 3-5 3z" fill="currentColor" stroke="none"/></svg>Preview Video
294
- </button>
295
  </div>
296
  </section>
297
 
298
- <!-- ======= 11. INTRODUCTION / ABOUT (very bottom) ======= -->
299
- <section class="mt-8 glass border border-white/80 rounded-3xl shadow-md p-5">
300
- <h2 class="text-lg md:text-xl font-extrabold">What is TikTokSaver PRO?</h2>
301
- <p class="mt-2 text-sm text-slate-600 leading-relaxed">
302
- <b>TikTokSaver PRO</b> is the fastest and cleanest way to save TikTok videos directly to your device β€” with <b>no watermark</b>, in full <b>HD & 4K</b> quality. Just paste any TikTok link, choose your preferred resolution, and the file downloads instantly. No apps, no sign-up, no hidden fees.
303
- </p>
304
-
305
- <div class="mt-4 space-y-2.5">
306
- <details class="bg-white border border-slate-100 rounded-2xl px-4 py-3 group">
307
- <summary class="flex items-center justify-between cursor-pointer text-sm font-semibold text-ink list-none">Is it really free?<span class="text-slate-400 group-open:rotate-45 transition">+</span></summary>
308
- <p class="mt-2 text-xs text-slate-500 leading-relaxed">Yes β€” unlimited downloads are 100% free. PRO adds 4K, batch and audio-only extras.</p>
309
- </details>
310
- <details class="bg-white border border-slate-100 rounded-2xl px-4 py-3 group">
311
- <summary class="flex items-center justify-between cursor-pointer text-sm font-semibold text-ink list-none">Do you store my videos?<span class="text-slate-400 group-open:rotate-45 transition">+</span></summary>
312
- <p class="mt-2 text-xs text-slate-500 leading-relaxed">Never. Files stream straight to your device β€” we don't keep any copies or personal data.</p>
313
- </details>
314
- <details class="bg-white border border-slate-100 rounded-2xl px-4 py-3 group">
315
- <summary class="flex items-center justify-between cursor-pointer text-sm font-semibold text-ink list-none">Which quality can I get?<span class="text-slate-400 group-open:rotate-45 transition">+</span></summary>
316
- <p class="mt-2 text-xs text-slate-500 leading-relaxed">HD no-watermark, standard no-watermark, original with watermark, and MP3 audio β€” pick from the list after clicking Download.</p>
317
- </details>
318
  </div>
319
- </section>
320
-
321
- <!-- ======= FOOTER ======= -->
322
- <footer class="mt-8 pb-6 text-center">
323
- <div class="flex items-center justify-center gap-1.5 text-xs text-slate-400">
324
- <svg viewBox="0 0 24 24" class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>
325
- We respect your privacy. No data is stored.
326
  </div>
327
- <p class="mt-3 text-[11px] text-slate-400">Β© 2026 TikTokSaver PRO Β· Not affiliated with TikTok / ByteScript.</p>
 
 
 
328
  </footer>
329
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
  </div>
331
- </div>
332
-
333
- <!-- ======================= JAVASCRIPT ======================= -->
334
- <script>
335
- (function () {
336
- "use strict";
337
-
338
- const $ = (id) => document.getElementById(id);
339
- const urlInput = $("urlInput"), pasteBtn = $("pasteBtn"), downloadBtn = $("downloadBtn");
340
- const btnIcon = $("btnIcon"), btnText = $("btnText"), errorMsg = $("errorMsg");
341
- const resultCard = $("resultCard"), resThumb = $("resThumb"), resTitle = $("resTitle");
342
- const resAuthor = $("resAuthor"), resAvatar = $("resAvatar"), resStats = $("resStats"), resList = $("resolutionList");
343
-
344
- const TIKTOK_REGEX = /https?:\/\/(www\.|vm\.|vt\.|m\.)?tiktok\.com\/[^\s]+/i;
345
-
346
- const defaultIcon = '<svg viewBox="0 0 24 24" class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v12"/><path d="m7 11 5 5 5-5"/><path d="M5 21h14"/></svg>';
347
- const spinnerIcon = '<svg viewBox="0 0 24 24" class="w-6 h-6 spin" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M12 3a9 9 0 1 0 9 9"/></svg>';
348
-
349
- function showError(m){ errorMsg.textContent = m; errorMsg.classList.remove("hidden"); }
350
- function clearError(){ errorMsg.textContent = ""; errorMsg.classList.add("hidden"); }
351
- function fmt(n){ if(n==null) return "0"; n=+n; if(n>=1e6) return (n/1e6).toFixed(1)+"M"; if(n>=1e3) return (n/1e3).toFixed(1)+"K"; return ""+n; }
352
-
353
- function setLoading(on){
354
- if(on){ downloadBtn.disabled=true; downloadBtn.classList.add("opacity-80","cursor-not-allowed"); btnIcon.innerHTML=spinnerIcon; btnText.textContent="Fetching..."; }
355
- else { downloadBtn.disabled=false; downloadBtn.classList.remove("opacity-80","cursor-not-allowed"); btnIcon.innerHTML=defaultIcon; btnText.textContent="Download Now"; }
356
- }
357
-
358
- pasteBtn.addEventListener("click", async () => {
359
- try { const t = await navigator.clipboard.readText(); if(t){ urlInput.value=t.trim(); clearError(); } }
360
- catch(e){ showError("Clipboard access denied. Please paste manually."); }
361
- });
362
-
363
- async function forceDownload(fileUrl, filename){
364
- try {
365
- const resp = await fetch(fileUrl);
366
- const blob = await resp.blob();
367
- const objectUrl = URL.createObjectURL(blob);
368
- const a = document.createElement("a");
369
- a.href = objectUrl; a.download = filename; a.style.display = "none";
370
- document.body.appendChild(a); a.click(); document.body.removeChild(a);
371
- setTimeout(() => URL.revokeObjectURL(objectUrl), 4000);
372
- } catch(e){
373
- const a = document.createElement("a");
374
- a.href = fileUrl; a.download = filename; a.target = "_blank"; a.rel = "noopener"; a.style.display = "none";
375
- document.body.appendChild(a); a.click(); document.body.removeChild(a);
376
- }
377
- }
378
-
379
- function buildRow(o){
380
- const row = document.createElement("div");
381
- row.className = "flex items-center justify-between gap-3 border border-slate-100 rounded-2xl px-3.5 py-3 hover:bg-slate-50 transition";
382
- row.innerHTML =
383
- '<div class="flex items-center gap-2.5 min-w-0">' +
384
- '<span class="w-8 h-8 rounded-xl flex items-center justify-center '+o.color+'">'+
385
- '<svg viewBox="0 0 24 24" class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="5" width="18" height="12" rx="2"/><path d="M8 21h8"/></svg>'+
386
- '</span>'+
387
- '<div class="min-w-0"><p class="text-sm font-semibold text-ink truncate">'+o.label+'</p>'+
388
- '<p class="text-[11px] text-slate-400 truncate">'+o.sub+'</p></div>'+
389
- '</div>';
390
- const btn = document.createElement("button");
391
- btn.className = "btn-grad shrink-0 flex items-center gap-1 text-white text-xs font-semibold px-3.5 py-2 rounded-xl shadow";
392
- btn.innerHTML = '<svg viewBox="0 0 24 24" class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v11"/><path d="m8 11 4 4 4-4"/><path d="M5 21h14"/></svg>Download';
393
- btn.addEventListener("click", async () => {
394
- const original = btn.innerHTML; btn.disabled = true;
395
- btn.innerHTML = '<svg viewBox="0 0 24 24" class="w-3.5 h-3.5 spin" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"><path d="M12 3a9 9 0 1 0 9 9"/></svg>Saving';
396
- await forceDownload(o.url, o.file);
397
- btn.disabled = false; btn.innerHTML = original;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
398
  });
399
- row.appendChild(btn);
400
- return row;
401
- }
402
-
403
- function render(data){
404
- resList.innerHTML = "";
405
- const safe = (data.title || "tiktok-video").replace(/[^\w\-]+/g,"_").slice(0,40);
406
- const opts = [];
407
- if(data.hdplay) opts.push({label:"HD No Watermark", sub:"Highest quality (1080p)", color:"bg-indigo-50 text-indigo-500", url:data.hdplay, file:safe+"_HD.mp4"});
408
- if(data.play) opts.push({label:"No Watermark", sub:"Standard quality (720p)", color:"bg-pink-50 text-pink-500", url:data.play, file:safe+"_NoWatermark.mp4"});
409
- if(data.wmplay) opts.push({label:"With Watermark", sub:"Original TikTok watermark", color:"bg-sky-50 text-sky-500", url:data.wmplay, file:safe+"_Watermark.mp4"});
410
- if(data.music) opts.push({label:"Audio Only (MP3)", sub:"Extract sound track", color:"bg-emerald-50 text-emerald-500", url:data.music, file:safe+"_Audio.mp3"});
411
- if(!opts.length){ showError("No downloadable formats found for this video."); return; }
412
- opts.forEach(o => resList.appendChild(buildRow(o)));
413
- }
414
-
415
- async function handleDownload(){
416
- clearError();
417
- const raw = (urlInput.value || "").trim();
418
- if(!raw){ showError("Please paste a TikTok video URL."); return; }
419
- if(!TIKTOK_REGEX.test(raw)){ showError("That doesn't look like a valid TikTok URL."); return; }
420
-
421
- setLoading(true);
422
- resultCard.classList.add("hidden");
423
- try {
424
- const endpoint = "https://tikwm.com/api/?url=" + encodeURIComponent(raw) + "&hd=1";
425
- const res = await fetch(endpoint, { headers: { "Accept": "application/json" } });
426
- const json = await res.json();
427
- if(!json || json.code !== 0 || !json.data) throw new Error((json && json.msg) || "Failed to process this video.");
428
- const d = json.data;
429
-
430
- resThumb.src = d.cover || d.origin_cover || "";
431
- resTitle.textContent = d.title || "Untitled TikTok video";
432
- if(d.author){ resAuthor.textContent = "@" + (d.author.unique_id || d.author.nickname || "user"); resAvatar.src = d.author.avatar || ""; }
433
- resStats.innerHTML =
434
- '<span class="flex items-center gap-1">β–· '+fmt(d.play_count)+'</span>'+
435
- '<span class="flex items-center gap-1">β™‘ '+fmt(d.digg_count)+'</span>'+
436
- '<span class="flex items-center gap-1">πŸ’¬ '+fmt(d.comment_count)+'</span>';
437
-
438
- render(d);
439
- resultCard.classList.remove("hidden");
440
- resultCard.scrollIntoView({ behavior: "smooth", block: "center" });
441
- } catch(err){
442
- showError(err.message || "Something went wrong. Please try again.");
443
- } finally {
444
- setLoading(false);
445
- }
446
- }
447
 
448
- downloadBtn.addEventListener("click", handleDownload);
449
- urlInput.addEventListener("keydown", (e) => { if(e.key === "Enter"){ e.preventDefault(); handleDownload(); } });
450
- })();
451
- </script>
452
  </body>
453
  </html>
 
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>TikTokSaver PRO – Download TikTok Videos Without Watermark</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet" />
11
+ <style>
12
+ * { font-family: 'Inter', sans-serif; box-sizing: border-box; }
13
+ body { background-color: #F5F8FC; overflow-x: hidden; }
14
+ .blob-pink {
15
+ position: fixed; top: -120px; left: -120px;
16
+ width: 420px; height: 420px;
17
+ background: radial-gradient(circle, rgba(255,150,180,0.35) 0%, rgba(255,100,150,0.12) 60%, transparent 100%);
18
+ border-radius: 50%; pointer-events: none; z-index: 0;
19
+ }
20
+ .blob-blue {
21
+ position: fixed; top: -100px; right: -100px;
22
+ width: 380px; height: 380px;
23
+ background: radial-gradient(circle, rgba(140,160,255,0.30) 0%, rgba(100,130,255,0.10) 60%, transparent 100%);
24
+ border-radius: 50%; pointer-events: none; z-index: 0;
25
+ }
26
+ .brand-gradient { background: linear-gradient(90deg, #FF5393 0%, #3B82F6 100%); }
27
+ .brand-gradient-text {
28
+ background: linear-gradient(90deg, #FF5393 0%, #3B82F6 100%);
29
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent;
30
+ background-clip: text;
31
+ }
32
+ .pro-badge { background: linear-gradient(135deg, #7C3AED 0%, #4F46E5 100%); }
33
+ .btn-download {
34
+ background: linear-gradient(90deg, #FF5393 0%, #3B82F6 100%);
35
+ transition: opacity 0.2s ease, transform 0.15s ease;
36
+ }
37
+ .btn-download:hover { opacity: 0.92; transform: translateY(-1px); }
38
+ .btn-download:active { transform: translateY(0px); opacity: 1; }
39
+ .feature-card { transition: transform 0.2s ease, box-shadow 0.2s ease; }
40
+ .feature-card:hover { transform: translateY(-3px); box-shadow: 0 12px 32px rgba(0,0,0,0.10); }
41
+ .url-input:focus { outline: none; }
42
+ .input-wrapper:focus-within { box-shadow: 0 0 0 3px rgba(99,102,241,0.18), 0 8px 30px rgba(0,0,0,0.10); }
43
+ .result-section {
44
+ opacity: 0; transform: translateY(18px);
45
+ transition: opacity 0.4s ease, transform 0.4s ease;
46
+ pointer-events: none;
47
+ }
48
+ .result-section.visible { opacity: 1; transform: translateY(0); pointer-events: all; }
49
+ @keyframes spin { to { transform: rotate(360deg); } }
50
+ .spinner { animation: spin 0.75s linear infinite; display: inline-block; }
51
+ @keyframes pulse-ring {
52
+ 0% { transform: scale(0.9); opacity: 0.7; }
53
+ 100% { transform: scale(1.15); opacity: 0; }
54
+ }
55
+ .pulse-ring { animation: pulse-ring 1.1s ease-out infinite; }
56
+ .pro-banner {
57
+ background: linear-gradient(135deg, #EDE9FE 0%, #DDD6FE 50%, #C7D2FE 100%);
58
+ border: 1px solid rgba(139,92,246,0.20);
59
+ }
60
+ .ham-line { display: block; width: 22px; height: 2px; background: #64748B; border-radius: 2px; }
61
+ .hero-pill {
62
+ background: linear-gradient(90deg, rgba(255,83,147,0.12) 0%, rgba(59,130,246,0.10) 100%);
63
+ border: 1px solid rgba(255,83,147,0.22);
64
+ }
65
+ .icon-bg-red { background: rgba(239,68,68,0.10); }
66
+ .icon-bg-indigo { background: rgba(99,102,241,0.10); }
67
+ .icon-bg-sky { background: rgba(14,165,233,0.10); }
68
+ .icon-bg-green { background: rgba(16,185,129,0.10); }
69
+ ::-webkit-scrollbar { width: 5px; }
70
+ ::-webkit-scrollbar-track { background: #F1F5F9; }
71
+ ::-webkit-scrollbar-thumb { background: #CBD5E1; border-radius: 10px; }
72
+ .toast {
73
+ position: fixed; bottom: 28px; left: 50%; transform: translateX(-50%) translateY(80px);
74
+ background: #1E293B; color: #fff; padding: 12px 24px; border-radius: 50px;
75
+ font-size: 14px; font-weight: 500; z-index: 9999;
76
+ transition: transform 0.35s cubic-bezier(0.34,1.56,0.64,1), opacity 0.35s ease;
77
+ opacity: 0; white-space: nowrap; pointer-events: none;
78
+ }
79
+ .toast.show { transform: translateX(-50%) translateY(0); opacity: 1; }
80
+ .mobile-menu { max-height: 0; overflow: hidden; transition: max-height 0.35s ease; }
81
+ .mobile-menu.open { max-height: 300px; }
82
+ .faq-answer { max-height: 0; overflow: hidden; transition: max-height 0.35s ease; }
83
+ .faq-answer.open { max-height: 200px; padding-top: 10px; padding-bottom: 14px; }
84
+ .faq-arrow { transition: transform 0.3s ease; }
85
+ .faq-arrow.open { transform: rotate(180deg); }
86
+
87
+ /* ── RESOLUTION CARD ── */
88
+ .res-card {
89
+ border: 2px solid #E2E8F0;
90
+ border-radius: 16px;
91
+ padding: 14px 16px;
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: space-between;
95
+ gap: 12px;
96
+ background: #fff;
97
+ transition: border-color 0.18s, box-shadow 0.18s;
98
+ }
99
+ .res-card:hover { border-color: #A5B4FC; box-shadow: 0 4px 18px rgba(99,102,241,0.10); }
100
+ .res-dl-btn {
101
+ flex-shrink: 0;
102
+ display: flex; align-items: center; gap: 6px;
103
+ padding: 9px 18px;
104
+ border-radius: 50px;
105
+ font-size: 13px; font-weight: 700;
106
+ background: linear-gradient(90deg, #FF5393 0%, #3B82F6 100%);
107
+ color: #fff;
108
+ cursor: pointer; border: none; outline: none;
109
+ transition: opacity 0.18s, transform 0.15s;
110
+ white-space: nowrap;
111
+ }
112
+ .res-dl-btn:hover { opacity: 0.88; transform: translateY(-1px); }
113
+ .res-dl-btn:active { transform: translateY(0); }
114
+ .res-dl-btn.loading { opacity: 0.7; pointer-events: none; }
115
+ .res-badge {
116
+ display: inline-flex; align-items: center;
117
+ padding: 2px 10px; border-radius: 50px;
118
+ font-size: 11px; font-weight: 700; letter-spacing: 0.04em;
119
+ }
120
+ /* shimmer skeleton */
121
+ @keyframes shimmer {
122
+ 0% { background-position: -600px 0; }
123
+ 100% { background-position: 600px 0; }
124
+ }
125
+ .skeleton {
126
+ background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);
127
+ background-size: 600px 100%;
128
+ animation: shimmer 1.4s infinite linear;
129
+ border-radius: 8px;
130
+ }
131
+ /* Download progress overlay on button */
132
+ .res-dl-btn .btn-inner { display: flex; align-items: center; gap: 6px; }
133
+ .res-section { display: none; }
134
+ .res-section.show { display: block; }
135
+ </style>
136
  </head>
137
+ <body class="min-h-screen relative">
138
+
139
+ <div class="blob-pink"></div>
140
+ <div class="blob-blue"></div>
141
+ <div id="toast" class="toast"></div>
142
+
143
+ <!-- ── HEADER ── -->
144
+ <header class="relative z-10 w-full bg-white/70 backdrop-blur-md border-b border-slate-100 sticky top-0">
145
+ <nav class="max-w-xl mx-auto px-4 py-3">
146
+ <div class="flex items-center justify-between">
147
+ <div class="flex items-center gap-2.5">
148
+ <div class="w-10 h-10 bg-black rounded-xl flex items-center justify-center shadow-md flex-shrink-0">
149
+ <svg width="22" height="22" viewBox="0 0 24 24" fill="none">
150
+ <path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 0 1-2.88 2.5 2.89 2.89 0 0 1-2.89-2.89 2.89 2.89 0 0 1 2.89-2.89c.28 0 .54.04.79.1V9.01a6.33 6.33 0 0 0-.79-.05 6.34 6.34 0 0 0-6.34 6.34 6.34 6.34 0 0 0 6.34 6.34 6.34 6.34 0 0 0 6.33-6.34V8.95a8.2 8.2 0 0 0 4.8 1.54V7.04a4.85 4.85 0 0 1-1.03-.35z" fill="white"/>
151
+ </svg>
152
+ </div>
153
+ <div class="flex items-center gap-1.5">
154
+ <span class="text-[17px] font-black text-[#0B132B] tracking-tight">TikTok</span>
155
+ <span class="text-[17px] font-black text-blue-500 tracking-tight">Saver</span>
156
+ <span class="pro-badge text-white text-[10px] font-bold px-2 py-0.5 rounded-full ml-0.5 tracking-wide">PRO</span>
157
+ </div>
158
  </div>
159
+ <button id="menuToggle" class="w-10 h-10 flex flex-col items-center justify-center gap-[5px] rounded-xl hover:bg-slate-50 transition-colors">
160
+ <span class="ham-line"></span><span class="ham-line"></span><span class="ham-line"></span>
161
+ </button>
162
+ </div>
163
+ <div id="mobileMenu" class="mobile-menu">
164
+ <div class="pt-3 pb-2 flex flex-col gap-1 border-t border-slate-100 mt-3">
165
+ <a href="#features" class="text-slate-600 font-medium text-sm px-3 py-2.5 rounded-xl hover:bg-slate-50 transition-colors">Features</a>
166
+ <a href="#howto" class="text-slate-600 font-medium text-sm px-3 py-2.5 rounded-xl hover:bg-slate-50 transition-colors">How to Use</a>
167
+ <a href="#faq" class="text-slate-600 font-medium text-sm px-3 py-2.5 rounded-xl hover:bg-slate-50 transition-colors">FAQ</a>
168
+ <a href="#pro" class="text-slate-600 font-medium text-sm px-3 py-2.5 rounded-xl hover:bg-slate-50 transition-colors">Upgrade PRO</a>
169
  </div>
170
  </div>
171
+ </nav>
172
+ </header>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
+ <!-- ── MAIN ── -->
175
+ <main class="relative z-10 max-w-xl mx-auto px-4 py-6 flex flex-col gap-6">
 
 
 
 
176
 
177
+ <!-- ── HERO ── -->
178
+ <section class="text-center pt-4 pb-2">
179
+ <div class="inline-flex items-center gap-1.5 hero-pill px-4 py-1.5 rounded-full mb-5">
180
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none">
181
+ <path d="M12 2l2.4 7.4H22l-6.2 4.5 2.4 7.4L12 17l-6.2 4.3 2.4-7.4L2 9.4h7.6z" fill="#FF5393"/>
182
+ </svg>
183
+ <span class="text-[13px] font-semibold text-slate-700">#1 TikTok Downloader</span>
184
+ </div>
185
+ <h1 class="text-[34px] sm:text-[40px] font-black text-[#0B132B] leading-[1.12] tracking-tight mb-4">
186
+ Download<br /><span class="brand-gradient-text">TikTok</span><br />Videos in One Click
187
  </h1>
188
+ <p class="text-slate-500 text-[15px] leading-relaxed max-w-xs mx-auto">
189
+ Fast, free and easy to use.<br />Save TikTok videos without watermark in HD quality.
190
  </p>
 
 
 
 
 
 
 
 
191
  </section>
192
 
193
+ <!-- ── INPUT BLOCK ── -->
194
+ <section>
195
+ <div class="input-wrapper bg-white rounded-2xl shadow-lg border border-slate-100 p-1.5">
196
+ <div class="flex items-center gap-2 px-3 py-2.5">
197
+ <svg class="w-5 h-5 text-slate-400 flex-shrink-0" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
198
+ <path stroke-linecap="round" stroke-linejoin="round" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"/>
199
+ </svg>
200
+ <input id="urlInput" type="url" class="url-input flex-1 text-[14px] text-slate-700 placeholder-slate-400 bg-transparent min-w-0"
201
+ placeholder="Paste TikTok video URL here..." autocomplete="off" spellcheck="false" />
202
+ <button id="pasteBtn" class="flex-shrink-0 text-[13px] font-semibold text-indigo-500 hover:text-indigo-700 bg-indigo-50 hover:bg-indigo-100 px-3 py-1.5 rounded-lg transition-colors flex items-center gap-1">
203
+ <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
204
+ <rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
205
+ <path stroke-linecap="round" stroke-linejoin="round" d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
206
+ </svg>
207
+ Paste
208
+ </button>
209
+ </div>
210
+
211
+ <!-- main CTA button -->
212
+ <button id="downloadBtn" class="btn-download w-full rounded-xl py-4 flex items-center justify-center gap-2.5 mt-1 relative overflow-hidden">
213
+ <span id="downloadBtnIcon">
214
+ <svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
215
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
216
+ </svg>
217
+ </span>
218
+ <span id="downloadBtnText" class="text-white font-bold text-[15px] tracking-wide">Download</span>
219
  </button>
220
  </div>
221
 
222
+ <!-- error -->
223
+ <div id="errorMsg" class="hidden mt-3 bg-red-50 border border-red-100 rounded-xl px-4 py-3 flex items-center gap-2.5">
224
+ <svg class="w-4 h-4 text-red-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
225
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
226
+ </svg>
227
+ <span id="errorText" class="text-red-600 text-[13px] font-medium"></span>
228
+ </div>
229
+ </section>
230
+
231
+ <!-- ── BADGES ROW ── -->
232
+ <section>
233
+ <div class="bg-white rounded-2xl border border-slate-100 shadow-sm px-4 py-3">
234
+ <div class="grid grid-cols-4 gap-1">
235
+ <div class="flex flex-col items-center gap-1.5">
236
+ <div class="icon-bg-red w-9 h-9 rounded-xl flex items-center justify-center">
237
+ <svg width="18" height="18" fill="none" stroke="#EF4444" stroke-width="2" viewBox="0 0 24 24">
238
+ <path stroke-linecap="round" stroke-linejoin="round" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"/>
239
+ </svg>
240
+ </div>
241
+ <span class="text-[11px] font-semibold text-slate-600 text-center leading-tight">No Watermark</span>
242
+ </div>
243
+ <div class="flex flex-col items-center gap-1.5">
244
+ <div class="icon-bg-indigo w-9 h-9 rounded-xl flex items-center justify-center">
245
+ <svg width="18" height="18" fill="none" stroke="#6366F1" stroke-width="2" viewBox="0 0 24 24">
246
+ <rect x="2" y="3" width="20" height="14" rx="2"/><path stroke-linecap="round" d="M8 21h8m-4-4v4"/>
247
+ </svg>
248
+ </div>
249
+ <span class="text-[11px] font-semibold text-slate-600 text-center leading-tight">HD Quality</span>
250
  </div>
251
+ <div class="flex flex-col items-center gap-1.5">
252
+ <div class="icon-bg-sky w-9 h-9 rounded-xl flex items-center justify-center">
253
+ <svg width="18" height="18" fill="none" stroke="#0EA5E9" stroke-width="2" viewBox="0 0 24 24">
254
+ <path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z"/>
255
+ </svg>
 
256
  </div>
257
+ <span class="text-[11px] font-semibold text-slate-600 text-center leading-tight">Super Fast</span>
258
+ </div>
259
+ <div class="flex flex-col items-center gap-1.5">
260
+ <div class="icon-bg-green w-9 h-9 rounded-xl flex items-center justify-center">
261
+ <svg width="18" height="18" fill="none" stroke="#10B981" stroke-width="2" viewBox="0 0 24 24">
262
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>
263
+ </svg>
264
+ </div>
265
+ <span class="text-[11px] font-semibold text-slate-600 text-center leading-tight">100% Safe</span>
266
  </div>
267
  </div>
 
 
268
  </div>
269
  </section>
270
 
271
+ <!-- ════════════════════════════════════════════════════════
272
+ RESULT SECTION (hidden until fetch succeeds)
273
+ ════════════════════════════════════════════════════════ -->
274
+ <section id="resultSection" class="result-section">
275
+ <div class="bg-white rounded-3xl border border-slate-100 shadow-lg overflow-hidden">
276
+
277
+ <!-- top bar -->
278
+ <div class="px-5 pt-4 pb-2 flex items-center justify-between">
279
+ <span class="text-[12px] font-semibold text-slate-400 uppercase tracking-widest">Search Result</span>
280
+ <button id="clearResult" class="text-slate-400 hover:text-slate-600 transition-colors p-1">
281
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
282
+ <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
283
+ </svg>
284
+ </button>
285
  </div>
286
+
287
+ <!-- video info row -->
288
+ <div class="px-4 pb-4">
289
+ <div class="flex gap-4">
290
+ <!-- thumbnail -->
291
+ <div class="relative flex-shrink-0 rounded-2xl overflow-hidden w-[106px] h-[144px] bg-slate-100 shadow">
292
+ <img id="videoThumb" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='106' height='144'%3E%3Crect fill='%23E2E8F0' width='106' height='144'/%3E%3C/svg%3E"
293
+ alt="Thumbnail" class="w-full h-full object-cover" />
294
+ <div class="absolute top-2 left-2 w-6 h-6 bg-black rounded-lg flex items-center justify-center">
295
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="white">
296
+ <path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 0 1-2.88 2.5 2.89 2.89 0 0 1-2.89-2.89 2.89 2.89 0 0 1 2.89-2.89c.28 0 .54.04.79.1V9.01a6.33 6.33 0 0 0-.79-.05 6.34 6.34 0 0 0-6.34 6.34 6.34 6.34 0 0 0 6.34 6.34 6.34 6.34 0 0 0 6.33-6.34V8.95a8.2 8.2 0 0 0 4.8 1.54V7.04a4.85 4.85 0 0 1-1.03-.35z"/>
297
+ </svg>
298
+ </div>
299
+ <div id="videoDuration" class="absolute bottom-2 right-2 bg-black/75 text-white text-[11px] font-bold px-1.5 py-0.5 rounded-md">00:00</div>
300
+ </div>
301
+
302
+ <!-- info -->
303
+ <div class="flex flex-col justify-between flex-1 min-w-0 py-0.5">
304
+ <div>
305
+ <p id="videoTitle" class="text-[13px] font-bold text-[#0B132B] leading-snug line-clamp-3 mb-2">β€”</p>
306
+ <div class="flex items-center gap-1.5">
307
+ <div class="w-6 h-6 rounded-full bg-gradient-to-br from-pink-400 to-purple-500 flex items-center justify-center flex-shrink-0">
308
+ <svg class="w-3 h-3 text-white" fill="currentColor" viewBox="0 0 20 20">
309
+ <path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd"/>
310
+ </svg>
311
+ </div>
312
+ <span id="authorHandle" class="text-[12px] font-semibold text-slate-700">@β€”</span>
313
+ <svg class="w-4 h-4 text-sky-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
314
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
315
+ </svg>
316
+ </div>
317
+ </div>
318
+ <div class="flex items-center gap-3 mt-2">
319
+ <div class="flex items-center gap-1 text-slate-500">
320
+ <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
321
+ <path stroke-linecap="round" stroke-linejoin="round" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/>
322
+ <path stroke-linecap="round" stroke-linejoin="round" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
323
+ </svg>
324
+ <span id="statViews" class="text-[12px] font-semibold">β€”</span>
325
+ </div>
326
+ <div class="flex items-center gap-1 text-slate-500">
327
+ <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
328
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
329
+ </svg>
330
+ <span id="statLikes" class="text-[12px] font-semibold">β€”</span>
331
+ </div>
332
+ <div class="flex items-center gap-1 text-slate-500">
333
+ <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
334
+ <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"/>
335
+ </svg>
336
+ <span id="statComments" class="text-[12px] font-semibold">β€”</span>
337
+ </div>
338
+ </div>
339
+ </div>
340
+ </div>
341
+ </div>
342
+
343
+ <!-- ── RESOLUTION OPTIONS (the big update) ── -->
344
+ <div class="px-4 pb-5">
345
+ <div class="flex items-center gap-2 mb-3">
346
+ <svg class="w-4 h-4 text-indigo-500" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
347
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
348
+ </svg>
349
+ <span class="text-[13px] font-bold text-[#0B132B]">Select Format & Download</span>
350
+ </div>
351
+
352
+ <div id="resolutionList" class="flex flex-col gap-2.5">
353
+ <!-- rows injected by JS -->
354
+ </div>
355
  </div>
356
+
357
+ <!-- preview button -->
358
+ <div class="px-4 pb-4">
359
+ <button id="previewBtn" class="w-full border-2 border-slate-200 hover:border-indigo-300 text-slate-700 font-semibold text-[14px] py-3 rounded-2xl transition-colors flex items-center justify-center gap-2">
360
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
361
+ <path stroke-linecap="round" stroke-linejoin="round" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/>
362
+ <path stroke-linecap="round" stroke-linejoin="round" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
363
+ </svg>
364
+ Preview Video
365
+ </button>
366
  </div>
367
+
368
  </div>
369
  </section>
370
 
371
+ <!-- ── FEATURE CARDS ── -->
372
+ <section id="features">
373
+ <h2 class="text-[17px] font-bold text-[#0B132B] mb-3">Why TikTokSaver PRO?</h2>
374
+ <div class="grid grid-cols-2 gap-3">
375
+ <div class="feature-card bg-white rounded-2xl border border-slate-100 shadow-sm p-4">
376
+ <div class="icon-bg-red w-11 h-11 rounded-2xl flex items-center justify-center mb-3">
377
+ <svg width="22" height="22" fill="none" stroke="#EF4444" stroke-width="2" viewBox="0 0 24 24">
378
+ <path stroke-linecap="round" stroke-linejoin="round" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"/>
379
+ </svg>
380
+ </div>
381
+ <h3 class="text-[14px] font-bold text-[#0B132B] mb-1">No Watermark</h3>
382
+ <p class="text-[12px] text-slate-500 leading-relaxed">Download videos without any watermark.</p>
383
  </div>
384
+ <div class="feature-card bg-white rounded-2xl border border-slate-100 shadow-sm p-4">
385
+ <div class="icon-bg-indigo w-11 h-11 rounded-2xl flex items-center justify-center mb-3">
386
+ <svg width="22" height="22" fill="none" stroke="#6366F1" stroke-width="2" viewBox="0 0 24 24">
387
+ <rect x="2" y="3" width="20" height="14" rx="2"/><path stroke-linecap="round" d="M8 21h8m-4-4v4"/>
388
+ </svg>
389
+ </div>
390
+ <h3 class="text-[14px] font-bold text-[#0B132B] mb-1">HD Quality</h3>
391
+ <p class="text-[12px] text-slate-500 leading-relaxed">Save videos in HD quality up to 1080p.</p>
392
  </div>
393
+ <div class="feature-card bg-white rounded-2xl border border-slate-100 shadow-sm p-4">
394
+ <div class="icon-bg-sky w-11 h-11 rounded-2xl flex items-center justify-center mb-3">
395
+ <svg width="22" height="22" fill="none" stroke="#0EA5E9" stroke-width="2" viewBox="0 0 24 24">
396
+ <path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z"/>
397
+ </svg>
398
+ </div>
399
+ <h3 class="text-[14px] font-bold text-[#0B132B] mb-1">Super Fast</h3>
400
+ <p class="text-[12px] text-slate-500 leading-relaxed">Lightning fast download servers worldwide.</p>
401
  </div>
402
+ <div class="feature-card bg-white rounded-2xl border border-slate-100 shadow-sm p-4">
403
+ <div class="icon-bg-green w-11 h-11 rounded-2xl flex items-center justify-center mb-3">
404
+ <svg width="22" height="22" fill="none" stroke="#10B981" stroke-width="2" viewBox="0 0 24 24">
405
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>
406
+ </svg>
407
+ </div>
408
+ <h3 class="text-[14px] font-bold text-[#0B132B] mb-1">100% Safe</h3>
409
+ <p class="text-[12px] text-slate-500 leading-relaxed">Secure and private. Your data is always safe.</p>
410
  </div>
411
  </div>
412
  </section>
413
 
414
+ <!-- ── HOW TO USE ── -->
415
+ <section id="howto">
416
+ <h2 class="text-[17px] font-bold text-[#0B132B] mb-3">How to Download TikTok Videos</h2>
417
+ <div class="bg-white rounded-3xl border border-slate-100 shadow-sm overflow-hidden">
418
+ <div class="flex gap-4 px-5 py-4 border-b border-slate-50">
419
+ <div class="w-9 h-9 brand-gradient rounded-full flex items-center justify-center flex-shrink-0 shadow-md shadow-pink-100"><span class="text-white text-[13px] font-bold">1</span></div>
420
+ <div><h4 class="text-[14px] font-bold text-[#0B132B] mb-0.5">Copy TikTok Video URL</h4><p class="text-[12px] text-slate-500">Open TikTok β†’ tap <strong>Share</strong> β†’ tap <strong>Copy Link</strong>.</p></div>
421
+ </div>
422
+ <div class="flex gap-4 px-5 py-4 border-b border-slate-50">
423
+ <div class="w-9 h-9 brand-gradient rounded-full flex items-center justify-center flex-shrink-0 shadow-md shadow-pink-100"><span class="text-white text-[13px] font-bold">2</span></div>
424
+ <div><h4 class="text-[14px] font-bold text-[#0B132B] mb-0.5">Paste the URL Above</h4><p class="text-[12px] text-slate-500">Tap <strong>Paste</strong> or press Ctrl+V in the input field. It auto-fetches instantly.</p></div>
425
+ </div>
426
+ <div class="flex gap-4 px-5 py-4 border-b border-slate-50">
427
+ <div class="w-9 h-9 brand-gradient rounded-full flex items-center justify-center flex-shrink-0 shadow-md shadow-pink-100"><span class="text-white text-[13px] font-bold">3</span></div>
428
+ <div><h4 class="text-[14px] font-bold text-[#0B132B] mb-0.5">Choose Your Format</h4><p class="text-[12px] text-slate-500">Select from No Watermark, HD 1080p, or Audio MP3 options.</p></div>
429
+ </div>
430
+ <div class="flex gap-4 px-5 py-4">
431
+ <div class="w-9 h-9 brand-gradient rounded-full flex items-center justify-center flex-shrink-0 shadow-md shadow-pink-100"><span class="text-white text-[13px] font-bold">4</span></div>
432
+ <div><h4 class="text-[14px] font-bold text-[#0B132B] mb-0.5">Click Download</h4><p class="text-[12px] text-slate-500">Tap the <strong>Download</strong> button β€” file saves to your device instantly.</p></div>
433
+ </div>
434
  </div>
435
  </section>
436
 
437
+ <!-- ── PRO BANNER ── -->
438
+ <section id="pro">
439
+ <div class="pro-banner rounded-3xl overflow-hidden p-5 relative">
440
+ <div class="absolute top-0 right-0 bg-pink-500 text-white text-[11px] font-black px-4 py-1.5 tracking-wider"
441
+ style="clip-path: polygon(0 0, 100% 0, 100% 100%, 8px 100%);">PRO</div>
442
+ <div class="flex gap-4 items-start">
443
+ <div class="flex-shrink-0 w-16 h-16 bg-gradient-to-br from-indigo-600 to-purple-700 rounded-2xl flex items-center justify-center shadow-lg shadow-purple-300/50"
444
+ style="clip-path: polygon(30% 0%,70% 0%,100% 30%,100% 70%,70% 100%,30% 100%,0% 70%,0% 30%);">
445
+ <svg width="30" height="30" viewBox="0 0 24 24" fill="none">
446
+ <path d="M5 16L3 5l5.5 5L12 4l3.5 6L21 5l-2 11H5zm0 0h14" stroke="#FFD700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
447
+ <path d="M5 19h14" stroke="#FFD700" stroke-width="2" stroke-linecap="round"/>
448
+ </svg>
449
+ </div>
450
+ <div class="flex-1 min-w-0 pt-1">
451
+ <div class="flex items-baseline gap-1 flex-wrap">
452
+ <h3 class="text-[16px] font-black text-[#0B132B]">Upgrade to TikTok</h3>
453
+ <span class="text-[16px] font-black brand-gradient-text">Saver PRO</span>
454
+ </div>
455
+ <p class="text-[12px] text-slate-600 leading-relaxed mt-1">Unlock 4K quality, batch download, audio download &amp; more premium features.</p>
456
+ </div>
457
  </div>
458
+ <div class="mt-4 grid grid-cols-2 gap-y-2 gap-x-3">
459
+ <div class="flex items-center gap-2"><svg class="w-4 h-4 text-purple-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg><span class="text-[12px] text-slate-700 font-medium">4K Quality</span></div>
460
+ <div class="flex items-center gap-2"><svg class="w-4 h-4 text-purple-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg><span class="text-[12px] text-slate-700 font-medium">Batch Download</span></div>
461
+ <div class="flex items-center gap-2"><svg class="w-4 h-4 text-purple-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg><span class="text-[12px] text-slate-700 font-medium">Audio MP3</span></div>
462
+ <div class="flex items-center gap-2"><svg class="w-4 h-4 text-purple-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg><span class="text-[12px] text-slate-700 font-medium">No Ads</span></div>
463
+ <div class="flex items-center gap-2"><svg class="w-4 h-4 text-purple-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg><span class="text-[12px] text-slate-700 font-medium">Unlimited Speed</span></div>
464
+ <div class="flex items-center gap-2"><svg class="w-4 h-4 text-purple-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg><span class="text-[12px] text-slate-700 font-medium">Priority Support</span></div>
465
  </div>
466
+ <button class="btn-download w-full text-white font-bold text-[14px] py-3.5 rounded-2xl mt-4 flex items-center justify-center gap-2">
467
+ <svg class="w-4 h-4" fill="none" stroke="white" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M5 3l14 9-14 9V3z"/></svg>
468
+ Get TikTokSaver PRO
469
+ <svg class="w-4 h-4" fill="none" stroke="white" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/></svg>
470
+ </button>
471
  </div>
 
 
 
 
472
  </section>
473
 
474
+ <!-- ── FAQ ── -->
475
+ <section id="faq">
476
+ <h2 class="text-[17px] font-bold text-[#0B132B] mb-3">Frequently Asked Questions</h2>
477
+ <div class="bg-white rounded-3xl border border-slate-100 shadow-sm overflow-hidden divide-y divide-slate-50">
478
+ <div class="faq-item">
479
+ <button class="faq-toggle w-full flex items-center justify-between px-5 py-4 text-left" data-faq="faq1">
480
+ <span class="text-[13px] font-semibold text-[#0B132B] pr-3">Is TikTokSaver PRO really free?</span>
481
+ <svg class="faq-arrow w-5 h-5 text-slate-400 flex-shrink-0" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/></svg>
482
+ </button>
483
+ <div id="faq1" class="faq-answer px-5"><p class="text-[13px] text-slate-500 leading-relaxed">Yes! Basic features including no-watermark download are completely free. Upgrade to PRO for 4K, batch downloads, and more.</p></div>
484
+ </div>
485
+ <div class="faq-item">
486
+ <button class="faq-toggle w-full flex items-center justify-between px-5 py-4 text-left" data-faq="faq2">
487
+ <span class="text-[13px] font-semibold text-[#0B132B] pr-3">Does it work on iPhone and Android?</span>
488
+ <svg class="faq-arrow w-5 h-5 text-slate-400 flex-shrink-0" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/></svg>
489
+ </button>
490
+ <div id="faq2" class="faq-answer px-5"><p class="text-[13px] text-slate-500 leading-relaxed">Yes! TikTokSaver PRO is a web-based tool that works on all devices β€” iPhone, Android, Windows, Mac β€” with no app required.</p></div>
491
+ </div>
492
+ <div class="faq-item">
493
+ <button class="faq-toggle w-full flex items-center justify-between px-5 py-4 text-left" data-faq="faq3">
494
+ <span class="text-[13px] font-semibold text-[#0B132B] pr-3">Why does the download button not open a new tab?</span>
495
+ <svg class="faq-arrow w-5 h-5 text-slate-400 flex-shrink-0" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/></svg>
496
+ </button>
497
+ <div id="faq3" class="faq-answer px-5"><p class="text-[13px] text-slate-500 leading-relaxed">We use a direct forced download method β€” clicking Download immediately saves the file to your device instead of opening a new browser tab.</p></div>
498
+ </div>
499
+ <div class="faq-item">
500
+ <button class="faq-toggle w-full flex items-center justify-between px-5 py-4 text-left" data-faq="faq4">
501
+ <span class="text-[13px] font-semibold text-[#0B132B] pr-3">Is it safe? Do you store my data?</span>
502
+ <svg class="faq-arrow w-5 h-5 text-slate-400 flex-shrink-0" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/></svg>
503
+ </button>
504
+ <div id="faq4" class="faq-answer px-5"><p class="text-[13px] text-slate-500 leading-relaxed">Absolutely. We do not store any video data or personal information. Downloads are processed in real-time only.</p></div>
505
+ </div>
506
+ <div class="faq-item">
507
+ <button class="faq-toggle w-full flex items-center justify-between px-5 py-4 text-left" data-faq="faq5">
508
+ <span class="text-[13px] font-semibold text-[#0B132B] pr-3">Can I download TikTok audio (MP3)?</span>
509
+ <svg class="faq-arrow w-5 h-5 text-slate-400 flex-shrink-0" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/></svg>
510
+ </button>
511
+ <div id="faq5" class="faq-answer px-5"><p class="text-[13px] text-slate-500 leading-relaxed">Yes! After fetching, click the Audio MP3 download button in the format list to save just the audio track β€” completely free.</p></div>
512
  </div>
513
  </div>
514
  </section>
515
 
516
+ <!-- ── TRUST METRICS ── -->
517
+ <section>
518
+ <div class="bg-white rounded-3xl border border-slate-100 shadow-sm p-5">
519
+ <h2 class="text-center text-[13px] font-semibold text-slate-400 mb-4 uppercase tracking-widest">Trusted by Millions</h2>
520
+ <div class="grid grid-cols-4 gap-2">
521
+ <div class="flex flex-col items-center gap-1.5 text-center">
522
+ <div class="icon-bg-indigo w-10 h-10 rounded-xl flex items-center justify-center">
523
+ <svg class="w-5 h-5 text-indigo-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/></svg>
524
+ </div>
525
+ <p class="text-[15px] font-black text-[#0B132B] leading-none">50M+</p>
526
+ <p class="text-[10px] text-slate-500 leading-snug">Videos Downloaded</p>
527
  </div>
528
+ <div class="flex flex-col items-center gap-1.5 text-center">
529
+ <div class="icon-bg-green w-10 h-10 rounded-xl flex items-center justify-center">
530
+ <svg class="w-5 h-5 text-emerald-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M14.828 14.828a4 4 0 01-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
 
 
 
531
  </div>
532
+ <p class="text-[15px] font-black text-[#0B132B] leading-none">10M+</p>
533
+ <p class="text-[10px] text-slate-500 leading-snug">Happy Users</p>
534
+ </div>
535
+ <div class="flex flex-col items-center gap-1.5 text-center">
536
+ <div class="icon-bg-red w-10 h-10 rounded-xl flex items-center justify-center">
537
+ <svg class="w-5 h-5 text-rose-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/></svg>
538
+ </div>
539
+ <p class="text-[15px] font-black text-[#0B132B] leading-none">99.9%</p>
540
+ <p class="text-[10px] text-slate-500 leading-snug">Uptime Guarantee</p>
541
+ </div>
542
+ <div class="flex flex-col items-center gap-1.5 text-center">
543
+ <div class="w-10 h-10 rounded-xl flex items-center justify-center" style="background:rgba(234,179,8,0.12);">
544
+ <svg class="w-5 h-5 text-yellow-500" fill="currentColor" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg>
545
  </div>
546
+ <p class="text-[15px] font-black text-[#0B132B] leading-none">4.9/5</p>
547
+ <p class="text-[10px] text-slate-500 leading-snug">User Rating</p>
548
  </div>
549
  </div>
 
 
 
550
  </div>
551
  </section>
552
 
553
+ <!-- ── FOOTER ── -->
554
+ <footer class="pt-4 pb-8">
555
+ <div class="flex items-center justify-center gap-2 mb-4">
556
+ <svg class="w-3.5 h-3.5 text-slate-400" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"/></svg>
557
+ <span class="text-[12px] text-slate-400">We respect your privacy. No data is stored.</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
558
  </div>
559
+ <div class="flex items-center justify-center gap-5 mb-4">
560
+ <a href="#" class="text-[12px] text-slate-400 hover:text-slate-600 transition-colors">Privacy Policy</a>
561
+ <span class="text-slate-200">β€’</span>
562
+ <a href="#" class="text-[12px] text-slate-400 hover:text-slate-600 transition-colors">Terms of Service</a>
563
+ <span class="text-slate-200">β€’</span>
564
+ <a href="#" class="text-[12px] text-slate-400 hover:text-slate-600 transition-colors">Contact</a>
 
565
  </div>
566
+ <p class="text-center text-[11px] text-slate-300">
567
+ Β© 2024 TikTokSaver PRO. All rights reserved.<br />
568
+ <span class="text-[10px]">Not affiliated with TikTok or ByteDance Ltd.</span>
569
+ </p>
570
  </footer>
571
 
572
+ </main>
573
+
574
+ <!-- ── PREVIEW MODAL ── -->
575
+ <div id="previewModal" class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/70 backdrop-blur-sm hidden">
576
+ <div class="bg-white rounded-3xl overflow-hidden w-full max-w-sm shadow-2xl">
577
+ <div class="flex items-center justify-between px-5 py-4 border-b border-slate-100">
578
+ <span class="font-bold text-[15px] text-[#0B132B]">Video Preview</span>
579
+ <button id="closeModal" class="w-8 h-8 rounded-full bg-slate-100 flex items-center justify-center text-slate-500 hover:bg-slate-200 transition-colors">
580
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg>
581
+ </button>
582
+ </div>
583
+ <div class="p-4">
584
+ <video id="previewVideo" controls class="w-full rounded-2xl bg-black" style="max-height:420px;"></video>
585
+ </div>
586
+ </div>
587
  </div>
588
+
589
+ <!-- ════════════════════════════════════════════════════════════
590
+ JAVASCRIPT – UPDATED: Instant fetch + direct downloads
591
+ ════════════════════════════════════════════════════════════ -->
592
+ <script>
593
+ (() => {
594
+ 'use strict';
595
+
596
+ /* ─── state ──────────────────────────────────────────────── */
597
+ let videoData = null;
598
+ let isFetching = false;
599
+
600
+ /* ─── DOM refs ───────────────────────────────────────────── */
601
+ const urlInput = document.getElementById('urlInput');
602
+ const downloadBtn = document.getElementById('downloadBtn');
603
+ const downloadBtnIcon = document.getElementById('downloadBtnIcon');
604
+ const downloadBtnText = document.getElementById('downloadBtnText');
605
+ const pasteBtn = document.getElementById('pasteBtn');
606
+ const resultSection = document.getElementById('resultSection');
607
+ const clearResult = document.getElementById('clearResult');
608
+ const errorMsg = document.getElementById('errorMsg');
609
+ const errorText = document.getElementById('errorText');
610
+ const resolutionList = document.getElementById('resolutionList');
611
+
612
+ // result card
613
+ const videoThumb = document.getElementById('videoThumb');
614
+ const videoTitle = document.getElementById('videoTitle');
615
+ const authorHandle = document.getElementById('authorHandle');
616
+ const videoDuration = document.getElementById('videoDuration');
617
+ const statViews = document.getElementById('statViews');
618
+ const statLikes = document.getElementById('statLikes');
619
+ const statComments = document.getElementById('statComments');
620
+
621
+ // preview
622
+ const previewBtn = document.getElementById('previewBtn');
623
+ const previewModal = document.getElementById('previewModal');
624
+ const previewVideo = document.getElementById('previewVideo');
625
+ const closeModal = document.getElementById('closeModal');
626
+
627
+ // nav
628
+ const menuToggle = document.getElementById('menuToggle');
629
+ const mobileMenu = document.getElementById('mobileMenu');
630
+
631
+ /* ─── helpers ────────────────────────────────────────────── */
632
+ const isValidUrl = url =>
633
+ /^https?:\/\/(www\.|vm\.|vt\.|m\.)?tiktok\.com\/.+/i.test(url.trim());
634
+
635
+ const fmt = n => {
636
+ const v = parseInt(n, 10);
637
+ if (!v) return '0';
638
+ if (v >= 1e6) return (v / 1e6).toFixed(1).replace(/\.0$/, '') + 'M';
639
+ if (v >= 1e3) return (v / 1e3).toFixed(1).replace(/\.0$/, '') + 'K';
640
+ return String(v);
641
+ };
642
+
643
+ const fmtDur = s => {
644
+ const t = parseInt(s, 10) || 0;
645
+ return `${String(Math.floor(t / 60)).padStart(2,'0')}:${String(t % 60).padStart(2,'0')}`;
646
+ };
647
+
648
+ /* toast */
649
+ let toastTimer;
650
+ const showToast = (msg, ms = 2800) => {
651
+ const el = document.getElementById('toast');
652
+ el.textContent = msg;
653
+ el.classList.add('show');
654
+ clearTimeout(toastTimer);
655
+ toastTimer = setTimeout(() => el.classList.remove('show'), ms);
656
+ };
657
+
658
+ /* error bar */
659
+ const showError = msg => {
660
+ errorText.textContent = msg;
661
+ errorMsg.classList.remove('hidden');
662
+ errorMsg.classList.add('flex');
663
+ };
664
+ const hideError = () => {
665
+ errorMsg.classList.add('hidden');
666
+ errorMsg.classList.remove('flex');
667
+ };
668
+
669
+ /* spinner SVG string */
670
+ const SPINNER_SVG = `
671
+ <span class="spinner">
672
+ <svg class="w-5 h-5 text-white" fill="none" viewBox="0 0 24 24">
673
+ <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="3" opacity="0.25"/>
674
+ <path fill="currentColor" opacity="0.8" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/>
675
+ </svg>
676
+ </span>`;
677
+
678
+ const DL_SVG = `
679
+ <svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
680
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
681
+ </svg>`;
682
+
683
+ /* loading state */
684
+ const setLoading = on => {
685
+ isFetching = on;
686
+ downloadBtn.disabled = on;
687
+ downloadBtn.style.opacity = on ? '0.80' : '1';
688
+ downloadBtnIcon.innerHTML = on ? SPINNER_SVG : DL_SVG;
689
+ downloadBtnText.textContent = on ? 'Fetching…' : 'Download';
690
+ };
691
+
692
+ /* ─── FORCE DOWNLOAD (no new tab!) ─────────────────────── */
693
+ /*
694
+ * Strategy:
695
+ * 1. Try fetch() β†’ blob β†’ object URL β†’ <a download>.click()
696
+ * (works for same-origin or CORS-permissive servers)
697
+ * 2. If fetch fails or CORS blocks, fall back to
698
+ * <a href=url download>.click()
699
+ * (browser may still save depending on Content-Disposition)
700
+ */
701
+ const forceDownload = async (url, filename) => {
702
+ if (!url) { showToast('⚠️ No download link available.'); return; }
703
+
704
+ // Try blob approach first
705
+ try {
706
+ const resp = await fetch(url, { mode: 'cors' });
707
+ if (resp.ok) {
708
+ const blob = await resp.blob();
709
+ const blobUrl = URL.createObjectURL(blob);
710
+ const a = document.createElement('a');
711
+ a.href = blobUrl;
712
+ a.download = filename;
713
+ a.style.display = 'none';
714
+ document.body.appendChild(a);
715
+ a.click();
716
+ document.body.removeChild(a);
717
+ setTimeout(() => URL.revokeObjectURL(blobUrl), 10000);
718
+ showToast('⬇️ Download started!');
719
+ return;
720
+ }
721
+ } catch (_) { /* CORS blocked – fall through */ }
722
+
723
+ // Fallback: direct anchor with download attribute
724
+ const a = document.createElement('a');
725
+ a.href = url;
726
+ a.download = filename;
727
+ a.target = '_self'; // stay on same page
728
+ a.rel = 'noopener noreferrer';
729
+ a.style.display = 'none';
730
+ document.body.appendChild(a);
731
+ a.click();
732
+ document.body.removeChild(a);
733
+ showToast('⬇️ Download started!');
734
+ };
735
+
736
+ /* ─── BUILD RESOLUTION LIST ──────────────────────────────── */
737
+ /*
738
+ * Defines all available format rows. Each entry:
739
+ * id – unique key
740
+ * label – display name
741
+ * tag – badge text
742
+ * tagColor – Tailwind bg / text classes for the badge
743
+ * icon – emoji prefix
744
+ * getUrl – function(data) β†’ download URL or null
745
+ * ext – file extension
746
+ * size – optional file size hint from data
747
+ */
748
+ const FORMAT_DEFS = [
749
+ {
750
+ id: 'nowm',
751
+ label: 'MP4 – No Watermark',
752
+ tag: 'FREE',
753
+ tagColor: 'bg-emerald-100 text-emerald-700',
754
+ icon: '🎬',
755
+ getUrl: d => d.play || null,
756
+ ext: 'mp4',
757
+ },
758
+ {
759
+ id: 'hd',
760
+ label: 'MP4 – HD 1080p',
761
+ tag: 'HD',
762
+ tagColor: 'bg-indigo-100 text-indigo-700',
763
+ icon: 'πŸ”Ή',
764
+ getUrl: d => d.hdplay || d.play || null,
765
+ ext: 'mp4',
766
+ },
767
+ {
768
+ id: 'wm',
769
+ label: 'MP4 – With Watermark',
770
+ tag: 'ORIGINAL',
771
+ tagColor: 'bg-slate-100 text-slate-600',
772
+ icon: 'πŸŽ₯',
773
+ getUrl: d => d.wmplay || d.play || null,
774
+ ext: 'mp4',
775
+ },
776
+ {
777
+ id: 'audio',
778
+ label: 'MP3 – Audio Only',
779
+ tag: 'AUDIO',
780
+ tagColor: 'bg-purple-100 text-purple-700',
781
+ icon: '🎡',
782
+ getUrl: d => d.music || null,
783
+ ext: 'mp3',
784
+ },
785
+ ];
786
+
787
+ const buildResolutionList = data => {
788
+ resolutionList.innerHTML = '';
789
+
790
+ FORMAT_DEFS.forEach(fmt_def => {
791
+ const dlUrl = fmt_def.getUrl(data);
792
+
793
+ const card = document.createElement('div');
794
+ card.className = 'res-card';
795
+
796
+ // left info
797
+ const info = document.createElement('div');
798
+ info.className = 'flex flex-col gap-1 min-w-0';
799
+
800
+ const titleRow = document.createElement('div');
801
+ titleRow.className = 'flex items-center gap-2 flex-wrap';
802
+
803
+ const labelEl = document.createElement('span');
804
+ labelEl.className = 'text-[13px] font-bold text-[#0B132B] whitespace-nowrap';
805
+ labelEl.textContent = fmt_def.icon + ' ' + fmt_def.label;
806
+
807
+ const badge = document.createElement('span');
808
+ badge.className = `res-badge ${fmt_def.tagColor}`;
809
+ badge.textContent = fmt_def.tag;
810
+
811
+ titleRow.appendChild(labelEl);
812
+ titleRow.appendChild(badge);
813
+
814
+ const sub = document.createElement('span');
815
+ sub.className = 'text-[11px] text-slate-400';
816
+ sub.textContent = dlUrl ? 'Ready to download' : 'Not available for this video';
817
+
818
+ info.appendChild(titleRow);
819
+ info.appendChild(sub);
820
+
821
+ // right: download button
822
+ const btn = document.createElement('button');
823
+ btn.className = 'res-dl-btn';
824
+ btn.id = 'dl_' + fmt_def.id;
825
+
826
+ if (!dlUrl) {
827
+ btn.disabled = true;
828
+ btn.style.background = '#E2E8F0';
829
+ btn.style.color = '#94A3B8';
830
+ btn.style.cursor = 'not-allowed';
831
+ btn.innerHTML = `
832
+ <svg width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
833
+ <path stroke-linecap="round" stroke-linejoin="round" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728L5.636 5.636"/>
834
+ </svg>
835
+ N/A`;
836
+ } else {
837
+ btn.innerHTML = `
838
+ <svg width="14" height="14" fill="none" stroke="white" stroke-width="2.5" viewBox="0 0 24 24">
839
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
840
+ </svg>
841
+ Download`;
842
+
843
+ /* ── CLICK: instant forced download, no new tab ──── */
844
+ btn.addEventListener('click', async () => {
845
+ // visual feedback: spinner on this button only
846
+ const orig = btn.innerHTML;
847
+ btn.innerHTML = `<span class="spinner"><svg class="w-4 h-4 text-white" fill="none" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="3" opacity="0.25"/><path fill="currentColor" opacity="0.8" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/></svg></span> Saving…`;
848
+ btn.classList.add('loading');
849
+
850
+ const author = data.author?.unique_id || 'tiktok';
851
+ const filename = `${author}_${fmt_def.id}_${Date.now()}.${fmt_def.ext}`;
852
+
853
+ await forceDownload(dlUrl, filename);
854
+
855
+ btn.innerHTML = orig;
856
+ btn.classList.remove('loading');
857
+ });
858
+ }
859
+
860
+ card.appendChild(info);
861
+ card.appendChild(btn);
862
+ resolutionList.appendChild(card);
863
+ });
864
+ };
865
+
866
+ /* ─── POPULATE RESULT CARD ───────────────────────────────── */
867
+ const populateResult = data => {
868
+ videoData = data;
869
+
870
+ if (data.cover || data.origin_cover) {
871
+ videoThumb.src = data.cover || data.origin_cover;
872
+ }
873
+ videoTitle.textContent = data.title || 'TikTok Video';
874
+ authorHandle.textContent = '@' + (data.author?.unique_id || data.author?.nickname || 'unknown');
875
+ videoDuration.textContent = fmtDur(data.duration);
876
+ statViews.textContent = fmt(data.play_count || data.views || 0);
877
+ statLikes.textContent = fmt(data.digg_count || data.likes || 0);
878
+ statComments.textContent = fmt(data.comment_count|| data.comments || 0);
879
+
880
+ buildResolutionList(data);
881
+ };
882
+
883
+ const showResult = () => {
884
+ resultSection.classList.add('visible');
885
+ setTimeout(() => resultSection.scrollIntoView({ behavior: 'smooth', block: 'nearest' }), 120);
886
+ };
887
+
888
+ const hideResult = () => {
889
+ resultSection.classList.remove('visible');
890
+ videoData = null;
891
+ resolutionList.innerHTML = '';
892
+ };
893
+
894
+ /* ─── MAIN FETCH (optimised for speed) ─────────────────── */
895
+ /*
896
+ * Speed optimisations applied:
897
+ * β€’ AbortController with 12 s timeout – avoids hanging forever
898
+ * β€’ API called with ?hd=1 to get HD link in one shot
899
+ * β€’ No artificial progress bar delay
900
+ * β€’ Result rendered immediately on JSON parse
901
+ */
902
+ const fetchVideo = async rawUrl => {
903
+ const url = rawUrl.trim();
904
+ hideError();
905
+
906
+ if (!url) { showError('Please paste a TikTok video URL first.'); urlInput.focus(); return; }
907
+ if (!isValidUrl(url)) { showError('Invalid TikTok URL. Copy a valid link from the TikTok app.'); return; }
908
+
909
+ setLoading(true);
910
+ hideResult();
911
+
912
+ const controller = new AbortController();
913
+ const timeout = setTimeout(() => controller.abort(), 12000);
914
+
915
+ try {
916
+ const endpoint =
917
+ `https://tikwm.com/api/?url=${encodeURIComponent(url)}&hd=1`;
918
+
919
+ const resp = await fetch(endpoint, {
920
+ method: 'GET',
921
+ headers: { 'Accept': 'application/json' },
922
+ signal: controller.signal,
923
+ });
924
+
925
+ clearTimeout(timeout);
926
+
927
+ if (!resp.ok) throw new Error(`Server error ${resp.status}`);
928
+
929
+ const json = await resp.json();
930
+
931
+ if (json.code !== 0 || !json.data) {
932
+ throw new Error(json.msg || 'Could not fetch video. Check the URL and try again.');
933
+ }
934
+
935
+ populateResult(json.data);
936
+ showResult();
937
+ showToast('βœ“ Video found! Choose your format below.');
938
+
939
+ } catch (err) {
940
+ clearTimeout(timeout);
941
+ let msg = err.message || 'Something went wrong. Please try again.';
942
+ if (err.name === 'AbortError') msg = 'Request timed out. Check your internet and try again.';
943
+ else if (/fetch|network/i.test(msg)) msg = 'Network error. Check your internet connection.';
944
+ showError(msg);
945
+ } finally {
946
+ setLoading(false);
947
+ }
948
+ };
949
+
950
+ /* ─── EVENT LISTENERS ────────────────────────────────────── */
951
+
952
+ // Main download button
953
+ downloadBtn.addEventListener('click', () => {
954
+ if (!isFetching) fetchVideo(urlInput.value);
955
+ });
956
+
957
+ // Enter key in input
958
+ urlInput.addEventListener('keydown', e => {
959
+ if (e.key === 'Enter' && !isFetching) fetchVideo(urlInput.value);
960
+ });
961
+
962
+ // Auto-fetch on paste (instant feel)
963
+ urlInput.addEventListener('paste', () => {
964
+ setTimeout(() => {
965
+ const v = urlInput.value.trim();
966
+ if (isValidUrl(v) && !isFetching) fetchVideo(v);
967
+ }, 60);
968
+ });
969
+
970
+ // Paste button
971
+ pasteBtn.addEventListener('click', async () => {
972
+ try {
973
+ if (navigator.clipboard?.readText) {
974
+ const txt = await navigator.clipboard.readText();
975
+ urlInput.value = txt;
976
+ urlInput.focus();
977
+ showToast('πŸ“‹ Pasted!');
978
+ if (isValidUrl(txt) && !isFetching) fetchVideo(txt);
979
+ } else {
980
+ urlInput.focus();
981
+ showToast('Tap input and press Ctrl+V / Cmd+V');
982
+ }
983
+ } catch {
984
+ urlInput.focus();
985
+ showToast('Tap input and paste manually');
986
+ }
987
+ });
988
+
989
+ // Clear result
990
+ clearResult.addEventListener('click', () => {
991
+ hideResult(); hideError();
992
+ urlInput.value = ''; urlInput.focus();
993
+ });
994
+
995
+ // Preview button
996
+ previewBtn.addEventListener('click', () => {
997
+ if (!videoData) return;
998
+ const src = videoData.play || videoData.wmplay;
999
+ if (!src) { showToast('⚠️ Preview not available.'); return; }
1000
+ previewVideo.src = src;
1001
+ previewModal.classList.remove('hidden');
1002
+ });
1003
+
1004
+ // Close modal
1005
+ const closePreview = () => {
1006
+ previewModal.classList.add('hidden');
1007
+ previewVideo.pause();
1008
+ previewVideo.src = '';
1009
+ };
1010
+ closeModal.addEventListener('click', closePreview);
1011
+ previewModal.addEventListener('click', e => { if (e.target === previewModal) closePreview(); });
1012
+ document.addEventListener('keydown', e => { if (e.key === 'Escape') closePreview(); });
1013
+
1014
+ // Mobile nav
1015
+ menuToggle.addEventListener('click', () => mobileMenu.classList.toggle('open'));
1016
+ document.querySelectorAll('#mobileMenu a').forEach(a => a.addEventListener('click', () => mobileMenu.classList.remove('open')));
1017
+
1018
+ // FAQ accordion
1019
+ document.querySelectorAll('.faq-toggle').forEach(btn => {
1020
+ btn.addEventListener('click', () => {
1021
+ const id = btn.dataset.faq;
1022
+ const answer = document.getElementById(id);
1023
+ const arrow = btn.querySelector('.faq-arrow');
1024
+ const isOpen = answer.classList.contains('open');
1025
+ document.querySelectorAll('.faq-answer').forEach(a => a.classList.remove('open'));
1026
+ document.querySelectorAll('.faq-arrow').forEach(a => a.classList.remove('open'));
1027
+ if (!isOpen) { answer.classList.add('open'); arrow.classList.add('open'); }
1028
+ });
1029
+ });
1030
+
1031
+ // Smooth scroll
1032
+ document.querySelectorAll('a[href^="#"]').forEach(a => {
1033
+ a.addEventListener('click', e => {
1034
+ e.preventDefault();
1035
+ const t = document.querySelector(a.getAttribute('href'));
1036
+ if (t) t.scrollIntoView({ behavior: 'smooth', block: 'start' });
1037
+ });
1038
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1039
 
1040
+ })();
1041
+ </script>
 
 
1042
  </body>
1043
  </html>