diff --git a/frontend/src/components/FooterStrip.astro b/frontend/src/components/FooterStrip.astro
new file mode 100644
index 0000000..dc851fe
--- /dev/null
+++ b/frontend/src/components/FooterStrip.astro
@@ -0,0 +1,8 @@
+---
+---
+
diff --git a/frontend/src/components/ListenWaysCard.astro b/frontend/src/components/ListenWaysCard.astro
new file mode 100644
index 0000000..a98ad74
--- /dev/null
+++ b/frontend/src/components/ListenWaysCard.astro
@@ -0,0 +1,28 @@
+---
+const ORIGIN = 'https://denpa.femboy.page';
+interface Props { stationId: string; }
+const { stationId } = Astro.props;
+---
+
+
+
他の聴き方
+
// other ways to listen
+
+
+
+
DIRECT STREAM (MP3)
+
{ORIGIN}/{stationId}.mp3
+
drop into VLC, mpv, foobar, etc.
+
+
+
DIRECT STREAM (OPUS)
+
{ORIGIN}/{stationId}.opus
+
smaller, better quality. modern players only.
+
+
+
METADATA JSON
+
{ORIGIN}/now-playing/{stationId}.json
+
build your own scrobbler.
+
+
+
diff --git a/frontend/src/components/TopNav.astro b/frontend/src/components/TopNav.astro
new file mode 100644
index 0000000..3e76fb5
--- /dev/null
+++ b/frontend/src/components/TopNav.astro
@@ -0,0 +1,9 @@
+---
+---
+
diff --git a/frontend/src/pages/index.astro b/frontend/src/pages/index.astro
new file mode 100644
index 0000000..02ca49e
--- /dev/null
+++ b/frontend/src/pages/index.astro
@@ -0,0 +1,44 @@
+---
+import '@styles/tokens.css';
+import '@styles/global.css';
+import '@styles/components/hero.css';
+import '@styles/components/deck.css';
+import '@styles/components/spectrum.css';
+import '@styles/components/tape.css';
+import '@styles/components/history-card.css';
+import '@styles/components/listen-ways-card.css';
+import '@styles/components/footer.css';
+
+import TopNav from '@components/TopNav.astro';
+import HistoryCard from '@components/HistoryCard.astro';
+import ListenWaysCard from '@components/ListenWaysCard.astro';
+import FooterStrip from '@components/FooterStrip.astro';
+import { HeroPlayer } from '@components/HeroPlayer';
+import { listStations } from '@lib/stations';
+
+export const prerender = false;
+
+const root = process.env.LIBRARY_ROOT ?? '/library';
+const initialStations = await listStations(root);
+const firstStation = initialStations[0]?.id ?? '';
+---
+
+
+
+
+
+ denpa.fm // 電波
+
+
+
+
+
+
+
+ {firstStation ?
:
}
+ {firstStation ?
:
}
+
+
+
+
+
diff --git a/frontend/src/styles/components/footer.css b/frontend/src/styles/components/footer.css
new file mode 100644
index 0000000..7579d5e
--- /dev/null
+++ b/frontend/src/styles/components/footer.css
@@ -0,0 +1,9 @@
+.footer {
+ margin-top: 12px; padding: 30px 0 24px;
+ border-top: 2px dashed #ff3ea566;
+}
+.footer-bot {
+ display: flex; justify-content: space-between; gap: 14px;
+ font-family: var(--f-mono); font-size: 12px; color: #fff4e8aa;
+ flex-wrap: wrap;
+}
diff --git a/frontend/src/styles/components/listen-ways-card.css b/frontend/src/styles/components/listen-ways-card.css
new file mode 100644
index 0000000..2e0a7ac
--- /dev/null
+++ b/frontend/src/styles/components/listen-ways-card.css
@@ -0,0 +1,20 @@
+.listen-ways-list { display: flex; flex-direction: column; gap: 14px; }
+.listen-way {
+ border: 1.5px dashed #5ef7ff44;
+ padding: 12px;
+ background: #0a04108c;
+}
+.lw-label { font-family: var(--f-pixel); font-size: 12px; color: var(--lemon); letter-spacing: 2px; margin-bottom: 4px; }
+.lw-url {
+ display: block; font-family: var(--f-mono); font-size: 13px;
+ color: var(--cyan); background: var(--ink);
+ padding: 6px 8px; word-break: break-all;
+}
+.lw-hint { font-family: var(--f-mono); font-size: 11px; color: #fff4e866; margin-top: 6px; }
+
+.row-grid { display: grid; gap: 24px; margin-bottom: 36px; }
+.row-grid.two { grid-template-columns: 1.2fr 1fr; }
+
+@media (max-width: 1000px) {
+ .row-grid.two { grid-template-columns: 1fr; }
+}