You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

691 lines
21 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>THE BRIDGE · LCARS</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=Antonio:wght@400;700&family=Share+Tech+Mono&display=swap" rel="stylesheet">
<style>
/* ── LCARS Color System ── */
:root {
--bg: #000000;
--orange: #FF9900;
--gold: #FFCC00;
--blue: #9999FF;
--purple: #CC88FF;
--pink: #FF99CC;
--teal: #4DFFDB;
--red: #FF6666;
--card-bg: #0d0500;
--gap: 8px;
--hdr: 72px;
--ftr: 52px;
--sw: 190px;
--er: 36px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { background: var(--bg); }
body {
background: var(--bg);
color: #fff;
font-family: 'Antonio', 'Arial Narrow', sans-serif;
min-height: 100vh;
}
/* ════════════════ HEADER ════════════════ */
.lcars-hdr {
display: flex;
align-items: stretch;
height: var(--hdr);
position: sticky;
top: 0;
z-index: 200;
background: var(--bg);
}
.hdr-elbow {
width: var(--sw);
flex-shrink: 0;
background: var(--orange);
border-radius: 0 0 var(--er) 0;
}
.hdr-sep { width: var(--gap); flex-shrink: 0; }
.hdr-bar {
flex: 1;
background: var(--orange);
border-radius: 0 0 0 var(--er);
display: flex;
align-items: center;
padding: 0 1.5rem 0 2rem;
gap: 1.5rem;
min-width: 0;
}
.hdr-title {
font-size: clamp(1.3rem, 3vw, 2rem);
font-weight: 700;
letter-spacing: 4px;
text-transform: uppercase;
color: #000;
white-space: nowrap;
}
.hdr-right {
display: flex;
align-items: center;
gap: 8px;
margin-left: auto;
flex-shrink: 0;
}
.lcars-chip {
height: 32px;
padding: 0 14px;
border-radius: 16px;
display: flex;
align-items: center;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 2px;
text-transform: uppercase;
color: #000;
white-space: nowrap;
}
.chip-blue { background: var(--blue); }
.chip-purple { background: var(--purple); }
#lcars-clock {
font-family: 'Share Tech Mono', monospace;
font-size: 1rem;
color: #000;
letter-spacing: 2px;
}
/* ════════════════ BODY ════════════════ */
.lcars-body {
display: flex;
gap: var(--gap);
}
/* ─── SIDEBAR ─── */
.lcars-sidebar {
width: var(--sw);
flex-shrink: 0;
align-self: flex-start;
display: flex;
flex-direction: column;
gap: 5px;
padding: var(--gap) 0;
position: sticky;
top: var(--hdr);
max-height: calc(100vh - var(--hdr));
overflow-y: auto;
scrollbar-width: none;
}
.lcars-sidebar::-webkit-scrollbar { display: none; }
.nav-pill {
height: 46px;
flex-shrink: 0;
border-radius: 0 23px 23px 0;
display: flex;
align-items: center;
padding: 0 20px 0 14px;
font-family: 'Antonio', sans-serif;
font-size: 0.8rem;
font-weight: 700;
letter-spacing: 2px;
text-transform: uppercase;
color: #000;
text-decoration: none;
cursor: pointer;
border: none;
transition: filter 0.1s;
}
.nav-pill:hover { filter: brightness(1.12); }
.nav-pill:active { filter: brightness(0.9); }
.nav-divider { height: 10px; flex-shrink: 0; }
.nav-pill.c-orange { background: var(--orange); }
.nav-pill.c-blue { background: var(--blue); }
.nav-pill.c-teal { background: var(--teal); }
.nav-pill.c-purple { background: var(--purple); }
.nav-pill.c-pink { background: var(--pink); }
.nav-pill.c-gold { background: var(--gold); }
.nav-pill.c-red { background: var(--red); }
/* ─── MAIN ─── */
.lcars-main {
flex: 1;
min-width: 0;
padding: 1.2rem 1.5rem 2rem;
}
.section {
margin-bottom: 2.5rem;
scroll-margin-top: calc(var(--hdr) + 10px);
}
.sec-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 1rem;
}
.sec-label {
height: 30px;
padding: 0 18px;
border-radius: 15px;
display: flex;
align-items: center;
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 3px;
text-transform: uppercase;
color: #000;
white-space: nowrap;
flex-shrink: 0;
}
.sec-rule {
flex: 1;
height: 2px;
opacity: 0.35;
}
.c-orange .sec-label { background: var(--orange); }
.c-orange .sec-rule { background: var(--orange); }
.c-blue .sec-label { background: var(--blue); }
.c-blue .sec-rule { background: var(--blue); }
.c-teal .sec-label { background: var(--teal); }
.c-teal .sec-rule { background: var(--teal); }
.c-purple .sec-label { background: var(--purple); }
.c-purple .sec-rule { background: var(--purple); }
.c-pink .sec-label { background: var(--pink); }
.c-pink .sec-rule { background: var(--pink); }
.c-gold .sec-label { background: var(--gold); }
.c-gold .sec-rule { background: var(--gold); }
.c-red .sec-label { background: var(--red); }
.c-red .sec-rule { background: var(--red); }
/* ─── CARDS ─── */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(185px, 1fr));
gap: 8px;
}
.card {
display: flex;
align-items: stretch;
text-decoration: none;
color: #fff;
background: var(--card-bg);
border: 1px solid #1e0d00;
border-radius: 6px;
overflow: hidden;
min-height: 68px;
transition: filter 0.1s, transform 0.1s;
-webkit-tap-highlight-color: transparent;
}
.card:hover { filter: brightness(1.2); transform: translateY(-1px); }
.card:active { filter: brightness(0.85); transform: translateY(0); }
.card-bar { width: 7px; flex-shrink: 0; }
.card-body { padding: 0.75rem 0.9rem; }
.card-name {
font-size: 1rem;
font-weight: 700;
letter-spacing: 1.5px;
text-transform: uppercase;
}
.card-desc {
font-size: 0.72rem;
letter-spacing: 0.3px;
line-height: 1.4;
margin-top: 0.2rem;
opacity: 0.55;
}
.c-orange .card-bar { background: var(--orange); }
.c-orange .card-name { color: var(--orange); }
.c-blue .card-bar { background: var(--blue); }
.c-blue .card-name { color: var(--blue); }
.c-teal .card-bar { background: var(--teal); }
.c-teal .card-name { color: var(--teal); }
.c-purple .card-bar { background: var(--purple); }
.c-purple .card-name { color: var(--purple); }
.c-pink .card-bar { background: var(--pink); }
.c-pink .card-name { color: var(--pink); }
.c-gold .card-bar { background: var(--gold); }
.c-gold .card-name { color: var(--gold); }
.c-red .card-bar { background: var(--red); }
.c-red .card-name { color: var(--red); }
/* ════════════════ FOOTER ════════════════ */
.lcars-ftr {
display: flex;
height: var(--ftr);
gap: var(--gap);
background: var(--bg);
}
.ftr-cap {
width: var(--sw);
flex-shrink: 0;
background: var(--blue);
border-radius: 0 var(--er) 0 0;
}
.ftr-sep { width: var(--gap); flex-shrink: 0; }
.ftr-bar {
flex: 1;
background: var(--orange);
border-radius: var(--er) 0 0 0;
display: flex;
align-items: center;
padding: 0 1.5rem;
gap: 1rem;
min-width: 0;
}
.ftr-label {
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 3px;
text-transform: uppercase;
color: #000;
white-space: nowrap;
}
.ftr-dots {
display: flex;
gap: 6px;
margin-left: auto;
}
.ftr-dot {
width: 36px;
height: 24px;
border-radius: 5px;
}
/* ════════════════ RESPONSIVE ════════════════ */
@media (max-width: 800px) {
:root { --hdr: 56px; --ftr: 44px; }
.hdr-elbow, .hdr-sep, .ftr-cap, .ftr-sep { display: none; }
.hdr-bar { border-radius: 0; }
.ftr-bar { border-radius: 0; }
.lcars-body { flex-direction: column; gap: 0; }
.lcars-sidebar {
width: 100%;
height: auto;
max-height: none;
position: static;
flex-direction: row;
flex-wrap: nowrap;
overflow-x: auto;
overflow-y: hidden;
padding: 8px;
gap: 6px;
scrollbar-width: none;
}
.lcars-sidebar::-webkit-scrollbar { display: none; }
.nav-pill {
border-radius: 20px;
height: 38px;
flex-shrink: 0;
padding: 0 14px;
font-size: 0.72rem;
}
.nav-divider { width: 10px; height: auto; }
.lcars-main { padding: 0.75rem 0.75rem 1.5rem; }
.card-grid { grid-template-columns: repeat(auto-fill, minmax(145px, 1fr)); }
}
@media (max-width: 420px) {
.card-grid { grid-template-columns: 1fr 1fr; }
.hdr-title { font-size: 1.2rem; letter-spacing: 2px; }
#lcars-clock { display: none; }
}
/* ── Animations ── */
@keyframes lcars-pulse {
0%, 80%, 100% { opacity: 1; }
88% { opacity: 0.3; }
}
.pulse { animation: lcars-pulse 3.5s infinite; }
</style>
</head>
<body>
<!-- HEADER -->
<header class="lcars-hdr">
<div class="hdr-elbow"></div>
<div class="hdr-sep"></div>
<div class="hdr-bar">
<div class="hdr-title">The Bridge</div>
<div class="hdr-right">
<div class="lcars-chip chip-blue">LCARS</div>
<div class="lcars-chip chip-purple pulse">ONLINE</div>
<div id="lcars-clock">00:00:00</div>
</div>
</div>
</header>
<div class="lcars-body">
<!-- SIDEBAR NAV -->
<nav class="lcars-sidebar">
<a href="#entertainment" class="nav-pill c-orange">Entertainment</a>
<a href="#cloud" class="nav-pill c-blue">Cloud &amp; Files</a>
<a href="#smarthome" class="nav-pill c-teal">Smart Home</a>
<div class="nav-divider"></div>
<a href="#ai" class="nav-pill c-purple">AI &amp; Tools</a>
<a href="#media" class="nav-pill c-pink">Media Mgmt</a>
<a href="#downloads" class="nav-pill c-gold">Downloads</a>
<div class="nav-divider"></div>
<a href="#system" class="nav-pill c-red">System</a>
</nav>
<!-- MAIN CONTENT -->
<main class="lcars-main">
<!-- ENTERTAINMENT -->
<section id="entertainment" class="section c-orange">
<div class="sec-header">
<div class="sec-label">Entertainment</div>
<div class="sec-rule"></div>
</div>
<div class="card-grid">
<a class="card" href="http://plex.home:32400/web" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Plex</div>
<div class="card-desc">Movies, TV shows, music &amp; more</div>
</div>
</a>
<a class="card" href="http://roon.doubleday.haus" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Roon</div>
<div class="card-desc">High-quality music player</div>
</div>
</a>
</div>
</section>
<!-- CLOUD & FILES -->
<section id="cloud" class="section c-blue">
<div class="sec-header">
<div class="sec-label">Cloud &amp; Files</div>
<div class="sec-rule"></div>
</div>
<div class="card-grid">
<a class="card" href="https://cloud.doubleday.io" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Nextcloud</div>
<div class="card-desc">Files, calendar, contacts &amp; more</div>
</div>
</a>
<a class="card" href="http://archive.doubleday.haus" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Photos</div>
<div class="card-desc">Photo library &amp; album management</div>
</div>
</a>
<a class="card" href="http://git.doubleday.haus" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Gitea</div>
<div class="card-desc">Private code repositories</div>
</div>
</a>
</div>
</section>
<!-- SMART HOME -->
<section id="smarthome" class="section c-teal">
<div class="sec-header">
<div class="sec-label">Smart Home</div>
<div class="sec-rule"></div>
</div>
<div class="card-grid">
<a class="card" href="http://ziggy.home" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Home Assistant</div>
<div class="card-desc">Home automation &amp; device control</div>
</div>
</a>
</div>
</section>
<!-- AI & TOOLS -->
<section id="ai" class="section c-purple">
<div class="sec-header">
<div class="sec-label">AI &amp; Tools</div>
<div class="sec-rule"></div>
</div>
<div class="card-grid">
<a class="card" href="http://ai.home" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">AI Chat</div>
<div class="card-desc">Private AI assistant (Open WebUI)</div>
</div>
</a>
<a class="card" href="http://search.home" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Search</div>
<div class="card-desc">Private, ad-free web search</div>
</div>
</a>
<a class="card" href="http://n8n.home" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Automation</div>
<div class="card-desc">n8n workflow automation</div>
</div>
</a>
<a class="card" href="http://mcpo.home" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">MCPO</div>
<div class="card-desc">MCP tool servers (fetch, time, HA, memory)</div>
</div>
</a>
<a class="card" href="http://agent.home" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Agent</div>
<div class="card-desc">AI homelab assistant</div>
</div>
</a>
<a class="card" href="http://fgs.home" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">FGS</div>
<div class="card-desc">Heavy metal discovery dashboard</div>
</div>
</a>
<a class="card" href="http://metal.home" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Metal</div>
<div class="card-desc">Metal curation pipeline monitor</div>
</div>
</a>
</div>
</section>
<!-- MEDIA MANAGEMENT -->
<section id="media" class="section c-pink">
<div class="sec-header">
<div class="sec-label">Media Management</div>
<div class="sec-rule"></div>
</div>
<div class="card-grid">
<a class="card" href="http://movies.doubleday.haus" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Radarr</div>
<div class="card-desc">Movie collection &amp; requests</div>
</div>
</a>
<a class="card" href="http://shows.doubleday.haus" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Sonarr</div>
<div class="card-desc">TV series collection &amp; requests</div>
</div>
</a>
<a class="card" href="http://music.doubleday.haus" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Lidarr</div>
<div class="card-desc">Music collection &amp; requests</div>
</div>
</a>
<a class="card" href="http://books.doubleday.haus" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Readarr</div>
<div class="card-desc">Ebook collection &amp; requests</div>
</div>
</a>
</div>
</section>
<!-- DOWNLOADS -->
<section id="downloads" class="section c-gold">
<div class="sec-header">
<div class="sec-label">Downloads</div>
<div class="sec-rule"></div>
</div>
<div class="card-grid">
<a class="card" href="http://sabnzbd.doubleday.haus" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">SABnzbd</div>
<div class="card-desc">Usenet download client</div>
</div>
</a>
<a class="card" href="http://transmission.doubleday.haus" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Transmission</div>
<div class="card-desc">Torrent download client</div>
</div>
</a>
<a class="card" href="http://search.doubleday.haus" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Prowlarr</div>
<div class="card-desc">Indexer management for downloads</div>
</div>
</a>
</div>
</section>
<!-- SYSTEM -->
<section id="system" class="section c-red">
<div class="sec-header">
<div class="sec-label">System</div>
<div class="sec-rule"></div>
</div>
<div class="card-grid">
<a class="card" href="http://adguard.home:3001" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">AdGuard</div>
<div class="card-desc">Network-level ad &amp; tracker blocking</div>
</div>
</a>
<a class="card" href="http://traces.home" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Langfuse</div>
<div class="card-desc">AI pipeline observability &amp; logs</div>
</div>
</a>
<a class="card" href="http://ollama.home" target="_blank">
<div class="card-bar"></div>
<div class="card-body">
<div class="card-name">Ollama</div>
<div class="card-desc">Local LLM model server API</div>
</div>
</a>
</div>
</section>
</main>
</div><!-- /.lcars-body -->
<!-- FOOTER -->
<footer class="lcars-ftr">
<div class="ftr-cap"></div>
<div class="ftr-sep"></div>
<div class="ftr-bar">
<span class="ftr-label">All Systems Nominal</span>
<div class="ftr-dots">
<div class="ftr-dot" style="background:var(--orange)"></div>
<div class="ftr-dot" style="background:var(--gold)"></div>
<div class="ftr-dot" style="background:var(--blue)"></div>
<div class="ftr-dot" style="background:var(--purple)"></div>
<div class="ftr-dot" style="background:var(--teal)"></div>
<div class="ftr-dot" style="background:var(--red)"></div>
</div>
</div>
</footer>
<script>
// Live clock
function tick() {
const t = new Date();
const p = n => String(n).padStart(2, '0');
document.getElementById('lcars-clock').textContent =
`${p(t.getHours())}:${p(t.getMinutes())}:${p(t.getSeconds())}`;
}
tick();
setInterval(tick, 1000);
// Smooth scroll for sidebar nav
document.querySelectorAll('.nav-pill[href^="#"]').forEach(pill => {
pill.addEventListener('click', e => {
e.preventDefault();
const target = document.querySelector(pill.getAttribute('href'));
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });
});
});
</script>
</body>
</html>