Files
singular-particular-space/Watchlists/soundscapeanomalies.html
JL Kruger dd51655792 Add Watchlists section — hub, 5 collection pages, build pipeline
- watchlists-hub.html: comic book panel grid, neon-teal/green/toucan palette,
  Rambla-only type hierarchy, CSS stagger entrance, wired to star map
- 5 collection pages built from *-watchlist.md sources via build.py:
  contentaddictionarchive, analogfrontier, culturaldecay,
  soundscapeanomalies, lastcinema
- build.py: parses MD files, generates self-contained HTML pages,
  updates hub subtitle with live counts
- index.html: Watchlists star node wired to Watchlists/watchlists-hub.html

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 14:22:02 +02:00

452 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SOUNDSCAPE ANOMALIES | WATCHLISTS</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Rambla:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
<style>
:root {
--bg-void: #04060b;
--text-warm: #e8d5b8;
--wl-teal: #2ac4b3;
--wl-green: #32dc8c;
--wl-toucan: #ffcf40;
--wl-teal-glow: rgba(42, 196, 179, 0.22);
--wl-green-glow: rgba(50, 220, 140, 0.22);
--wl-toucan-glow: rgba(255, 207, 64, 0.22);
--muted: rgba(232, 213, 184, 0.45);
}
* { box-sizing: border-box; margin: 0; padding: 0; border-radius: 0; }
body {
background-color: var(--bg-void);
color: var(--text-warm);
font-family: 'Rambla', sans-serif;
line-height: 1.5;
padding-top: 88px;
}
/* ── Sticky header ── */
.sticky-header {
position: fixed;
top: 0; left: 0; right: 0;
height: 72px;
background: var(--bg-void);
border-bottom: 2px solid var(--wl-teal);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 2rem;
z-index: 1000;
}
.header-title {
font-weight: 700;
text-transform: uppercase;
color: var(--wl-toucan);
font-size: 1.1rem;
letter-spacing: -0.01em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 55%;
}
.header-nav {
display: flex;
align-items: center;
gap: 2rem;
}
.nav-link {
font-weight: 700;
text-transform: uppercase;
text-decoration: none;
color: var(--wl-teal);
font-size: 0.85rem;
letter-spacing: 0.04em;
transition: color 100ms ease;
}
.nav-link:hover { color: var(--wl-green); }
.header-count {
font-weight: 700;
text-transform: uppercase;
color: var(--wl-green);
font-size: 0.78rem;
letter-spacing: 0.1em;
}
.menu-toggle {
display: none;
background: none;
border: 2px solid var(--wl-teal);
color: var(--wl-teal);
padding: 0.4rem 0.6rem;
font-size: 1.1rem;
cursor: pointer;
font-family: inherit;
transition: color 100ms ease, border-color 100ms ease;
}
.menu-toggle:hover { color: var(--wl-green); border-color: var(--wl-green); }
@media (max-width: 600px) {
.header-nav {
display: none;
flex-direction: column;
align-items: flex-start;
position: absolute;
top: 72px; left: 0; right: 0;
background: var(--bg-void);
padding: 1.25rem 2rem;
border-bottom: 2px solid var(--wl-teal);
gap: 0.75rem;
}
.header-nav.open { display: flex; }
.menu-toggle { display: block; }
.header-title { max-width: 65%; }
}
/* ── Lightbox ── */
#lightbox {
position: fixed;
inset: 0;
background: rgba(4, 6, 11, 0.92);
display: none;
justify-content: center;
align-items: center;
z-index: 2000;
padding: 2rem;
cursor: pointer;
}
.caption-box {
background: #080d10;
border: 2px solid var(--wl-teal);
border-top: 10px solid var(--wl-toucan);
border-left: 6px solid var(--wl-green);
max-width: 640px;
width: 100%;
max-height: 90vh;
overflow-y: auto;
padding: 2rem 2rem 1.5rem;
position: relative;
cursor: default;
}
.caption-close {
position: absolute;
top: 0.6rem;
right: 0.75rem;
background: none;
border: none;
color: var(--wl-teal);
font-family: 'Rambla', sans-serif;
font-size: 1.6rem;
font-weight: 700;
line-height: 1;
cursor: pointer;
padding: 0.1rem 0.3rem;
transition: color 100ms ease;
}
.caption-close:hover { color: var(--wl-toucan); }
.caption-text {
font-style: italic;
font-size: 1.05rem;
color: var(--text-warm);
margin-bottom: 1.25rem;
line-height: 1.65;
padding-right: 1.5rem;
}
.dismiss-hint {
font-weight: 700;
text-transform: uppercase;
font-size: 0.62rem;
letter-spacing: 0.18em;
color: var(--muted);
text-align: center;
margin-top: 1.25rem;
}
/* ── Panels ── */
.container {
max-width: 900px;
margin: 0 auto;
padding: 2rem 2rem 4rem;
}
@media (max-width: 600px) {
.container { padding: 1.5rem 1.25rem 3rem; }
}
@keyframes panelIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.playlist-panel {
margin-bottom: 3.5rem;
border: 2px solid var(--border-color);
background: var(--bg-void);
position: relative;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.6);
animation: panelIn 350ms ease both;
}
.playlist-panel:nth-child(1) { animation-delay: 0ms; }
.playlist-panel:nth-child(2) { animation-delay: 60ms; }
.playlist-panel:nth-child(3) { animation-delay: 120ms; }
.playlist-panel:nth-child(4) { animation-delay: 180ms; }
.playlist-panel:nth-child(5) { animation-delay: 240ms; }
.playlist-panel:nth-child(6) { animation-delay: 300ms; }
.playlist-panel:nth-child(7) { animation-delay: 360ms; }
.playlist-panel:nth-child(8) { animation-delay: 420ms; }
.panel-header {
background: var(--border-color);
padding: 0.75rem 1.25rem;
color: var(--bg-void);
display: flex;
justify-content: space-between;
align-items: center;
}
.panel-header h2 {
font-size: 1.15rem;
font-weight: 700;
text-transform: uppercase;
margin: 0;
line-height: 1.2;
}
.panel-number {
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
color: rgba(4, 6, 11, 0.75);
letter-spacing: 0.06em;
white-space: nowrap;
margin-left: 1rem;
flex-shrink: 0;
}
.video-container {
position: relative;
padding-bottom: 56.25%;
height: 0;
overflow: hidden;
}
.video-container iframe {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
border: 0;
}
.panel-teal { --border-color: var(--wl-teal); }
.panel-green { --border-color: var(--wl-green); }
.panel-toucan { --border-color: var(--wl-toucan); }
</style>
</head>
<body>
<header class="sticky-header">
<div class="header-title">SOUNDSCAPE ANOMALIES</div>
<button class="menu-toggle" id="menu-toggle"></button>
<nav class="header-nav" id="header-nav">
<a href="watchlists-hub.html" class="nav-link">← WATCHLISTS</a>
<span class="header-count">8 PLAYLISTS</span>
</nav>
</header>
<div id="lightbox" role="dialog" aria-modal="true" aria-label="Introduction">
<div class="caption-box">
<button class="caption-close" id="caption-close" aria-label="Close">×</button>
<p class="caption-text">There are sounds that shouldn&#x27;t exist in the arrangements they appear in. Dark ambient. Ritual drone. Frequencies that feel like memory. I use this music for thinking, for deep work, for the hours before sleep when the brain needs to be occupied but not led. It doesn&#x27;t have melody in the pop sense. It has texture. Atmosphere. Intention.</p>
<p class="dismiss-hint">CLICK ANYWHERE TO DISMISS</p>
</div>
</div>
<main class="container">
<section class="playlist-panel panel-teal">
<div class="panel-header">
<h2>RITUAL, DRONE &amp; DARK AMBIENT FULL ALBUMS</h2>
<span class="panel-number">PANEL 01</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLN_G7yTx9SXeR047RrbIuhsJFBeBZHaeO"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen>
</iframe>
</div>
</section>
<section class="playlist-panel panel-green">
<div class="panel-header">
<h2>FROZEN ECHOES: DARK AMBIENT MEETS DRONE TEXTURES</h2>
<span class="panel-number">PANEL 02</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLnPbOOvxxh-cJNVhhQ05TldMrNv_ycNPW"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen>
</iframe>
</div>
</section>
<section class="playlist-panel panel-toucan">
<div class="panel-header">
<h2>DARK AMBIENT SOUNDSCAPES &amp; INDUSTRIAL NOISE MUSIC</h2>
<span class="panel-number">PANEL 03</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLg0P6LepONgLmkrXUQpIBjnvYoi_lolo0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen>
</iframe>
</div>
</section>
<section class="playlist-panel panel-teal">
<div class="panel-header">
<h2>THE SOUND OF ISOLATION: DARK AMBIENT AND DRONE</h2>
<span class="panel-number">PANEL 04</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLAsJFJTfcTKP-eGc0S6EbCfSoctELYM7t"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen>
</iframe>
</div>
</section>
<section class="playlist-panel panel-green">
<div class="panel-header">
<h2>MISERY LOVES COMPANY: MEDITATIVE DRONE ATMOSPHERES</h2>
<span class="panel-number">PANEL 05</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLezayui57fOezxQBXfB0YIvM2EgSFdoZO"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen>
</iframe>
</div>
</section>
<section class="playlist-panel panel-toucan">
<div class="panel-header">
<h2>TRIBAL AMBIENT: SHAMANIC DRUMMING &amp; DEEP SOUNDSCAPES</h2>
<span class="panel-number">PANEL 06</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLCwOPk7IsaoA61VHcHD8M3rb5dRcLm7Dy"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen>
</iframe>
</div>
</section>
<section class="playlist-panel panel-teal">
<div class="panel-header">
<h2>OBSTINATOR DARK AMBIENT</h2>
<span class="panel-number">PANEL 07</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLNPzbTO0Qe116YhIxNIj083qeTlMpD32e"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen>
</iframe>
</div>
</section>
<section class="playlist-panel panel-green">
<div class="panel-header">
<h2>LE OMBRE DEL NON-ESSERE</h2>
<span class="panel-number">PANEL 08</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLgvBz-Cwkzii_UJNJcU0Qtr5Gzu6tG66T"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen>
</iframe>
</div>
</section>
</main>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Lightbox: show on first load
const lightbox = document.getElementById('lightbox');
if (!localStorage.getItem('watchlist-soundscapeanomalies-seen')) {
lightbox.style.display = 'flex';
localStorage.setItem('watchlist-soundscapeanomalies-seen', '1');
}
function closeLightbox() { lightbox.style.display = 'none'; }
lightbox.addEventListener('click', (e) => {
if (e.target === lightbox) closeLightbox();
});
document.getElementById('caption-close').addEventListener('click', closeLightbox);
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeLightbox();
});
// Mobile nav toggle
const menuToggle = document.getElementById('menu-toggle');
const headerNav = document.getElementById('header-nav');
menuToggle.addEventListener('click', (e) => {
e.stopPropagation();
headerNav.classList.toggle('open');
});
document.addEventListener('click', (e) => {
if (!headerNav.contains(e.target) && e.target !== menuToggle) {
headerNav.classList.remove('open');
}
});
// Lazy-load iframes via IntersectionObserver
const observer = new IntersectionObserver((entries, obs) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const iframe = entry.target;
const src = iframe.getAttribute('data-src');
if (src) {
iframe.setAttribute('src', src);
iframe.removeAttribute('data-src');
}
obs.unobserve(iframe);
}
});
}, { rootMargin: '200px 0px' });
document.querySelectorAll('iframe[data-src]').forEach(
iframe => observer.observe(iframe)
);
});
</script>
</body>
</html>