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>
This commit is contained in:
2026-03-28 14:22:02 +02:00
parent bdb39c8c08
commit dd51655792
13 changed files with 3598 additions and 1 deletions

View File

@@ -0,0 +1,30 @@
# The Analog Frontier
---
>>on-first-load - lightbox - "Before everything was a file, sound was a voltage. Before everything was a stream, images were magnetic. The analog world didn't disappear — it got archived, obsessed over, and loved harder by the people who understood what was lost. This is a collection of playlists about those machines, that music, and the humans who still speak their language."
---
- **Electronic Music And Synthesizer Documentaries \- YouTube**
- URL: https://www.youtube.com/playlist?list=PL9IOjFRFjrOlaSN20n8BVup9Sw5pECF_N
- **Vintage Synth Music \- YouTube**
- URL: https://www.youtube.com/playlist?list=PL705B75747F552D89
- **Kosmische Wellen \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLTESZvBAvs-21WEss2-tAc88YUVJvbHjt
- **Analog Synths \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLGPon0XahgRzdHHRcXIXOTYncuiTmihTQ
- **Video Synth \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLnwRAEdhoHKvgCHahY_Geef80sn98Q1yq
- **Analog Ambient: Warm Synths \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLSui2JfAn3uzFXSPuBOFdyUMOhjSQK_0O
- **Old Hi-Tech \- YouTube**
- URL: https://www.youtube.com/playlist?list=PL1Qu_o1uczDrmRp0aaTDPfIChzMG3BsnG
---

View File

@@ -0,0 +1,30 @@
# Cultural Decay Observations
---
>>on-first-load - lightbox - "The internet ate the 20th century and we watched it happen in real time. The video essay form — someone with a camera and a thesis, talking into the void — became the literature of my generation. These are the playlists I return to when I want to understand the shape of the thing we're all living inside. Criticism as a survival skill."
---
- **Internet Analysis, by tiffanyferg \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLeYBqpyQVyaYqtBAfbNy6d_xtxcrjCVy6
- **Internet Girl Mythology: Pop Culture & Digital Dissected \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLkTkIkgJg3GsmoEsh4a9-YRUuZtHNr0w9
- **Essays: Media & Pop Culture \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLa8L4_jjaB62-j89zcyfQ_ZV7bVceMSDB
- **Media & Pop Culture Analysis \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLJQUAVYdQ53t3hqA1t1hNcWrrZT5sGMfj
- **Video Essays \(Solar Sands\) \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLgp6-KTN0LyAkDMmtGROSmer8IpL7kUSd
- **Media Video Essays \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLK5fE38XOCnpWSvoxMNL8igQxPZlAi4_F
- **Actually Interesting Video Essays \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLbOF9TQmQrNgWHaLCPaE81l4hEL-2Rrjf
---

View File

@@ -0,0 +1,33 @@
# Soundscape Anomalies
---
>>on-first-load - lightbox - "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."
---
- **Ritual, Drone & Dark Ambient Full Albums \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLN_G7yTx9SXeR047RrbIuhsJFBeBZHaeO
- **Frozen Echoes: Dark Ambient Meets Drone Textures \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLnPbOOvxxh-cJNVhhQ05TldMrNv_ycNPW
- **Dark Ambient Soundscapes & Industrial Noise Music \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLg0P6LepONgLmkrXUQpIBjnvYoi_lolo0
- **The Sound of Isolation: Dark Ambient and Drone \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLAsJFJTfcTKP-eGc0S6EbCfSoctELYM7t
- **Misery Loves Company: Meditative Drone Atmospheres \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLezayui57fOezxQBXfB0YIvM2EgSFdoZO
- **Tribal Ambient: Shamanic Drumming & Deep Soundscapes \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLCwOPk7IsaoA61VHcHD8M3rb5dRcLm7Dy
- **Obstinator Dark Ambient \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLNPzbTO0Qe116YhIxNIj083qeTlMpD32e
- **Le Ombre del Non-Essere \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLgvBz-Cwkzii_UJNJcU0Qtr5Gzu6tG66T
---

View File

@@ -0,0 +1,27 @@
# The Last Cinema
---
>>on-first-load - lightbox - "Short films are the ones that got away. The feature film has a machine behind it — financing, distribution, marketing. The short film has a person behind it, usually broke, always obsessed. This collection is experimental work, avant-garde work, cult films, archive footage — cinema that exists outside the machine. Watch them when you have 10 minutes and a reason to feel something strange."
---
- **Experimental, Avant-Garde & Surreal Short Films \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLx8zUw4PoWHgqy5bD0HcuuTgVqPOSNrHn
- **Films: Cult Movies \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLqqTsphh57d5czFm-bK404ripWFI-2a8c
- **A History of Unique Visual Art \(Mega Compilation\) \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLHPWDhsjb4ZFGV_3ezZHcQ142HwppW--Y
- **Loops \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLSpz5qTrO-GnziQviNzmarSRpTbe8OcgQ
- **Movies \(Homerecorded Delicatessens\) \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLo16qa3p5doyYLVw4JCm7bGBH7nf4vLnV
- **Archives \- YouTube**
- URL: https://www.youtube.com/playlist?list=PLjf4Mu2Zp3kYtBZB38-huwZA3DJaIcGN_
---

View File

@@ -0,0 +1,436 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>THE ANALOG FRONTIER | 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; }
.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">THE ANALOG FRONTIER</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">7 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">Before everything was a file, sound was a voltage. Before everything was a stream, images were magnetic. The analog world didn&#x27;t disappear — it got archived, obsessed over, and loved harder by the people who understood what was lost. This is a collection of playlists about those machines, that music, and the humans who still speak their language.</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>ELECTRONIC MUSIC AND SYNTHESIZER DOCUMENTARIES</h2>
<span class="panel-number">PANEL 01</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PL9IOjFRFjrOlaSN20n8BVup9Sw5pECF_N"
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>VINTAGE SYNTH MUSIC</h2>
<span class="panel-number">PANEL 02</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PL705B75747F552D89"
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>KOSMISCHE WELLEN</h2>
<span class="panel-number">PANEL 03</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLTESZvBAvs-21WEss2-tAc88YUVJvbHjt"
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>ANALOG SYNTHS</h2>
<span class="panel-number">PANEL 04</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLGPon0XahgRzdHHRcXIXOTYncuiTmihTQ"
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>VIDEO SYNTH</h2>
<span class="panel-number">PANEL 05</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLnwRAEdhoHKvgCHahY_Geef80sn98Q1yq"
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>ANALOG AMBIENT: WARM SYNTHS</h2>
<span class="panel-number">PANEL 06</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLSui2JfAn3uzFXSPuBOFdyUMOhjSQK_0O"
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>OLD HI-TECH</h2>
<span class="panel-number">PANEL 07</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PL1Qu_o1uczDrmRp0aaTDPfIChzMG3BsnG"
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-analogfrontier-seen')) {
lightbox.style.display = 'flex';
localStorage.setItem('watchlist-analogfrontier-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>

520
Watchlists/build.py Normal file
View File

@@ -0,0 +1,520 @@
#!/usr/bin/env python3
"""
Watchlists build script.
For each *-watchlist.md in this folder:
- Parse title, optional first-load lightbox, and playlist entries
- Generate a self-contained HTML page
Then update watchlists-hub.html subtitle with current totals.
Output filenames: strip '-watchlist' suffix, lowercase the stem, no hyphens/spaces.
ContentAddictionArchive-watchlist.md → contentaddictionarchive.html
AnalogFrontier-watchlist.md → analogfrontier.html
etc.
Run after adding or editing any *-watchlist.md file.
"""
import re
from pathlib import Path
from html import escape
HERE = Path(__file__).parent
HUB = HERE / "watchlists-hub.html"
COLORS = ["teal", "green", "toucan"] # rotation order
ALLOW = (
"accelerometer; autoplay; clipboard-write; "
"encrypted-media; gyroscope; picture-in-picture; web-share"
)
# ── MD parsing ────────────────────────────────────────────────────────────────
def slug_from_path(path: Path) -> str:
stem = path.stem # e.g. "AnalogFrontier-watchlist"
stem = re.sub(r'-watchlist$', '', stem, flags=re.IGNORECASE)
return stem.lower().replace('-', '').replace('_', '').replace(' ', '')
def parse_md(path: Path) -> dict:
text = path.read_text(encoding='utf-8')
# Title: first # heading
m = re.search(r'^#\s+(.+)$', text, re.MULTILINE)
title = m.group(1).strip() if m else path.stem
# Optional lightbox: >>on-first-load - lightbox - "text"
m = re.search(r'>>on-first-load\s+-\s+lightbox\s+-\s+"([^"]+)"', text)
lightbox = m.group(1).strip() if m else None
# Playlist entries
# - **Name \- YouTube**
# - URL: https://www.youtube.com/playlist?list=PLxxxxxx
playlists = []
for m in re.finditer(
r'-\s+\*\*(.+?)\s*\\-\s*YouTube\*\*\s*\n\s+-\s+URL:\s+(https://[^\s]+)',
text
):
name = m.group(1).strip()
url = m.group(2).strip()
lid = re.search(r'[?&]list=([A-Za-z0-9_-]+)', url)
if lid:
playlists.append({'name': name, 'list_id': lid.group(1)})
return {'title': title, 'lightbox': lightbox, 'playlists': playlists}
# ── HTML generation ───────────────────────────────────────────────────────────
def build_lightbox_html(text: str, slug: str) -> tuple[str, str]:
"""Return (lightbox_div_html, lightbox_js_html). Empty strings if no lightbox."""
if not text:
return '', ''
safe = escape(text)
div = f"""
<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">{safe}</p>
<p class="dismiss-hint">CLICK ANYWHERE TO DISMISS</p>
</div>
</div>"""
js = f"""
// Lightbox: show on first load
const lightbox = document.getElementById('lightbox');
if (!localStorage.getItem('watchlist-{slug}-seen')) {{
lightbox.style.display = 'flex';
localStorage.setItem('watchlist-{slug}-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();
}});
"""
return div, js
def build_panels_html(playlists: list) -> str:
panels = []
for i, pl in enumerate(playlists):
color = COLORS[i % len(COLORS)]
num = f"PANEL {i+1:02d}"
embed_url = f"https://www.youtube.com/embed/videoseries?list={pl['list_id']}"
title_esc = escape(pl['name'].upper())
panels.append(f"""
<section class="playlist-panel panel-{color}">
<div class="panel-header">
<h2>{title_esc}</h2>
<span class="panel-number">{num}</span>
</div>
<div class="video-container">
<iframe
data-src="{embed_url}"
allow="{ALLOW}"
allowfullscreen>
</iframe>
</div>
</section>""")
return '\n'.join(panels)
def build_stagger_css(count: int) -> str:
lines = []
for i in range(1, count + 1):
delay = (i - 1) * 60
lines.append(
f" .playlist-panel:nth-child({i}) {{ animation-delay: {delay}ms; }}"
)
return '\n'.join(lines)
def generate_html(data: dict, slug: str) -> str:
title = data['title']
playlists = data['playlists']
count = len(playlists)
title_upper = title.upper()
count_label = f"{count} PLAYLIST{'S' if count != 1 else ''}"
lightbox_div, lightbox_js = build_lightbox_html(data['lightbox'], slug)
panels_html = build_panels_html(playlists)
stagger_css = build_stagger_css(count)
# Lightbox CSS block (only if there's a lightbox)
lightbox_css = """
/* ── 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;
}
""" if data['lightbox'] else ''
return f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{escape(title_upper)} | 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_css}
/* ── 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;
}}
{stagger_css}
.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">{escape(title_upper)}</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">{count_label}</span>
</nav>
</header>
{lightbox_div}
<main class="container">
{panels_html}
</main>
<script>
document.addEventListener('DOMContentLoaded', () => {{
{lightbox_js}
// 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>
"""
# ── Hub subtitle update ───────────────────────────────────────────────────────
def update_hub_subtitle(collection_count: int, playlist_total: int):
hub_text = HUB.read_text(encoding='utf-8')
subtitle = (
f'<div class="subtitle">'
f'{collection_count} COLLECTION{"S" if collection_count != 1 else ""}'
f' · CURATED VIDEO ARCHIVES'
f' · {playlist_total} PLAYLIST{"S" if playlist_total != 1 else ""}'
f'</div>'
)
hub_text = re.sub(
r'<!-- SUBTITLE-START -->.*?<!-- SUBTITLE-END -->',
f'<!-- SUBTITLE-START -->{subtitle}<!-- SUBTITLE-END -->',
hub_text,
flags=re.DOTALL
)
HUB.write_text(hub_text, encoding='utf-8')
# ── Main ──────────────────────────────────────────────────────────────────────
def main():
md_files = sorted(HERE.glob('*-watchlist.md'))
if not md_files:
print("No *-watchlist.md files found.")
return
total_playlists = 0
for md_path in md_files:
slug = slug_from_path(md_path)
out = HERE / f"{slug}.html"
data = parse_md(md_path)
count = len(data['playlists'])
if count == 0:
print(f" SKIP {md_path.name} — no playlists found")
continue
html = generate_html(data, slug)
out.write_text(html, encoding='utf-8')
total_playlists += count
print(f" BUILD {out.name}{data['title']} ({count} playlists)")
update_hub_subtitle(len(md_files), total_playlists)
print(f"\nUpdated hub subtitle — {len(md_files)} collections, {total_playlists} playlists total")
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,451 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AND ARCHIVE OF THE END OF MY ADDICTION | 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">AND ARCHIVE OF THE END OF MY ADDICTION</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">One of the most insidious and persistent addictions I have had to manage and overcome in my life, is my addiction to videos on screens. It began with TV after school, then videos on the computer, then YouTube. I realized my addiction before short form hit the dopamine receptors of a generation. Although that was because I was too poor to get caught by Vine like my friends at church. Noooo, my battle with content addiction has been long and fraught with failure. However, one of the most reliable methods I have found for curbing use, is to cultivate the act of curation. That is, document your habits, assess the content for value. Don&#x27;t begin by making judgements. Just keep a record of what you watched and organize it by how valuable you think it is. From there, see how your choices of what to watch and when change. Learning to work with my brain instead of against it began by understanding my addiction to content. Anyway, here is a selection of playlists from that journey. There&#x27;s some interesting stuff here, but future watchlists in other parts of this website will undoubtedly be better and more thoughtfully curated. - JL</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>MUSICAL MEANDERINGS</h2>
<span class="panel-number">PANEL 01</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OCZ9GbPdci0M63b1PcI1TVZ"
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>FOOD CURIOS</h2>
<span class="panel-number">PANEL 02</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OCq5LsgL2EmoaP9dwlhu2go"
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>CURIOSITIES</h2>
<span class="panel-number">PANEL 03</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967ODwpT-Z-ej0dE4EcMIQirxe"
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>BAN CAN WATCH QUEUE</h2>
<span class="panel-number">PANEL 04</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OAuW_pFsPCtQyLp6nqoChHA"
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>NEW WATCH QUEUE</h2>
<span class="panel-number">PANEL 05</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OBOQgKPJdgeb_661OCc-IP_"
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>UNSORTED MIXES</h2>
<span class="panel-number">PANEL 06</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OAdklUmXZk8RI7DYhRmMIxT"
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>WATCH IT AGAIN FROM TIME TO TIME</h2>
<span class="panel-number">PANEL 07</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OBfSGKNlj6nxh9E6J-Rzof5"
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>MISCELLANY</h2>
<span class="panel-number">PANEL 08</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OAoUDyuAtKTSLCEgZkFwqdP"
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-contentaddictionarchive-seen')) {
lightbox.style.display = 'flex';
localStorage.setItem('watchlist-contentaddictionarchive-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>

View File

@@ -0,0 +1,436 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CULTURAL DECAY OBSERVATIONS | 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; }
.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">CULTURAL DECAY OBSERVATIONS</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">7 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">The internet ate the 20th century and we watched it happen in real time. The video essay form — someone with a camera and a thesis, talking into the void — became the literature of my generation. These are the playlists I return to when I want to understand the shape of the thing we&#x27;re all living inside. Criticism as a survival skill.</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>INTERNET ANALYSIS, BY TIFFANYFERG</h2>
<span class="panel-number">PANEL 01</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLeYBqpyQVyaYqtBAfbNy6d_xtxcrjCVy6"
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>INTERNET GIRL MYTHOLOGY: POP CULTURE &amp; DIGITAL DISSECTED</h2>
<span class="panel-number">PANEL 02</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLkTkIkgJg3GsmoEsh4a9-YRUuZtHNr0w9"
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>ESSAYS: MEDIA &amp; POP CULTURE</h2>
<span class="panel-number">PANEL 03</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLa8L4_jjaB62-j89zcyfQ_ZV7bVceMSDB"
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>MEDIA &amp; POP CULTURE ANALYSIS</h2>
<span class="panel-number">PANEL 04</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLJQUAVYdQ53t3hqA1t1hNcWrrZT5sGMfj"
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>VIDEO ESSAYS \(SOLAR SANDS\)</h2>
<span class="panel-number">PANEL 05</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLgp6-KTN0LyAkDMmtGROSmer8IpL7kUSd"
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>MEDIA VIDEO ESSAYS</h2>
<span class="panel-number">PANEL 06</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLK5fE38XOCnpWSvoxMNL8igQxPZlAi4_F"
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>ACTUALLY INTERESTING VIDEO ESSAYS</h2>
<span class="panel-number">PANEL 07</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLbOF9TQmQrNgWHaLCPaE81l4hEL-2Rrjf"
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-culturaldecay-seen')) {
lightbox.style.display = 'flex';
localStorage.setItem('watchlist-culturaldecay-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>

421
Watchlists/lastcinema.html Normal file
View File

@@ -0,0 +1,421 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>THE LAST CINEMA | 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; }
.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">THE LAST CINEMA</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">6 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">Short films are the ones that got away. The feature film has a machine behind it — financing, distribution, marketing. The short film has a person behind it, usually broke, always obsessed. This collection is experimental work, avant-garde work, cult films, archive footage — cinema that exists outside the machine. Watch them when you have 10 minutes and a reason to feel something strange.</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>EXPERIMENTAL, AVANT-GARDE &amp; SURREAL SHORT FILMS</h2>
<span class="panel-number">PANEL 01</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLx8zUw4PoWHgqy5bD0HcuuTgVqPOSNrHn"
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>FILMS: CULT MOVIES</h2>
<span class="panel-number">PANEL 02</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLqqTsphh57d5czFm-bK404ripWFI-2a8c"
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>A HISTORY OF UNIQUE VISUAL ART \(MEGA COMPILATION\)</h2>
<span class="panel-number">PANEL 03</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLHPWDhsjb4ZFGV_3ezZHcQ142HwppW--Y"
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>LOOPS</h2>
<span class="panel-number">PANEL 04</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLSpz5qTrO-GnziQviNzmarSRpTbe8OcgQ"
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>MOVIES \(HOMERECORDED DELICATESSENS\)</h2>
<span class="panel-number">PANEL 05</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLo16qa3p5doyYLVw4JCm7bGBH7nf4vLnV"
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>ARCHIVES</h2>
<span class="panel-number">PANEL 06</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLjf4Mu2Zp3kYtBZB38-huwZA3DJaIcGN_"
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-thelastcinema-seen')) {
lightbox.style.display = 'flex';
localStorage.setItem('watchlist-thelastcinema-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>

View File

@@ -0,0 +1,451 @@
<!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>

View File

@@ -0,0 +1,505 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AND ARCHIVE OF THE END OF MY ADDICTION | 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 / caption box ── */
#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; /* clear the × button */
}
.attribution {
font-weight: 700;
text-transform: uppercase;
color: var(--wl-toucan);
font-size: 0.85rem;
letter-spacing: 0.06em;
text-align: right;
}
.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;
}
/* ── Playlist panels ── */
.container {
max-width: 900px;
margin: 0 auto;
padding: 2rem 2rem 4rem;
}
@media (max-width: 600px) {
.container {
padding: 1.5rem 1.25rem 3rem;
}
}
/* Panel entrance stagger */
@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;
}
/* Color rotation */
.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">END OF MY ADDICTION</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">
One of the most insidious and persistent addictions I have had to manage and overcome in my life, is my addiction to videos on screens. It began with TV after school, then videos on the computer, then YouTube. I realized my addiction before short form hit the dopamine receptors of a generation. Although that was because I was too poor to get caught by Vine like my friends at church. Noooo, my battle with content addiction has been long and fraught with failure. However, one of the most reliable methods I have found for curbing use, is to cultivate the act of curation. That is, document your habits, assess the content for value. Don't begin by making judgements. Just keep a record of what you watched and organize it by how valuable you think it is. From there, see how your choices of what to watch and when change. Learning to work with my brain instead of against it began by understanding my addiction to content. Anyway, here is a selection of playlists from that journey. There's some interesting stuff here, but future watchlists in other parts of this website will undoubtedly be better and more thoughtfully curated.
</p>
<div class="attribution">— JL</div>
<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>MUSICAL MEANDERINGS</h2>
<span class="panel-number">PANEL 01</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OCZ9GbPdci0M63b1PcI1TVZ"
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>FOOD CURIOS</h2>
<span class="panel-number">PANEL 02</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OCq5LsgL2EmoaP9dwlhu2go"
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>CURIOSITIES</h2>
<span class="panel-number">PANEL 03</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967ODwpT-Z-ej0dE4EcMIQirxe"
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>BAN CAN WATCH QUEUE</h2>
<span class="panel-number">PANEL 04</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OAuW_pFsPCtQyLp6nqoChHA"
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>NEW WATCH QUEUE</h2>
<span class="panel-number">PANEL 05</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OBOQgKPJdgeb_661OCc-IP_"
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>UNSORTED MIXES</h2>
<span class="panel-number">PANEL 06</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OAdklUmXZk8RI7DYhRmMIxT"
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>WATCH IT AGAIN FROM TIME TO TIME</h2>
<span class="panel-number">PANEL 07</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OBfSGKNlj6nxh9E6J-Rzof5"
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>MISCELLANY</h2>
<span class="panel-number">PANEL 08</span>
</div>
<div class="video-container">
<iframe
data-src="https://www.youtube.com/embed/videoseries?list=PLUby3nb967OAoUDyuAtKTSLCEgZkFwqdP"
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-caa-seen')) {
lightbox.style.display = 'flex';
localStorage.setItem('watchlist-caa-seen', '1');
}
function closeLightbox() {
lightbox.style.display = 'none';
}
// Dismiss on backdrop click (not caption-box click)
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>

View File

@@ -0,0 +1,257 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WATCHLISTS | SINGULAR PARTICULAR</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: 2.5rem 2rem;
max-width: 1200px;
margin: 0 auto;
}
header {
margin-bottom: 3.5rem;
}
.back-link {
display: inline-block;
font-weight: 700;
text-transform: uppercase;
text-decoration: none;
color: var(--wl-teal);
font-size: 0.85rem;
letter-spacing: 0.06em;
margin-bottom: 1.25rem;
transition: color 100ms ease;
}
.back-link:hover {
color: var(--wl-green);
}
h1 {
font-size: clamp(3rem, 10vw, 5.5rem);
font-weight: 700;
text-transform: uppercase;
color: var(--wl-teal);
line-height: 0.88;
letter-spacing: -0.02em;
margin-bottom: 0.75rem;
border-left: 6px solid var(--wl-toucan);
padding-left: 1rem;
}
.subtitle {
font-weight: 700;
text-transform: uppercase;
color: var(--wl-green);
font-size: 0.78rem;
letter-spacing: 0.12em;
padding-left: calc(1rem + 6px); /* align under h1 text */
}
.hub-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 2.5rem;
}
@media (max-width: 768px) {
.hub-grid {
grid-template-columns: 1fr;
gap: 2rem;
}
body {
padding: 1.5rem;
}
h1 {
font-size: clamp(2.5rem, 12vw, 4rem);
}
}
/* Panel entrance stagger */
@keyframes panelIn {
from {
opacity: 0;
transform: translateY(18px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.panel-card {
display: block;
text-decoration: none;
color: inherit;
border: 2px solid var(--border-color);
background: var(--bg-void);
transition: box-shadow 100ms ease, border-color 100ms ease;
position: relative;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.6);
animation: panelIn 320ms ease both;
}
.panel-card:nth-child(1) { animation-delay: 0ms; }
.panel-card:nth-child(2) { animation-delay: 80ms; }
.panel-card:nth-child(3) { animation-delay: 160ms; }
.panel-card:nth-child(4) { animation-delay: 240ms; }
.panel-card:nth-child(5) { animation-delay: 320ms; }
.panel-card:hover {
box-shadow: 0 0 8px 4px var(--glow-color), 0 4px 8px rgba(0, 0, 0, 0.6);
border-color: var(--hover-border);
}
.panel-header {
background: var(--border-color);
padding: 0.75rem 1.25rem;
color: var(--bg-void);
}
.panel-header h2 {
font-size: 1.25rem;
font-weight: 700;
text-transform: uppercase;
margin: 0;
line-height: 1.2;
}
.panel-body {
padding: 1.25rem 1.25rem 1.5rem;
}
.count {
display: block;
font-weight: 700;
text-transform: uppercase;
font-size: 0.7rem;
letter-spacing: 0.12em;
color: var(--muted);
margin-bottom: 0.6rem;
}
.description {
font-style: italic;
font-size: 0.95rem;
color: var(--text-warm);
line-height: 1.5;
}
/* Color rotation */
.panel-teal {
--border-color: var(--wl-teal);
--glow-color: var(--wl-teal-glow);
--hover-border: var(--wl-green);
}
.panel-green {
--border-color: var(--wl-green);
--glow-color: var(--wl-green-glow);
--hover-border: var(--wl-toucan);
}
.panel-toucan {
--border-color: var(--wl-toucan);
--glow-color: var(--wl-toucan-glow);
--hover-border: var(--wl-teal);
}
</style>
</head>
<body>
<header>
<a href="../index.html" class="back-link">← SPACE</a>
<h1>WATCHLISTS</h1>
<!-- SUBTITLE-START --><div class="subtitle">5 COLLECTIONS · CURATED VIDEO ARCHIVES · 36 PLAYLISTS</div><!-- SUBTITLE-END -->
</header>
<main class="hub-grid">
<!-- Real data -->
<a href="contentaddictionarchive.html" class="panel-card panel-teal">
<div class="panel-header">
<h2>AND ARCHIVE OF THE END OF MY ADDICTION</h2>
</div>
<div class="panel-body">
<span class="count">8 PLAYLISTS</span>
<p class="description">A record of a long war with content addiction.</p>
</div>
</a>
<!-- Placeholders -->
<a href="analogfrontier.html" class="panel-card panel-green">
<div class="panel-header">
<h2>THE ANALOG FRONTIER</h2>
</div>
<div class="panel-body">
<span class="count">7 PLAYLISTS</span>
<p class="description">Early digital artifacts and salvaged broadcast media.</p>
</div>
</a>
<a href="culturaldecay.html" class="panel-card panel-toucan">
<div class="panel-header">
<h2>CULTURAL DECAY OBSERVATIONS</h2>
</div>
<div class="panel-body">
<span class="count">7 PLAYLISTS</span>
<p class="description">Documenting the slow collapse of 20th century aesthetics.</p>
</div>
</a>
<a href="soundscapeanomalies.html" class="panel-card panel-teal">
<div class="panel-header">
<h2>SOUNDSCAPE ANOMALIES</h2>
</div>
<div class="panel-body">
<span class="count">8 PLAYLISTS</span>
<p class="description">Frequencies that feel like memory. Sound at the edge of perception.</p>
</div>
</a>
<a href="lastcinema.html" class="panel-card panel-green">
<div class="panel-header">
<h2>THE LAST CINEMA</h2>
</div>
<div class="panel-body">
<span class="count">6 PLAYLISTS</span>
<p class="description">Short films found in the wreckage of the old world.</p>
</div>
</a>
</main>
</body>
</html>

View File

@@ -694,7 +694,7 @@ body::after {
{ id: 'music', label: 'Music', sign: '♬', x: 12, y: 44, href: '' },
{ id: 'images', label: 'Images', sign: '絵', x: 55, y: 35, href: 'Images/images.html' },
{ id: 'playlists', label: 'Playlists', sign: '≡', x: 78, y: 50, href: 'Playlists/playlists.html' },
{ id: 'watchlists', label: 'Watchlists', sign: '視', x: 22, y: 66, href: '' },
{ id: 'watchlists', label: 'Watchlists', sign: '視', x: 22, y: 66, href: 'Watchlists/watchlists-hub.html' },
{ id: 'toolsntoys', label: 'ToolsnToys', sign: '⚙', x: 50, y: 72, href: '' },
{ id: 'creatorlists', label: 'Creatorlists', sign: '創', x: 75, y: 70, href: '' }
];