- 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>
452 lines
16 KiB
HTML
452 lines
16 KiB
HTML
<!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'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'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 & 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 & 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 & 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>
|