File size: 28,507 Bytes
d60a507
 
 
 
 
68a78c2
d60a507
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68a78c2
 
d60a507
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47c2d21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Stranger Things Seasons 1-4 Watchlist</title>
    <style>
        body {
            font-family: 'Courier New', Courier, monospace;
            background-color: #000;
            color: #ff0000; /* Neon red for Stranger Things vibe */
            margin: 0;
            padding: 20px;
            overflow: auto;
        }
        h1 {
            text-align: center;
            color: #ffcc00; /* Yellow neon */
            text-shadow: 0 0 10px #ff0000;
        }
        .tabs {
            display: flex;
            justify-content: center;
            margin-bottom: 20px;
        }
        .tab-button {
            background: #222;
            border: 1px solid #ff0000;
            color: #fff;
            padding: 10px 20px;
            margin: 0 5px;
            cursor: pointer;
            transition: background 0.3s;
        }
        .tab-button:hover {
            background: #ff0000;
        }
        .tab-content {
            display: none;
        }
        .active {
            display: block;
        }
        .calendar {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 5px;
            max-width: 800px;
            margin: 0 auto;
        }
        .day {
            background: #111;
            border: 1px solid #333;
            padding: 10px;
            text-align: center;
            min-height: 100px;
            cursor: pointer;
            transition: transform 0.2s;
        }
        .day:hover {
            transform: scale(1.05);
            border-color: #ff0000;
        }
        .scheduled {
            background: #330000;
            color: #fff;
        }
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.8);
            justify-content: center;
            align-items: center;
        }
        .modal-content {
            background: #222;
            padding: 20px;
            max-width: 600px;
            border: 2px solid #ff0000;
            color: #fff;
        }
        .list-view ul {
            list-style: none;
            padding: 0;
        }
        .list-view li {
            background: #111;
            margin: 10px 0;
            padding: 10px;
            border: 1px solid #ff0000;
        }
        .progress {
            text-align: center;
        }
        .progress-bar {
            width: 80%;
            height: 20px;
            background: #333;
            margin: 20px auto;
            position: relative;
        }
        .progress-fill {
            height: 100%;
            background: linear-gradient(to right, #ff0000, #ffcc00);
            width: 0%;
            transition: width 0.5s;
        }
        #fun-fact {
            margin: 20px auto;
            padding: 10px;
            background: #440000;
            max-width: 600px;
            text-align: center;
        }
        .demogorgon {
            animation: shake 0.5s infinite;
        }
        @keyframes shake {
            0% { transform: translate(1px, 1px) rotate(0deg); }
            10% { transform: translate(-1px, -2px) rotate(-1deg); }
            20% { transform: translate(-3px, 0px) rotate(1deg); }
            30% { transform: translate(3px, 2px) rotate(0deg); }
            40% { transform: translate(1px, -1px) rotate(1deg); }
            50% { transform: translate(-1px, 2px) rotate(-1deg); }
            60% { transform: translate(-3px, 1px) rotate(0deg); }
            70% { transform: translate(3px, 1px) rotate(-1deg); }
            80% { transform: translate(-1px, -1px) rotate(1deg); }
            90% { transform: translate(1px, 2px) rotate(0deg); }
            100% { transform: translate(1px, -2px) rotate(-1deg); }
        }
    </style>
</head>
<body>
    <h1>Stranger Things Seasons 1-4 Watchlist</h1>
    <p style="text-align: center; color: #fff;">Dive into the Upside Down before November 2025. Click dates for details, and watch for Demogorgon surprises!</p>

    <div class="tabs">
        <button class="tab-button" onclick="openTab('calendar')">Calendar View</button>
        <button class="tab-button" onclick="openTab('list')">List View</button>
        <button class="tab-button" onclick="openTab('progress')">Progress Tracker</button>
        <button class="tab-button" onclick="showRandomFact()">Random Fun Fact!</button>
    </div>

    <div id="calendar" class="tab-content active">
        <!-- Calendar will be generated here -->
    </div>

    <div id="list" class="tab-content">
        <div class="list-view">
            <ul>
                <!-- List will be generated here -->
            </ul>
        </div>
    </div>

    <div id="progress" class="tab-content">
        <div class="progress">
            <h2>Your Binge Progress</h2>
            <div class="progress-bar">
                <div class="progress-fill" id="progress-fill"></div>
            </div>
            <p id="progress-text">0/34 episodes watched (0%)</p>
            <button onclick="markWatched()">Mark Next Episode as Watched</button>
            <button onclick="resetProgress()">Reset Progress</button>
        </div>
    </div>

    <div id="fun-fact" style="display: none;"></div>

    <div id="modal" class="modal" onclick="closeModal()">
        <div class="modal-content" onclick="event.stopPropagation()">
            <h2 id="modal-title"></h2>
            <p id="modal-details"></p>
        </div>
    </div>

    <script>
        // Episode Data (combined from JSON and search)
        const episodes = {
            season_1: [
                { number: 1, title: 'Chapter One: The Vanishing of Will Byers', duration: 49, synopsis: 'On his way home from a friend\'s house, young Will sees something terrifying. Nearby, a sinister secret lurks in the depths of a government lab', facts: 'Series premiere episode that establishes the central mystery and introduces the main characters' },
                { number: 2, title: 'Chapter Two: The Weirdo on Maple Street', duration: 56, synopsis: 'Lucas, Mike and Dustin try to talk to the girl they found in the woods. Meanwhile, Hopper questions an anxious Joyce about an unsettling phone call', facts: 'Introduces Eleven and begins establishing her relationship with the boys' },
                { number: 3, title: 'Chapter Three: Holly, Jolly', duration: 52, synopsis: 'An increasingly concerned Nancy looks for Barb and finds out what Jonathan\'s been up to. Joyce is convinced Will is trying to talk to her', facts: 'Marked as \'Top-rated\' episode, develops the parallel storylines of Will\'s disappearance and Barb\'s fate' },
                { number: 4, title: 'Chapter Four: The Body', duration: 51, synopsis: 'Refusing to believe Will is dead, Joyce tries to connect with her son. The boys give Eleven a makeover. Jonathan and Nancy form an unlikely alliance', facts: 'Features the iconic scene of Eleven\'s makeover and explores Joyce\'s maternal instincts' },
                { number: 5, title: 'Chapter Five: The Flea and the Acrobat', duration: 53, synopsis: 'Hopper breaks into the lab to find the truth about Will\'s death. The boys try to locate the \'gate\' that will take them to Will', facts: 'Reveals more about the government laboratory and the Upside Down portal' },
                { number: 6, title: 'Chapter Six: The Monster', duration: 47, synopsis: 'A frantic Jonathan looks for Nancy in the darkness, but Steve\'s looking for her, too. Hopper and Joyce uncover the truth about the lab\'s experiments', facts: 'Marked as \'Top-rated\' episode, features major revelations about the Demogorgon and government experiments' },
                { number: 7, title: 'Chapter Seven: The Bathtub', duration: 42, synopsis: 'The government comes searching for Eleven. Eleven looks for Will and Barb in the Upside Down', facts: 'Marked as \'Top-rated\' episode, shortest episode of the season at 42 minutes' },
                { number: 8, title: 'Chapter Eight: The Upside Down', duration: 55, synopsis: 'Joyce and Hopper are taken in for questioning. Nancy and Jonathan prepare to fight the monster and save Will', facts: 'Season finale that resolves the main mystery while setting up future storylines' }
            ],
            season_2: [
                { number: 1, title: 'Chapter One: MADMAX', synopsis: 'As the town preps for Halloween, a high-scoring rival shakes things up at the arcade, and a sceptical Hopper inspects a field of rotting pumpkins', facts: 'Introduces Max Mayfield as the new character nicknamed \'MADMAX\' after her arcade skills' },
                { number: 2, title: 'Chapter Two: Trick or Treat, Freak', synopsis: 'After Will sees something terrible on trick-or-treat night, Mike wonders whether Eleven\'s still out there. Nancy wrestles with the truth about Barb', facts: 'Halloween-themed episode that explores Will\'s continued connection to the Upside Down' },
                { number: 3, title: 'Chapter Three: The Pollywog', synopsis: 'Dustin adopts a strange new pet, and Eleven grows increasingly impatient. A well-meaning Bob urges Will to stand up to his fears', facts: 'Introduces Dart, the creature Dustin finds and adopts, not knowing its true nature' },
                { number: 4, title: 'Chapter Four: Will the Wise', synopsis: 'An ailing Will opens up to Joyce -- with disturbing results. While Hopper digs for the truth, Eleven unearths a surprising discovery', facts: 'Explores Will\'s deepening connection to the Mind Flayer and the Upside Down' },
                { number: 5, title: 'Chapter Five: Dig Dug', synopsis: 'Nancy and Jonathan swap conspiracy theories with a new ally as Eleven searches for someone from her past. \'Bob the Brain\' tackles a difficult problem', facts: 'Marked as \'Top-rated\' episode, features Bob Newby\'s problem-solving skills and Eleven\'s search for her origins' },
                { number: 6, title: 'Chapter Six: The Spy', synopsis: 'Will\'s connection to a shadowy evil grows stronger but no one\'s quite sure how to stop it. Elsewhere, Dustin and Steve forge an unlikely bond', facts: 'Develops the unlikely friendship between Steve and Dustin that becomes a fan favourite dynamic' },
                { number: 7, title: 'Chapter Seven: The Lost Sister', synopsis: 'Psychic visions draw Eleven to a band of violent outcasts and an angry girl with a shadowy past', facts: 'Marked as \'Top-rated\' episode, controversial standalone episode focusing on Eleven\'s backstory away from Hawkins' },
                { number: 8, title: 'Chapter Eight: The Mind Flayer', synopsis: 'An unlikely hero steps forward when a deadly development puts the Hawkins lab on lockdown, trapping Will and several others inside', facts: 'Marked as \'Top-rated\' episode, features significant character development and introduces the Mind Flayer concept' },
                { number: 9, title: 'Chapter Nine: The Gate', synopsis: 'Eleven makes plans to finish what she started while the survivors turn up the heat on the monstrous force that\'s holding Will hostage', facts: 'Season finale that resolves the Mind Flayer storyline and features Eleven\'s return to close the gate' }
            ],
            season_3: [
                { number: 1, title: 'Chapter One: Suzie, Do You Copy?', duration: 50, synopsis: 'Summer brings new jobs and budding romance. But the mood shifts when Dustin\'s radio picks up a Russian broadcast, and Will senses something is wrong', facts: 'Set in summer 1985, introduces the Russian storyline and the new Starcourt Mall setting' },
                { number: 2, title: 'Chapter Two: The Mall Rats', duration: 50, synopsis: 'Nancy and Jonathan follow a lead, Steve and Robin sign on to a secret mission, and Max and Eleven go shopping. A rattled Billy has troubling visions', facts: 'Develops the friendship between Max and Eleven while introducing Robin as Steve\'s coworker' },
                { number: 3, title: 'Chapter Three: The Case of the Missing Lifeguard', duration: 49, synopsis: 'With El and Max looking for Billy, Will declares a day without girls. Steve and Dustin go on a stakeout, and Joyce and Hopper return to Hawkins Lab', facts: 'Explores the changing dynamics of the group as they grow older and relationships become more complex' },
                { number: 4, title: 'Chapter Four: The Sauna Test', duration: 52, synopsis: 'A code red brings the gang back together to face a frighteningly familiar evil. Karen urges Nancy to keep digging, and Robin finds a useful map', facts: 'Features the innovative \'sauna test\' to determine if Billy is possessed by the Mind Flayer' },
                { number: 5, title: 'Chapter Five: The Flayed', duration: 52, synopsis: 'Strange surprises lurk inside an old farmhouse and deep beneath the Starcourt Mall. Meanwhile, the Mind Flayer is gathering strength', facts: 'Reveals the extent of the Mind Flayer\'s influence and the Russian operation beneath Starcourt Mall' },
                { number: 6, title: 'Chapter Six: E Pluribus Unum', duration: 59, synopsis: 'Dr. Alexei reveals what the Russians have been building, and Eleven sees where Billy has been. Dustin and Erica stage a daring rescue', facts: 'Latin title meaning \'Out of Many, One\', features significant plot revelations about the Russian operation' },
                { number: 7, title: 'Chapter Seven: The Bite', duration: 55, synopsis: 'With time running out - and an assassin close behind - Hopper\'s crew races back to Hawkins, where El and the kids are preparing for war', facts: 'Marked as \'Top-rated\' episode, builds tension towards the season finale with multiple storylines converging' },
                { number: 8, title: 'Chapter Eight: The Battle of Starcourt', duration: 77, synopsis: 'Terror reigns in the food court when the Mind Flayer comes to collect. But down below, in the dark, the future of the world is at stake', facts: 'Season finale featuring the climactic battle at Starcourt Mall and significant character developments' }
            ],
            season_4: [
                { number: 1, title: 'Chapter One: The Hellfire Club', duration: 78, synopsis: 'The Hawkins group faces new threats; Eleven struggles to regain her powers in a new setting.', facts: 'Introduces the Hellfire Club, a D&D group.' },
                { number: 2, title: 'Chapter Two: Vecna\'s Curse', duration: 77, synopsis: 'The group learns more about Vecna, the new supernatural antagonist, while Eleven continues her journey to regain strength.', facts: 'Introduces Vecna as the main villain.' },
                { number: 3, title: 'Chapter Three: The Monster and the Superhero', duration: 62, synopsis: 'Emotional connections deepen as characters confront their fears; the monster threat escalates.', facts: 'Focuses on character fears and superhero themes.' },
                { number: 4, title: 'Chapter Four: Dear Billy', duration: 75, synopsis: 'Max faces haunting memories; strategic plans form to tackle the dark forces invading Hawkins.', facts: 'Iconic episode with Kate Bush\'s \'Running Up That Hill\' revival.' },
                { number: 5, title: 'Chapter Five: The Nina Project', duration: 77, synopsis: 'Explores Eleven’s backstory through a secretive experiment, shedding light on her powers and struggles.', facts: 'Deep dive into Eleven\'s origins.' },
                { number: 6, title: 'Chapter Six: The Dive', duration: 59, synopsis: 'The Hawkins team takes a risky dive into the Upside Down; emotional stakes rise for all characters.', facts: 'Features underwater exploration in the Upside Down.' },
                { number: 7, title: 'Chapter Seven: The Massacre at Hawkins Lab', duration: 79, synopsis: 'Confrontation and revelations at Hawkins Lab intensify; tense battles with Vecna\'s forces unfold.', facts: 'Major revelations about Vecna\'s identity.' },
                { number: 8, title: 'Chapter Eight: Papa', duration: 77, synopsis: 'Eleven faces her past and her "Papa" in an emotional and intense showdown.', facts: 'Emotional confrontation with Dr. Brenner.' },
                { number: 9, title: 'Chapter Nine: The Piggyback', duration: 150, synopsis: 'Season finale with epic battles and closure for many story arcs; one of the longest episodes in the series.', facts: 'One of the longest episodes in TV history at 150 minutes.' }
            ]
        };

        // Schedule Data from CSV
        const schedule = [
            { date: '2025-07-22', day: 'Tuesday', time: 'Evening', episodes: ['Season 1, Episode 1: Chapter One: The Vanishing of Will Byers'], notes: '' },
            { date: '2025-07-23', day: 'Wednesday', time: 'Evening', episodes: ['Season 1, Episode 2: Chapter Two: The Weirdo on Maple Street'], notes: '' },
            { date: '2025-07-27', day: 'Sunday', time: 'Afternoon', episodes: ['Season 1, Episode 3: Chapter Three: Holly, Jolly', 'Season 1, Episode 4: Chapter Four: The Body'], notes: 'Occasional double for a weekend treat—biscuits recommended!' },
            { date: '2025-07-29', day: 'Tuesday', time: 'Evening', episodes: ['Season 1, Episode 5: Chapter Five: The Flea and the Acrobat'], notes: '' },
            { date: '2025-07-30', day: 'Wednesday', time: 'Evening', episodes: ['Season 1, Episode 6: Chapter Six: The Monster'], notes: '' },
            { date: '2025-08-03', day: 'Sunday', time: 'Afternoon', episodes: ['Season 1, Episode 7: Chapter Seven: The Bathtub'], notes: '' },
            { date: '2025-08-05', day: 'Tuesday', time: 'Evening', episodes: ['Season 1, Episode 8: Chapter Eight: The Upside Down'], notes: 'End of Season 1—celebrate with extra biscuits?' },
            { date: '2025-08-06', day: 'Wednesday', time: 'Evening', episodes: ['Season 2, Episode 1: Chapter One: MADMAX'], notes: '' },
            { date: '2025-08-10', day: 'Sunday', time: 'Afternoon', episodes: ['Season 2, Episode 2: Chapter Two: Trick or Treat, Freak'], notes: '' },
            { date: '2025-08-12', day: 'Tuesday', time: 'Evening', episodes: ['Season 2, Episode 3: Chapter Three: The Pollywog'], notes: '' },
            { date: '2025-08-13', day: 'Wednesday', time: 'Evening', episodes: ['Season 2, Episode 4: Chapter Four: Will the Wise'], notes: '' },
            { date: '2025-08-17', day: 'Sunday', time: 'Afternoon', episodes: ['Season 2, Episode 5: Chapter Five: Dig Dug', 'Season 2, Episode 6: Chapter Six: The Spy'], notes: 'Double for momentum' },
            { date: '2025-08-19', day: 'Tuesday', time: 'Evening', episodes: ['Season 2, Episode 7: Chapter Seven: The Lost Sister'], notes: '' },
            { date: '2025-08-20', day: 'Wednesday', time: 'Evening', episodes: ['Season 2, Episode 8: Chapter Eight: The Mind Flayer'], notes: '' },
            { date: '2025-08-24', day: 'Sunday', time: 'Afternoon', episodes: ['Season 2, Episode 9: Chapter Nine: The Gate'], notes: 'End of Season 2' },
            { date: '2025-08-26', day: 'Tuesday', time: 'Evening', episodes: ['Season 3, Episode 1: Chapter One: Suzie, Do You Copy?'], notes: '' },
            { date: '2025-08-27', day: 'Wednesday', time: 'Evening', episodes: ['Season 3, Episode 2: Chapter Two: The Mall Rats'], notes: '' },
            { date: '2025-08-31', day: 'Sunday', time: 'Afternoon', episodes: ['Season 3, Episode 3: Chapter Three: The Case of the Missing Lifeguard'], notes: '' },
            { date: '2025-09-02', day: 'Tuesday', time: 'Evening', episodes: ['Season 3, Episode 4: Chapter Four: The Sauna Test'], notes: '' },
            { date: '2025-09-03', day: 'Wednesday', time: 'Evening', episodes: ['Season 3, Episode 5: Chapter Five: The Flayed'], notes: '' },
            { date: '2025-09-07', day: 'Sunday', time: 'Afternoon', episodes: ['Season 3, Episode 6: Chapter Six: E Pluribus Unum', 'Season 3, Episode 7: Chapter Seven: The Bite'], notes: 'Double to wrap up the season soon' },
            { date: '2025-09-09', day: 'Tuesday', time: 'Evening', episodes: ['Season 3, Episode 8: Chapter Eight: The Battle of Starcourt'], notes: 'End of Season 3' },
            { date: '2025-09-10', day: 'Wednesday', time: 'Evening', episodes: ['Season 4, Episode 1: Chapter One: The Hellfire Club'], notes: '' },
            { date: '2025-09-14', day: 'Sunday', time: 'Afternoon', episodes: ['Season 4, Episode 2: Chapter Two: Vecna\'s Curse'], notes: '' },
            { date: '2025-09-16', day: 'Tuesday', time: 'Evening', episodes: ['Season 4, Episode 3: Chapter Three: The Monster and the Superhero'], notes: '' },
            { date: '2025-09-17', day: 'Wednesday', time: 'Evening', episodes: ['Season 4, Episode 4: Chapter Four: Dear Billy'], notes: '' },
            { date: '2025-09-21', day: 'Sunday', time: 'Afternoon', episodes: ['Season 4, Episode 5: Chapter Five: The Nina Project'], notes: '' },
            { date: '2025-09-23', day: 'Tuesday', time: 'Evening', episodes: ['Season 4, Episode 6: Chapter Six: The Dive'], notes: '' },
            { date: '2025-09-24', day: 'Wednesday', time: 'Evening', episodes: ['Season 4, Episode 7: Chapter Seven: The Massacre at Hawkins Lab'], notes: '' },
            { date: '2025-09-28', day: 'Sunday', time: 'Afternoon', episodes: ['Season 4, Episode 8: Chapter Eight: Papa', 'Season 4, Episode 9: Chapter Nine: The Piggyback'], notes: 'Final double to finish strong—end of Season 4!' }
        ];

        // Flatten all facts for random button
        const allFacts = Object.values(episodes).flat().map(ep => ep.facts);

        // Progress tracking
        let watched = 0;
        const totalEpisodes = 34;

        function updateProgress() {
            const percent = (watched / totalEpisodes) * 100;
            document.getElementById('progress-fill').style.width = `${percent}%`;
            document.getElementById('progress-text').innerText = `${watched}/${totalEpisodes} episodes watched (${Math.round(percent)}%)`;
            if (percent >= 100) {
                alert('Congrats! You\'ve finished all episodes. Ready for Season 5?');
            }
        }

        function markWatched() {
            if (watched < totalEpisodes) {
                watched++;
                updateProgress();
                // Fun surprise
                if (Math.random() < 0.2) {
                    document.body.classList.add('demogorgon');
                    setTimeout(() => document.body.classList.remove('demogorgon'), 2000);
                    alert('Demogorgon alert! Shake it off!');
                }
            }
        }

        function resetProgress() {
            watched = 0;
            updateProgress();
        }

        // Tab functionality
        function openTab(tabName) {
            document.querySelectorAll('.tab-content').forEach(tab => tab.classList.remove('active'));
            document.getElementById(tabName).classList.add('active');
        }

        // Modal
        function showModal(title, details) {
            document.getElementById('modal-title').innerText = title;
            document.getElementById('modal-details').innerHTML = details;
            document.getElementById('modal').style.display = 'flex';
        }

        function closeModal() {
            document.getElementById('modal').style.display = 'none';
        }

        // Generate Calendar
        function generateCalendar() {
            const months = [
                { name: 'July 2025', start: new Date(2025, 6, 1), days: 31 },
                { name: 'August 2025', start: new Date(2025, 7, 1), days: 31 },
                { name: 'September 2025', start: new Date(2025, 8, 1), days: 30 }
            ];

            const calendarDiv = document.getElementById('calendar');
            months.forEach(month => {
                const monthDiv = document.createElement('div');
                monthDiv.innerHTML = `<h2>${month.name}</h2><div class="calendar"></div>`;
                const weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
                weekdays.forEach(day => {
                    const dayHeader = document.createElement('div');
                    dayHeader.classList.add('day');
                    dayHeader.innerText = day;
                    monthDiv.querySelector('.calendar').appendChild(dayHeader);
                });

                // Padding for first day
                const firstDay = month.start.getDay();
                for (let i = 0; i < firstDay; i++) {
                    const emptyDay = document.createElement('div');
                    emptyDay.classList.add('day');
                    monthDiv.querySelector('.calendar').appendChild(emptyDay);
                }

                for (let d = 1; d <= month.days; d++) {
                    const dayDiv = document.createElement('div');
                    dayDiv.classList.add('day');
                    const dateStr = `2025-${String(month.start.getMonth() + 1).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
                    const sched = schedule.find(s => s.date === dateStr);
                    dayDiv.innerText = d;
                    if (sched) {
                        dayDiv.classList.add('scheduled');
                        dayDiv.innerText += '\n' + sched.time + '\n' + sched.episodes.length + ' ep(s)';
                        dayDiv.onclick = () => {
                            let details = `<p>${sched.notes}</p>`;
                            sched.episodes.forEach(epTitle => {
                                const [seasonStr, epStr] = epTitle.split(', Episode ');
                                const seasonNum = parseInt(seasonStr.replace('Season ', ''));
                                const epNum = parseInt(epStr.split(':')[0]);
                                const epData = episodes[`season_${seasonNum}`]?.find(e => e.number === epNum);
                                if (epData) {
                                    details += `<h3>${epTitle}</h3><p>Duration: ${epData.duration || 'N/A'} min</p><p>Synopsis: ${epData.synopsis || 'N/A'}</p><p>Fun Fact: ${epData.facts || 'N/A'}</p>`;
                                } else {
                                    details += `<h3>${epTitle}</h3><p>Details not available.</p>`;
                                }
                            });
                            showModal(`${dateStr} - ${sched.time}`, details);
                        };
                    }
                    monthDiv.querySelector('.calendar').appendChild(dayDiv);
                }
                calendarDiv.appendChild(monthDiv);
            });
        }

        // Generate List View
        function generateList() {
            const listUl = document.querySelector('.list-view ul');
            schedule.forEach(s => {
                const li = document.createElement('li');
                li.innerText = `${s.date} (${s.day}, ${s.time}): ${s.episodes.join(' | ')} - ${s.notes}`;
                li.onclick = () => {
                    let details = `<p>${s.notes}</p>`;
                    s.episodes.forEach(epTitle => {
                        const [seasonStr, epStr] = epTitle.split(', Episode ');
                        const seasonNum = parseInt(seasonStr.replace('Season ', ''));
                        const epNum = parseInt(epStr.split(':')[0]);
                        const epData = episodes[`season_${seasonNum}`]?.find(e => e.number === epNum);
                        if (epData) {
                            details += `<h3>${epTitle}</h3><p>Duration: ${epData.duration || 'N/A'} min</p><p>Synopsis: ${epData.synopsis || 'N/A'}</p><p>Fun Fact: ${epData.facts || 'N/A'}</p>`;
                        }
                    });
                    showModal(`${s.date} Schedule`, details);
                };
                listUl.appendChild(li);
            });
        }

        // Random Fun trituradora Fact
        function showRandomFact() {
            const factDiv = document.getElementById('fun-fact');
            const randomFact = allFacts[Math.floor(Math.random() * allFacts.length)];
            factDiv.innerText = `Random Fact: ${randomFact}`;
            factDiv.style.display = 'block';
            setTimeout(() => factDiv.style.display = 'none', 5000);
        }

        // Initialize
        generateCalendar();
        generateList();
        updateProgress();
    </script>
</body>
</html>