<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Norelco Mori</title>
    <link href="https://cdn.jsdelivr.net/npm/geist@1.2.0/dist/fonts/geist-sans/style.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/geist@1.2.0/dist/fonts/geist-mono/style.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Gelasio:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="/style.css">
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());
        gtag('config', 'G-XXXXXXXXXX');
    </script>
</head>
<body>
    <div id="transport" class="transport"></div>

    <nav>
        <a href="/">NORELCO MORI</a>
        <a href="/about.html">about</a>
        <a href="/episodes.html">episodes</a>
        <a href="/blog.html">news</a>
    </nav>

    <main id="content">
        <noscript>
            <p>This site requires JavaScript to function. Please enable JavaScript and refresh the page.</p>
        </noscript>
        <p id="js-error" style="display:none; padding: 2rem;">
            Failed to load site. Please <a href="javascript:location.reload(true)">hard refresh</a> or clear your browser cache.
        </p>
    </main>

    <footer>
        <span>&copy; 2026 | NORELCO MORI</span>
        <span><a href="/subscribe.html">subscribe</a>&nbsp;&nbsp;&nbsp;&nbsp;<a href="/contact.html">contact</a>&nbsp;&nbsp;&nbsp;&nbsp;<a href="/donate.html">donate</a></span>
    </footer>

    <script>
        window.onerror = function() {
            document.getElementById('js-error').style.display = 'block';
        };
    </script>
    <script src="/audio-manager.js" onerror="document.getElementById('js-error').style.display='block'"></script>
    <script src="/audio-player.js" onerror="document.getElementById('js-error').style.display='block'"></script>
    <script src="/transport.js" onerror="document.getElementById('js-error').style.display='block'"></script>
    <script src="/video-manager.js" onerror="document.getElementById('js-error').style.display='block'"></script>
    <script src="/router.js" onerror="document.getElementById('js-error').style.display='block'"></script>
    <script>
        // Initialize transport
        const transport = new Transport(document.getElementById('transport'));

        // Register default playlist (all Norelco Mori episodes)
        const defaultTracks = [
            { title: 'Episode 001: Civilian Sect', src: '/episodes/Norelco%20Mori%20Episode%20001.mp3', trackNum: 1, duration: '00:54:00', url: '/podcast/episode-001.html' },
            { title: 'Episode 002: To London Or The Lake', src: '/episodes/Norelco%20Mori%20Episode%20002.mp3', trackNum: 2, duration: '01:07:36', url: '/podcast/episode-002.html' },
            { title: 'Episode 003: Ides', src: '/episodes/Norelco%20Mori%20Episode%20003.mp3', trackNum: 3, duration: '01:22:35', url: '/podcast/episode-003.html' },
            { title: 'Episode 004: 16,000 Birds Apiece', src: '/episodes/Norelco%20Mori%20Episode%20004.mp3', trackNum: 4, duration: '00:52:50', url: '/podcast/episode-004.html' },
            { title: 'Episode 005: All Hail The Black Flame', src: '/episodes/Norelco%20Mori%20Episode%20005.mp3', trackNum: 5, duration: '01:08:12', url: '/podcast/episode-005.html' },
            { title: 'Episode 006: Pakomatka Pohjoiseen', src: '/episodes/Norelco%20Mori%20Episode%20006.mp3', trackNum: 6, duration: '01:01:33', url: '/podcast/episode-006.html' },
            { title: 'Episode 007: Ascetic House January Program - Part 1', src: '/episodes/Norelco%20Mori%20Episode%20007%20Part%201.mp3', trackNum: 7, duration: '00:45:06', url: '/podcast/episode-007-part-1.html' },
            { title: 'Episode 007: Ascetic House January Program - Part 2', src: '/episodes/Norelco%20Mori%20Episode%20007%20Part%202.mp3', trackNum: 8, duration: '00:55:31', url: '/podcast/episode-007-part-2.html' },
            { title: 'Episode 007: Ascetic House January Program - Part 3', src: '/episodes/Norelco%20Mori%20Episode%20007%20Part%203.mp3', trackNum: 9, duration: '01:20:55', url: '/podcast/episode-007-part-3.html' },
            { title: 'Episode 008: Invocation', src: '/episodes/Norelco%20Mori%20Episode%20008.mp3', trackNum: 10, duration: '01:00:31', url: '/podcast/episode-008.html' },
            { title: 'Episode 009: Threshold', src: '/episodes/Norelco%20Mori%20Episode%20009.mp3', trackNum: 11, duration: '01:03:08', url: '/podcast/episode-009.html' },
            { title: 'Episode 010: Phinery Tapes', src: '/episodes/Norelco%20Mori%20Episode%20010%20Edit.mp3', trackNum: 12, duration: '01:00:42', url: '/podcast/episode-010.html' },
            { title: 'Episode 011: A Subtle Shift in the Smallest Hours', src: '/episodes/Norelco%20Mori%20Episode%20011.mp3', trackNum: 13, duration: '01:12:08', url: '/podcast/episode-011.html' },
            { title: 'Episode 012: Light Sleeper', src: '/episodes/Norelco%20Mori%20Episode%20012%20II.mp3', trackNum: 14, duration: '01:00:03', url: '/podcast/episode-012.html' },
            { title: 'Episode 013: Black Ghost Knife', src: '/episodes/Norelco%20Mori%20Episode%20013.mp3', trackNum: 15, duration: '01:00:28', url: '/podcast/episode-013.html' },
            { title: 'Episode 014: No Valley Low Enough', src: '/episodes/Norelco%20Mori%20Episode%20014.mp3', trackNum: 16, duration: '00:59:54', url: '/podcast/episode-014.html' },
            { title: 'Episode 015: Polarity', src: '/episodes/Norelco%20Mori%20Episode%20015.mp3', trackNum: 17, duration: '00:59:02', url: '/podcast/episode-015.html' },
            { title: 'Episode 016: Noise City', src: '/episodes/Norelco%20Mori%20Episode%20016.mp3', trackNum: 18, duration: '01:05:05', url: '/podcast/episode-016.html' },
            { title: 'Episode 017: In Unspoiled Sands', src: '/episodes/Norelco%20Mori%20Episode%20017.mp3', trackNum: 19, duration: '01:01:23', url: '/podcast/episode-017.html' },
            { title: 'Episode 018: A Lonely Painter', src: '/episodes/Norelco%20Mori%20Episode%20018.mp3', trackNum: 20, duration: '00:58:21', url: '/podcast/episode-018.html' },
            { title: 'Episode 019: Nothing Fancy', src: '/episodes/Norelco%20Mori%20Episode%20019.mp3', trackNum: 21, duration: '01:03:15', url: '/podcast/episode-019.html' },
            { title: 'Episode 020: Motion To Abandon', src: '/episodes/Norelco%20Mori%20Episode%20020.mp3', trackNum: 22, duration: '01:01:27', url: '/podcast/episode-020.html' },
            { title: 'Episode 021: Monorail Trespassing', src: '/episodes/Norelco%20Mori%20Episode%20021.mp3', trackNum: 23, duration: '00:59:59', url: '/podcast/episode-021.html' },
            { title: 'Episode 022: Contrary To Reason', src: '/episodes/Norelco%20Mori%20Episode%20022.mp3', trackNum: 24, duration: '01:01:46', url: '/podcast/episode-022.html' },
            { title: 'Episode 023: Black Mountain', src: '/episodes/Norelco%20Mori%20Episode%20023.mp3', trackNum: 25, duration: '01:03:26', url: '/podcast/episode-023.html' },
            { title: 'Episode 024: Dead Medicine', src: '/episodes/Norelco%20Mori%20Episode%20024.mp3', trackNum: 26, duration: '01:05:48', url: '/podcast/episode-024.html' },
            { title: 'Episode 025: Hospital Productions / Bed of Nails - Part 1', src: '/episodes/Norelco%20Mori%20Episode%20025.mp3', trackNum: 27, duration: '01:06:20', url: '/podcast/episode-025-part-1.html' },
            { title: 'Episode 025: Hospital Productions / Bed of Nails - Part 2', src: '/episodes/Norelco%20Mori%20Episode%20025%20Part%202a.mp3', trackNum: 28, duration: '00:59:24', url: '/podcast/episode-025-part-2.html' },
            { title: 'Episode 026: Treasury Painted Roof', src: '/episodes/Norelco%20Mori%20Episode%20026.mp3', trackNum: 29, duration: '00:58:20', url: '/podcast/episode-026.html' },
            { title: 'Episode 027: Even Death Can Die', src: '/episodes/Norelco%20Mori%20Episode%20027.mp3', trackNum: 30, duration: '01:01:20', url: '/podcast/episode-027.html' },
            { title: 'Episode 028: Stolen', src: '/episodes/Norelco%20Mori%20Episode%20028.mp3', trackNum: 31, duration: '01:06:59', url: '/podcast/episode-028.html' },
            { title: 'Episode 029: Frozen Blue', src: '/episodes/Norelco%20Mori%20Episode%20029.mp3', trackNum: 32, duration: '01:03:52', url: '/podcast/episode-029.html' },
            { title: 'Episode 030: GHB River', src: '/episodes/Norelco%20Mori%20Episode%20030.mp3', trackNum: 33, duration: '01:03:44', url: '/podcast/episode-030.html' },
            { title: 'Episode 031: I\'m So Sorry, Goodbye', src: '/episodes/Norelco%20Mori%20Episode%20031.mp3', trackNum: 34, duration: '01:03:44', url: '/podcast/episode-031.html' },
            { title: 'Episode 032: Mindswap', src: '/episodes/Norelco%20Mori%20Episode%20032.mp3', trackNum: 35, duration: '01:00:34', url: '/podcast/episode-032.html' },
            { title: 'Episode 033: Black Horizons - Part 1', src: '/episodes/Norelco%20Mori%20Episode%20033%20BH1.mp3', trackNum: 36, duration: '00:57:36', url: '/podcast/episode-033-part-1.html' },
            { title: 'Episode 033: Black Horizons - Part 2', src: '/episodes/Norelco%20Mori%20Episode%20033%20BH2.mp3', trackNum: 37, duration: '00:58:11', url: '/podcast/episode-033-part-2.html' },
            { title: 'Episode 033: Black Horizons - Part 3', src: '/episodes/Norelco%20Mori%20Episode%20033%20BH3.mp3', trackNum: 38, duration: '01:01:33', url: '/podcast/episode-033-part-3.html' },
            { title: 'Episode 034: Mike Haley', src: '/episodes/Norelco%20Mori%20Episode%20034%20Mike%20Haley.mp3', trackNum: 39, duration: '01:03:56', url: '/podcast/episode-034.html' },
            { title: 'Episode 035: Decompression', src: '/episodes/Norelco%20Mori%20Episode%20035.mp3', trackNum: 40, duration: '00:59:17', url: '/podcast/episode-035.html' },
            { title: 'Episode 036: Solved', src: '/episodes/Norelco%20Mori%20Episode%20036.mp3', trackNum: 41, duration: '00:59:40', url: '/podcast/episode-036.html' },
            { title: 'Episode 037: Dreary Consciousness', src: '/episodes/Norelco%20Mori%20Episode%20037.mp3', trackNum: 42, duration: '01:01:59', url: '/podcast/episode-037.html' },
            { title: 'Episode 038: Don\'t Wait', src: '/episodes/Norelco%20Mori%20Episode%20038.mp3', trackNum: 43, duration: '01:02:36', url: '/podcast/episode-038.html' },
            { title: 'Episode 039: What Role, If Any', src: '/episodes/Norelco%20Mori%20Episode%20039.mp3', trackNum: 44, duration: '01:01:16', url: '/podcast/episode-039.html' },
            { title: 'Episode 040: Stop Suffering', src: '/episodes/Norelco%20Mori%20Episode%20040.mp3', trackNum: 45, duration: '00:59:40', url: '/podcast/episode-040.html' },
            { title: 'Episode 041: Generations Unlimited', src: '/episodes/Norelco%20Mori%20Episode%20041%20Generations%20Unlimited.mp3', trackNum: 46, duration: '01:02:51', url: '/podcast/episode-041.html' },
            { title: 'Episode 042: Invisible City Records', src: '/episodes/Norelco%20Mori%20Episode%20042%20-%20Invisible%20City%20Records.mp3', trackNum: 47, duration: '01:03:38', url: '/podcast/episode-042.html' },
            { title: 'Episode 043: The Deepest Waters Make The Least Noise', src: '/episodes/Norelco%20Mori%20Episode%20043.mp3', trackNum: 48, duration: '00:58:08', url: '/podcast/episode-043.html' },
            { title: 'Episode 044: Plug And Delay', src: '/episodes/Norelco%20Mori%20Episode%20044.mp3', trackNum: 49, duration: '01:00:48', url: '/podcast/episode-044.html' },
            { title: 'Episode 045: Mask Therapy', src: '/episodes/Norelco%20Mori%20Episode%20045.mp3', trackNum: 50, duration: '01:04:50', url: '/podcast/episode-045.html' },
            { title: 'Episode 046: Surplus Damage', src: '/episodes/Norelco%20Mori%20Episode%20046.mp3', trackNum: 51, duration: '00:57:27', url: '/podcast/episode-046.html' },
            { title: 'Episode 047: Landing', src: '/episodes/Norelco%20Mori%20Episode%20047%20Landing.mp3', trackNum: 52, duration: '01:05:02', url: '/podcast/episode-047.html' },
            { title: 'Episode 048: Rule Of Twelfths', src: '/episodes/Norelco%20Mori%20Episode%20048.mp3', trackNum: 53, duration: '01:02:41', url: '/podcast/episode-048.html' },
            { title: 'Episode 049: Fifteen Years Lost To Cocaine', src: '/episodes/Norelco%20Mori%20Episode%20049.mp3', trackNum: 54, duration: '01:02:25', url: '/podcast/episode-049.html' },
            { title: 'Episode 050: Revolver', src: '/episodes/Norelco%20Mori%20Episode%20050.mp3', trackNum: 55, duration: '00:55:48', url: '/podcast/episode-050.html' },
            { title: 'Episode 051: Editions Littlefield', src: '/episodes/Norelco%20Mori%20Episode%20051.mp3', trackNum: 56, duration: '01:01:16', url: '/podcast/episode-051.html' },
            { title: 'Episode 052: Karl Fousek - Part 1', src: '/episodes/Norelco%20Mori%20Episode%20052%20Part%201%20Karl%20Fousek.mp3', trackNum: 57, duration: '01:06:00', url: '/podcast/episode-052-part-1.html' },
            { title: 'Episode 052 - Part 2: Karl Fousek Guest Mix', src: '/episodes/Norelco%20Mori%20Episode%20052%20Part%202%20Karl%20Fousek%20Mix.mp3', trackNum: 58, duration: '01:04:42', url: '/podcast/episode-052-part-2.html' },
            { title: 'Episode 053: Maiella', src: '/episodes/Norelco%20Mori%20Episode%20053.mp3', trackNum: 59, duration: '01:06:14', url: '/podcast/episode-053.html' },
            { title: 'Episode 054: Dayspring', src: '/episodes/Norelco%20Mori%20Episode%20054.mp3', trackNum: 60, duration: '00:59:47', url: '/podcast/episode-054.html' },
            { title: 'Episode 055: The Dark God Of Revolution', src: '/episodes/Norelco%20Mori%20Episode%20055.mp3', trackNum: 61, duration: '01:03:11', url: '/podcast/episode-055.html' },
            { title: 'Episode 056: Ghosts', src: '/episodes/Norelco%20Mori%20Episode%20056.mp3', trackNum: 62, duration: '01:02:11', url: '/podcast/episode-056.html' },
            { title: 'Episode 057: Total Black - Part 1', src: '/episodes/Norelco%20Mori%20Episode%20057%20Total%20Black.mp3', trackNum: 63, duration: '01:05:20', url: '/podcast/episode-057-part-1.html' },
            { title: 'Episode 057: Total Black - Part 2', src: '/episodes/Norelco%20Mori%20Episode%20057%20Total%20Black%20Part%202.mp3', trackNum: 64, duration: '01:02:38', url: '/podcast/episode-057-part-2.html' },
            { title: 'Episode 057: Total Black - Part 3', src: '/episodes/Norelco%20Mori%20Episode%20057%20Total%20Black%20Part%203.mp3', trackNum: 65, duration: '00:58:44', url: '/podcast/episode-057-part-3.html' },
            { title: 'Episode 058: Undulations', src: '/episodes/Norelco%20Mori%20Episode%20058.mp3', trackNum: 66, duration: '01:03:24', url: '/podcast/episode-058.html' },
            { title: 'Episode 059: Hay Dias Que No Tengo Soda', src: '/episodes/Norelco%20Mori%20Episode%20059.mp3', trackNum: 67, duration: '01:00:00', url: '/podcast/episode-059.html' },
            { title: 'Episode 060: Audio. Visuals. Atmosphere.', src: '/episodes/Norelco%20Mori%20Episode%20060%20AVA.mp3', trackNum: 68, duration: '01:05:55', url: '/podcast/episode-060.html' },
            { title: 'Episode 061: Tandem Tapes', src: '/episodes/Norelco%20Mori%20Episode%20061%20Tandem%20Tapes.mp3', trackNum: 69, duration: '00:59:00', url: '/podcast/episode-061.html' },
            { title: 'Episode 062: Heteroticisms 1-4', src: '/episodes/Norelco%20Mori%20Episode%20062%20Heteroticisms%201-4.mp3', trackNum: 70, duration: '01:01:39', url: '/podcast/episode-062.html' },
            { title: 'Episode 063: Circulo Silencioso', src: '/episodes/Norelco%20Mori%20Episode%20063.mp3', trackNum: 71, duration: '01:02:14', url: '/podcast/episode-063.html' },
            { title: 'Episode 064: Dead Deer Dream', src: '/episodes/Norelco%20Mori%20Episode%20064.mp3', trackNum: 72, duration: '00:58:51', url: '/podcast/episode-064.html' },
            { title: 'Episode 065: Blood', src: '/episodes/Norelco%20Mori%20Episode%20065%20Blood.mp3', trackNum: 73, duration: '00:58:08', url: '/podcast/episode-065.html' },
            { title: 'Episode 066: Hands On Ears', src: '/episodes/Norelco%20Mori%20Episode%20066.mp3', trackNum: 74, duration: '01:03:00', url: '/podcast/episode-066.html' },
            { title: 'Episode 067: NTS Live', src: '/episodes/Norelco%20Mori%20Episode%20067%20NTS%20150118.mp3', trackNum: 75, duration: '00:59:55', url: '/podcast/episode-067.html' },
            { title: 'Episode 068: Under A Sea Of Benzodiazepines', src: '/episodes/Norelco%20Mori%20Episode%20068.mp3', trackNum: 76, duration: '01:01:36', url: '/podcast/episode-068.html' },
            { title: 'Episode 069: Slum Lust', src: '/episodes/Norelco%20Mori%20Episode%20069.mp3', trackNum: 77, duration: '00:59:08', url: '/podcast/episode-069.html' },
            { title: 'Episode 070 - Neologist Productions', src: '/episodes/Norelco%20Mori%20Episode%20070%202.mp3', trackNum: 78, duration: '01:08:59', url: '/podcast/episode-070.html' },
            { title: 'Episode 071: Iron Ridge', src: '/episodes/Norelco%20Mori%20Episode%20071.mp3', trackNum: 79, duration: '01:04:27', url: '/podcast/episode-071.html' },
            { title: 'Episode 072: Nerves Of Human Life', src: '/episodes/Norelco%20Mori%20Episode%20072.mp3', trackNum: 80, duration: '01:02:12', url: '/podcast/episode-072.html' },
            { title: 'Episode 073: Sinneslöschen', src: '/episodes/Norelco%20Mori%20Episode%20073%20Sinneslochen.mp3', trackNum: 81, duration: '01:03:48', url: '/podcast/episode-073.html' },
            { title: 'Episode 074: The Long Forgotten', src: '/episodes/Norelco%20Mori%20Episode%20074.mp3', trackNum: 82, duration: '01:07:47', url: '/podcast/episode-074.html' },
            { title: 'Episode 075: Dinzu Artefacts', src: '/episodes/Norelco%20Mori%20Episode%20075.mp3', trackNum: 83, duration: '01:03:52', url: '/podcast/episode-075.html' },
            { title: 'Episode 076: Beauty Sleep', src: '/episodes/Norelco%20Mori%20-%20Episode%2076%20-%20Beauty%20Sleep.mp3', trackNum: 84, duration: '01:00:50', url: '/podcast/episode-076.html' }
        ];
        window.audioManager.register('Norelco Mori', defaultTracks);
        window.audioManager.setActivePlaylist('Norelco Mori');

        // Load waveforms for all tracks
        function loadWaveform(index, src) {
            const filename = decodeURIComponent(src.split('/').pop().replace(/\.[^.]+$/, ''));
            const waveformPath = `/waveforms/${encodeURIComponent(filename)}.json`;

            return fetch(waveformPath)
                .then(r => r.ok ? r.json() : null)
                .then(data => {
                    if (data) {
                        window.audioManager.setWaveform('Norelco Mori', index, data);
                        if (index === 0) transport.drawWaveform(data);
                    }
                })
                .catch(() => {});
        }
        defaultTracks.forEach((track, i) => loadWaveform(i, track.src));

        // Initialize router
        const router = new Router(document.getElementById('content'), {
            basePath: '/pages',
            defaultPage: 'home',
            onNavigate: (pageName, contentEl) => {
                // Clear previous players but preserve playback state
                window.audioManager.clearPlayers();
                window.videoManager.clearPlayers();

                // Re-register the default playlist so it's always available
                window.audioManager.register('Norelco Mori', defaultTracks);

                // If no playlist is active, set the default as active
                if (!window.audioManager.activePlayerName) {
                    window.audioManager.setActivePlaylist('Norelco Mori');
                }

                // Reload waveforms for default playlist
                defaultTracks.forEach((track, i) => loadWaveform(i, track.src));

                // Execute any inline scripts in the loaded content
                const scripts = contentEl.querySelectorAll('script');
                scripts.forEach(script => {
                    try {
                        if (script.src) {
                            const newScript = document.createElement('script');
                            newScript.src = script.src;
                            document.body.appendChild(newScript);
                        } else {
                            // Use eval for inline scripts - more reliable than DOM manipulation
                            eval(script.textContent);
                        }
                        script.remove();
                    } catch (e) {
                        console.error('Script execution error:', e);
                    }
                });


                // Scan for YouTube videos to manage
                window.videoManager.scanForVideos(contentEl);
            }
        });
    </script>
</body>
</html>
