1e357244e1
Three full-fidelity dashboard mockups (Bridge/Console, Aurora/Glass, Bento/Modular) plus a chooser index and a tracker-detail page in the chosen Aurora language. Self-contained HTML, no build needed.
1161 lines
42 KiB
HTML
1161 lines
42 KiB
HTML
<!doctype html>
|
||
<html lang="en" data-theme="light">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Notify Bridge — Bento</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=Manrope:wght@300..800&family=JetBrains+Mono:wght@300..600&display=swap" rel="stylesheet">
|
||
<style>
|
||
/* ============================================================
|
||
OPTION C — "BENTO MODULAR"
|
||
Apple Keynote / Linear blog energy. Mixed-size colorful tiles
|
||
in a tight grid. Each tile commits to a single role and color.
|
||
Generous radius, confident type, playful but disciplined.
|
||
============================================================ */
|
||
:root[data-theme="light"] {
|
||
--bg: #f4f3ef;
|
||
--surface: #ffffff;
|
||
--ink: #0c0d11;
|
||
--ink-dim: #4d5159;
|
||
--mute: #898d97;
|
||
--rule: #e7e6e0;
|
||
--rule-strong: #cfcec7;
|
||
|
||
/* Tile palette — bold, confident, never muddy */
|
||
--tile-violet: #6d4ce6;
|
||
--tile-violet-fg: #ffffff;
|
||
--tile-mint: #c8f078;
|
||
--tile-mint-fg: #1a2e0c;
|
||
--tile-coral: #ff6f5b;
|
||
--tile-coral-fg: #ffffff;
|
||
--tile-honey: #ffd23a;
|
||
--tile-honey-fg: #2a1f00;
|
||
--tile-cobalt: #1d3aff;
|
||
--tile-cobalt-fg: #ffffff;
|
||
--tile-rose: #ffd1e0;
|
||
--tile-rose-fg: #4a0d2e;
|
||
--tile-ink: #0c0d11;
|
||
--tile-ink-fg: #ffffff;
|
||
--tile-bone: #f0eee8;
|
||
--tile-bone-fg: #0c0d11;
|
||
|
||
/* Status */
|
||
--ok: #1f9d56;
|
||
--warn: #c97600;
|
||
--err: #d6322f;
|
||
}
|
||
:root[data-theme="dark"] {
|
||
--bg: #0a0a0c;
|
||
--surface: #14151a;
|
||
--ink: #f0eee8;
|
||
--ink-dim: #b0b3bd;
|
||
--mute: #6f7280;
|
||
--rule: #232530;
|
||
--rule-strong: #353846;
|
||
|
||
--tile-violet: #8366ff;
|
||
--tile-violet-fg: #ffffff;
|
||
--tile-mint: #b0e85d;
|
||
--tile-mint-fg: #142605;
|
||
--tile-coral: #ff7864;
|
||
--tile-coral-fg: #2a0500;
|
||
--tile-honey: #ffcf3d;
|
||
--tile-honey-fg: #2a1f00;
|
||
--tile-cobalt: #4566ff;
|
||
--tile-cobalt-fg: #ffffff;
|
||
--tile-rose: #ff9bbf;
|
||
--tile-rose-fg: #2a0010;
|
||
--tile-ink: #f0eee8;
|
||
--tile-ink-fg: #0c0d11;
|
||
--tile-bone: #1c1d24;
|
||
--tile-bone-fg: #f0eee8;
|
||
|
||
--ok: #4cd383;
|
||
--warn: #ffb454;
|
||
--err: #ff7a7a;
|
||
}
|
||
|
||
*, *::before, *::after { box-sizing: border-box; }
|
||
html, body { margin: 0; padding: 0; }
|
||
body {
|
||
background: var(--bg);
|
||
color: var(--ink);
|
||
font-family: 'Manrope', ui-sans-serif, system-ui, sans-serif;
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
min-height: 100vh;
|
||
overflow-x: hidden;
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
letter-spacing: -0.005em;
|
||
transition: background .3s ease, color .3s ease;
|
||
}
|
||
::selection { background: var(--tile-violet); color: white; }
|
||
::-webkit-scrollbar { width: 8px; height: 8px; }
|
||
::-webkit-scrollbar-thumb { background: var(--rule-strong); border-radius: 999px; }
|
||
|
||
/* ============================================================
|
||
APP SHELL — narrow rail, wide canvas
|
||
============================================================ */
|
||
.shell {
|
||
display: grid;
|
||
grid-template-columns: 76px 1fr;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
/* RAIL — icon-only, tactile */
|
||
.rail {
|
||
background: var(--surface);
|
||
border-right: 1px solid var(--rule);
|
||
display: flex; flex-direction: column;
|
||
padding: 18px 12px;
|
||
align-items: center;
|
||
gap: 4px;
|
||
position: sticky; top: 0;
|
||
height: 100vh;
|
||
}
|
||
.rail__logo {
|
||
width: 44px; height: 44px;
|
||
border-radius: 14px;
|
||
background: var(--tile-ink);
|
||
color: var(--tile-ink-fg);
|
||
display: grid; place-items: center;
|
||
font-family: 'Manrope', sans-serif;
|
||
font-weight: 800;
|
||
font-size: 19px;
|
||
letter-spacing: -0.06em;
|
||
margin-bottom: 16px;
|
||
box-shadow: 0 6px 16px -8px rgba(0,0,0,0.3);
|
||
}
|
||
.rail__btn {
|
||
width: 44px; height: 44px;
|
||
border-radius: 14px;
|
||
border: 0; background: transparent;
|
||
color: var(--ink-dim);
|
||
display: grid; place-items: center;
|
||
cursor: pointer;
|
||
transition: all .15s;
|
||
position: relative;
|
||
}
|
||
.rail__btn svg { width: 20px; height: 20px; }
|
||
.rail__btn:hover { background: var(--bg); color: var(--ink); }
|
||
.rail__btn.is-active {
|
||
background: var(--ink);
|
||
color: var(--surface);
|
||
}
|
||
.rail__btn .badge {
|
||
position: absolute;
|
||
top: 4px; right: 4px;
|
||
min-width: 16px; height: 16px;
|
||
padding: 0 4px;
|
||
border-radius: 8px;
|
||
background: var(--tile-coral);
|
||
color: white;
|
||
font-size: 9px; font-weight: 700;
|
||
display: grid; place-items: center;
|
||
border: 2px solid var(--surface);
|
||
}
|
||
.rail__sep {
|
||
width: 24px; height: 1px;
|
||
background: var(--rule);
|
||
margin: 8px 0;
|
||
}
|
||
.rail__foot {
|
||
margin-top: auto;
|
||
display: flex; flex-direction: column; gap: 4px;
|
||
align-items: center;
|
||
}
|
||
.rail__avatar {
|
||
width: 40px; height: 40px;
|
||
border-radius: 50%;
|
||
background: linear-gradient(135deg, var(--tile-violet), var(--tile-coral));
|
||
color: white;
|
||
display: grid; place-items: center;
|
||
font-weight: 700;
|
||
font-size: 14px;
|
||
border: 3px solid var(--surface);
|
||
box-shadow: 0 0 0 1px var(--rule);
|
||
}
|
||
|
||
/* ============================================================
|
||
MAIN CANVAS
|
||
============================================================ */
|
||
.main { padding: 28px 36px 60px; max-width: 1480px; }
|
||
|
||
/* TOP BAR */
|
||
.topbar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 14px;
|
||
margin-bottom: 28px;
|
||
}
|
||
.crumb {
|
||
font-size: 13px;
|
||
color: var(--mute);
|
||
font-weight: 500;
|
||
}
|
||
.crumb b { color: var(--ink); font-weight: 600; }
|
||
.topbar .grow { flex: 1; }
|
||
.search {
|
||
display: flex; align-items: center; gap: 10px;
|
||
background: var(--surface);
|
||
border: 1px solid var(--rule);
|
||
border-radius: 14px;
|
||
padding: 9px 14px;
|
||
color: var(--mute);
|
||
font-size: 13px;
|
||
width: 280px;
|
||
cursor: text;
|
||
transition: border-color .15s;
|
||
}
|
||
.search:hover { border-color: var(--rule-strong); }
|
||
.search svg { width: 15px; height: 15px; }
|
||
.search .kbd {
|
||
margin-left: auto;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: 10px;
|
||
padding: 2px 6px;
|
||
border-radius: 6px;
|
||
background: var(--bg);
|
||
color: var(--ink-dim);
|
||
}
|
||
.icon-btn {
|
||
width: 40px; height: 40px;
|
||
border-radius: 12px;
|
||
background: var(--surface);
|
||
border: 1px solid var(--rule);
|
||
color: var(--ink-dim);
|
||
display: grid; place-items: center;
|
||
cursor: pointer;
|
||
transition: all .15s;
|
||
}
|
||
.icon-btn:hover { border-color: var(--rule-strong); color: var(--ink); }
|
||
.icon-btn svg { width: 16px; height: 16px; }
|
||
.new-btn {
|
||
display: inline-flex; align-items: center; gap: 8px;
|
||
height: 40px; padding: 0 18px;
|
||
border-radius: 12px;
|
||
background: var(--ink); color: var(--surface);
|
||
border: 0;
|
||
font-family: inherit;
|
||
font-size: 13px; font-weight: 600;
|
||
cursor: pointer;
|
||
transition: transform .15s;
|
||
}
|
||
.new-btn:hover { transform: translateY(-1px); }
|
||
.new-btn svg { width: 14px; height: 14px; }
|
||
|
||
/* HERO TILE */
|
||
.hero {
|
||
background: var(--ink);
|
||
color: var(--surface);
|
||
border-radius: 28px;
|
||
padding: 36px 40px 32px;
|
||
margin-bottom: 16px;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.hero::before {
|
||
content: '';
|
||
position: absolute;
|
||
right: -120px; top: -120px;
|
||
width: 460px; height: 460px;
|
||
border-radius: 50%;
|
||
background: radial-gradient(circle, var(--tile-mint) 0%, transparent 60%);
|
||
opacity: 0.45;
|
||
filter: blur(20px);
|
||
}
|
||
.hero__row {
|
||
display: grid;
|
||
grid-template-columns: 1fr auto;
|
||
align-items: end; gap: 28px;
|
||
position: relative;
|
||
}
|
||
.hero__kicker {
|
||
display: inline-flex; align-items: center; gap: 8px;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: 11px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.18em;
|
||
background: rgba(255,255,255,0.1);
|
||
padding: 6px 12px;
|
||
border-radius: 999px;
|
||
color: var(--tile-mint);
|
||
margin-bottom: 22px;
|
||
}
|
||
.hero__kicker .dot {
|
||
width: 7px; height: 7px;
|
||
border-radius: 50%;
|
||
background: var(--tile-mint);
|
||
animation: ping 1.4s ease-in-out infinite;
|
||
box-shadow: 0 0 8px var(--tile-mint);
|
||
}
|
||
@keyframes ping {
|
||
0%, 100% { transform: scale(1); opacity: 1; }
|
||
50% { transform: scale(1.5); opacity: 0.5; }
|
||
}
|
||
.hero__title {
|
||
font-size: 72px;
|
||
font-weight: 700;
|
||
line-height: 0.96;
|
||
letter-spacing: -0.04em;
|
||
margin: 0 0 16px;
|
||
color: var(--surface);
|
||
max-width: 12ch;
|
||
}
|
||
.hero__title em {
|
||
font-style: normal;
|
||
color: var(--tile-mint);
|
||
}
|
||
.hero__sub {
|
||
font-size: 16px;
|
||
color: rgba(255,255,255,0.72);
|
||
max-width: 480px;
|
||
line-height: 1.5;
|
||
font-weight: 400;
|
||
}
|
||
.hero__sub b { color: var(--surface); font-weight: 600; }
|
||
.hero__big {
|
||
text-align: right;
|
||
}
|
||
.hero__big-label {
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: 11px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.16em;
|
||
color: rgba(255,255,255,0.55);
|
||
margin-bottom: 8px;
|
||
}
|
||
.hero__big-num {
|
||
font-size: 96px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.05em;
|
||
color: var(--tile-mint);
|
||
line-height: 0.9;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
.hero__big-row {
|
||
margin-top: 14px;
|
||
display: flex; gap: 10px;
|
||
justify-content: flex-end;
|
||
}
|
||
.hero-pill {
|
||
display: inline-flex; align-items: center; gap: 6px;
|
||
padding: 5px 12px;
|
||
border-radius: 999px;
|
||
background: rgba(255,255,255,0.1);
|
||
font-size: 12px;
|
||
color: rgba(255,255,255,0.85);
|
||
}
|
||
.hero-pill b {
|
||
color: var(--surface); font-weight: 600;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
/* ============================================================
|
||
BENTO GRID — 12 columns, tiles span as needed
|
||
============================================================ */
|
||
.bento {
|
||
display: grid;
|
||
grid-template-columns: repeat(12, 1fr);
|
||
grid-auto-rows: minmax(140px, auto);
|
||
gap: 16px;
|
||
}
|
||
|
||
.tile {
|
||
border-radius: 24px;
|
||
padding: 22px 24px;
|
||
position: relative;
|
||
overflow: hidden;
|
||
display: flex; flex-direction: column;
|
||
transition: transform .25s cubic-bezier(.4,.4,0,1);
|
||
}
|
||
.tile:hover { transform: translateY(-3px); }
|
||
|
||
.tile--surface { background: var(--surface); border: 1px solid var(--rule); color: var(--ink); }
|
||
.tile--violet { background: var(--tile-violet); color: var(--tile-violet-fg); }
|
||
.tile--mint { background: var(--tile-mint); color: var(--tile-mint-fg); }
|
||
.tile--coral { background: var(--tile-coral); color: var(--tile-coral-fg); }
|
||
.tile--honey { background: var(--tile-honey); color: var(--tile-honey-fg); }
|
||
.tile--cobalt { background: var(--tile-cobalt); color: var(--tile-cobalt-fg); }
|
||
.tile--rose { background: var(--tile-rose); color: var(--tile-rose-fg); }
|
||
.tile--ink { background: var(--tile-ink); color: var(--tile-ink-fg); }
|
||
.tile--bone { background: var(--tile-bone); color: var(--tile-bone-fg); border: 1px solid var(--rule); }
|
||
|
||
.tile__head {
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
margin-bottom: 18px;
|
||
}
|
||
.tile__label {
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: 10.5px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.16em;
|
||
opacity: 0.7;
|
||
font-weight: 500;
|
||
}
|
||
.tile__icon-circle {
|
||
width: 36px; height: 36px;
|
||
border-radius: 12px;
|
||
background: rgba(0,0,0,0.08);
|
||
display: grid; place-items: center;
|
||
}
|
||
.tile--violet .tile__icon-circle, .tile--coral .tile__icon-circle, .tile--cobalt .tile__icon-circle, .tile--ink .tile__icon-circle {
|
||
background: rgba(255,255,255,0.15);
|
||
}
|
||
.tile__icon-circle svg { width: 18px; height: 18px; }
|
||
.tile__num {
|
||
font-size: 56px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.04em;
|
||
line-height: 0.95;
|
||
font-variant-numeric: tabular-nums;
|
||
margin-bottom: 6px;
|
||
margin-top: auto;
|
||
}
|
||
.tile__num .frac { font-size: 28px; opacity: 0.55; font-weight: 600; }
|
||
.tile__caption {
|
||
font-size: 13px;
|
||
line-height: 1.4;
|
||
opacity: 0.85;
|
||
margin-top: 4px;
|
||
}
|
||
.tile__caption b { font-weight: 700; opacity: 1; }
|
||
.tile__delta {
|
||
display: inline-flex; align-items: center; gap: 4px;
|
||
font-size: 11.5px;
|
||
font-weight: 600;
|
||
padding: 3px 9px;
|
||
border-radius: 999px;
|
||
background: rgba(0,0,0,0.10);
|
||
font-variant-numeric: tabular-nums;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
}
|
||
.tile--violet .tile__delta, .tile--coral .tile__delta, .tile--cobalt .tile__delta, .tile--ink .tile__delta {
|
||
background: rgba(255,255,255,0.2);
|
||
}
|
||
|
||
/* SPANS */
|
||
.span-3 { grid-column: span 3; }
|
||
.span-4 { grid-column: span 4; }
|
||
.span-5 { grid-column: span 5; }
|
||
.span-6 { grid-column: span 6; }
|
||
.span-7 { grid-column: span 7; }
|
||
.span-8 { grid-column: span 8; }
|
||
.span-12 { grid-column: span 12; }
|
||
.row-2 { grid-row: span 2; }
|
||
.row-3 { grid-row: span 3; }
|
||
|
||
/* SIGNAL TILE — large, surface */
|
||
.signal-tile { padding: 0; overflow: hidden; }
|
||
.signal-tile__head {
|
||
padding: 22px 26px 14px;
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
}
|
||
.signal-tile__title {
|
||
font-size: 22px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.025em;
|
||
margin: 0;
|
||
}
|
||
.signal-tile__title small {
|
||
font-weight: 500;
|
||
color: var(--mute);
|
||
font-size: 13px;
|
||
margin-left: 8px;
|
||
}
|
||
.seg {
|
||
display: inline-flex; padding: 3px;
|
||
background: var(--bg);
|
||
border-radius: 12px;
|
||
gap: 2px;
|
||
}
|
||
.seg button {
|
||
padding: 6px 12px;
|
||
border: 0; background: transparent;
|
||
color: var(--ink-dim);
|
||
font-family: inherit;
|
||
font-size: 12px; font-weight: 600;
|
||
border-radius: 9px;
|
||
cursor: pointer;
|
||
transition: all .15s;
|
||
}
|
||
.seg button.is-active {
|
||
background: var(--surface);
|
||
color: var(--ink);
|
||
box-shadow: 0 1px 2px rgba(0,0,0,0.06);
|
||
}
|
||
|
||
.signal-list { padding: 0 0 4px; }
|
||
.signal {
|
||
display: grid;
|
||
grid-template-columns: 40px 1fr auto;
|
||
gap: 14px;
|
||
padding: 14px 26px;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
transition: background .15s;
|
||
}
|
||
.signal + .signal { border-top: 1px solid var(--rule); }
|
||
.signal:hover { background: var(--bg); }
|
||
.signal__avatar {
|
||
width: 40px; height: 40px;
|
||
border-radius: 12px;
|
||
display: grid; place-items: center;
|
||
background: var(--avatar-bg, var(--tile-violet));
|
||
color: var(--avatar-fg, white);
|
||
}
|
||
.signal__avatar svg { width: 20px; height: 20px; }
|
||
.signal__head {
|
||
font-size: 14.5px;
|
||
line-height: 1.4;
|
||
color: var(--ink);
|
||
font-weight: 500;
|
||
}
|
||
.signal__head b { font-weight: 700; }
|
||
.signal__head .v { color: var(--ink-dim); font-weight: 400; }
|
||
.signal__sub {
|
||
margin-top: 4px;
|
||
font-size: 12px;
|
||
color: var(--mute);
|
||
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
|
||
}
|
||
.signal__sub .ch {
|
||
color: var(--ink); font-weight: 500;
|
||
background: var(--bg);
|
||
padding: 2px 7px;
|
||
border-radius: 6px;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: 11px;
|
||
}
|
||
.signal__sub .arrow { color: var(--mute); }
|
||
.signal__when {
|
||
text-align: right;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: 11px;
|
||
color: var(--mute);
|
||
}
|
||
.signal__when b {
|
||
display: block;
|
||
color: var(--ink);
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
/* PROVIDER TILES — bold-color blocks */
|
||
.prov-tile {
|
||
cursor: pointer;
|
||
}
|
||
.prov-tile__name {
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.015em;
|
||
display: flex; align-items: center; gap: 8px;
|
||
margin-bottom: 4px;
|
||
}
|
||
.prov-tile__name .pulse {
|
||
width: 8px; height: 8px;
|
||
border-radius: 50%;
|
||
background: currentColor;
|
||
animation: ping 1.6s ease-in-out infinite;
|
||
}
|
||
.prov-tile__sub {
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: 11px;
|
||
opacity: 0.65;
|
||
margin-bottom: auto;
|
||
}
|
||
.prov-tile__num {
|
||
font-size: 36px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.03em;
|
||
line-height: 1;
|
||
font-variant-numeric: tabular-nums;
|
||
margin-top: 16px;
|
||
}
|
||
.prov-tile__num small {
|
||
font-size: 11px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.12em;
|
||
font-weight: 600;
|
||
opacity: 0.65;
|
||
margin-left: 6px;
|
||
}
|
||
|
||
/* WAVE / CHART TILE */
|
||
.chart-tile { padding-bottom: 12px; }
|
||
.chart-tile .tile__head { margin-bottom: 8px; }
|
||
.chart-svg {
|
||
width: 100%; height: 180px; display: block;
|
||
margin-top: 8px;
|
||
}
|
||
.chart-legend {
|
||
display: flex; gap: 18px;
|
||
margin-top: 4px;
|
||
font-size: 11px; color: var(--ink-dim); font-weight: 500;
|
||
}
|
||
.chart-legend span { display: inline-flex; align-items: center; gap: 6px; }
|
||
.chart-legend i {
|
||
display: inline-block; width: 14px; height: 3px; border-radius: 2px;
|
||
}
|
||
|
||
/* WIRES TILE */
|
||
.wires-tile { padding: 22px 26px; }
|
||
.wires-tile .tile__head { margin-bottom: 8px; }
|
||
.wire {
|
||
display: grid;
|
||
grid-template-columns: 1fr auto 1fr;
|
||
gap: 10px;
|
||
align-items: center;
|
||
padding: 10px 0;
|
||
}
|
||
.wire + .wire { border-top: 1px solid var(--rule); }
|
||
.wire__from, .wire__to { font-size: 13px; }
|
||
.wire__to { text-align: right; }
|
||
.wire__name { color: var(--ink); font-weight: 600; }
|
||
.wire__sub { font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--mute); margin-top: 2px; }
|
||
.wire__count {
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
color: var(--ink);
|
||
background: var(--bg);
|
||
padding: 4px 10px;
|
||
border-radius: 999px;
|
||
font-variant-numeric: tabular-nums;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* COMPOSE TILE — full width, surface dark */
|
||
.compose-tile {
|
||
padding: 32px 36px;
|
||
display: grid;
|
||
grid-template-columns: 1fr auto;
|
||
align-items: center;
|
||
gap: 28px;
|
||
}
|
||
.compose-tile__title {
|
||
font-size: 36px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.035em;
|
||
line-height: 1.05;
|
||
margin: 0 0 8px;
|
||
}
|
||
.compose-tile__title em { font-style: normal; color: var(--tile-mint); }
|
||
.compose-tile__sub {
|
||
font-size: 15px;
|
||
opacity: 0.7;
|
||
max-width: 540px;
|
||
line-height: 1.5;
|
||
}
|
||
.compose-tile__cta { display: flex; gap: 10px; }
|
||
.ghost-btn-dark {
|
||
display: inline-flex; align-items: center; gap: 8px;
|
||
padding: 0 18px; height: 44px;
|
||
border-radius: 14px;
|
||
border: 1px solid rgba(255,255,255,0.18);
|
||
background: rgba(255,255,255,0.06);
|
||
color: var(--surface);
|
||
font-family: inherit;
|
||
font-size: 13.5px; font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all .15s;
|
||
}
|
||
.ghost-btn-dark:hover { background: rgba(255,255,255,0.14); }
|
||
.primary-btn-light {
|
||
display: inline-flex; align-items: center; gap: 8px;
|
||
padding: 0 22px; height: 44px;
|
||
border-radius: 14px;
|
||
background: var(--tile-mint);
|
||
color: var(--tile-mint-fg);
|
||
border: 0;
|
||
font-family: inherit;
|
||
font-size: 13.5px; font-weight: 700;
|
||
cursor: pointer;
|
||
transition: transform .15s;
|
||
}
|
||
.primary-btn-light:hover { transform: translateY(-1px); }
|
||
|
||
/* HEALTH TILE — small numerical readout */
|
||
.health-rows { display: flex; flex-direction: column; gap: 10px; margin-top: auto; }
|
||
.health-row {
|
||
display: flex; justify-content: space-between; align-items: center;
|
||
font-size: 13px;
|
||
}
|
||
.health-row .key { color: var(--ink-dim); font-weight: 500; }
|
||
.health-row .val {
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-weight: 600; font-variant-numeric: tabular-nums;
|
||
color: var(--ink);
|
||
}
|
||
.health-row .val .dot {
|
||
display: inline-block; width: 7px; height: 7px;
|
||
border-radius: 50%; margin-right: 6px;
|
||
background: var(--ok);
|
||
}
|
||
|
||
/* CHANNELS TILE — channel chips */
|
||
.channels-grid {
|
||
display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px;
|
||
margin-top: auto;
|
||
}
|
||
.channel-chip {
|
||
display: flex; align-items: center; gap: 9px;
|
||
padding: 10px 12px;
|
||
border-radius: 12px;
|
||
background: rgba(255,255,255,0.12);
|
||
font-size: 12.5px;
|
||
font-weight: 600;
|
||
}
|
||
.tile--bone .channel-chip, .tile--mint .channel-chip, .tile--honey .channel-chip, .tile--rose .channel-chip {
|
||
background: rgba(0,0,0,0.06);
|
||
}
|
||
.channel-chip svg { width: 14px; height: 14px; }
|
||
.channel-chip small {
|
||
margin-left: auto;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-weight: 500; opacity: 0.7;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
/* THEME TOGGLE */
|
||
.theme-toggle {
|
||
position: fixed; right: 24px; top: 24px; z-index: 50;
|
||
background: var(--surface);
|
||
border: 1px solid var(--rule);
|
||
border-radius: 999px;
|
||
padding: 4px;
|
||
display: inline-flex;
|
||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||
}
|
||
.theme-toggle button {
|
||
padding: 7px 14px;
|
||
border: 0; background: transparent;
|
||
color: var(--ink-dim);
|
||
font-family: inherit;
|
||
font-size: 11.5px; font-weight: 600;
|
||
border-radius: 999px;
|
||
cursor: pointer;
|
||
}
|
||
.theme-toggle button.is-active {
|
||
background: var(--ink); color: var(--surface);
|
||
}
|
||
|
||
/* Reveal */
|
||
@keyframes rise {
|
||
from { opacity: 0; transform: translateY(14px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
.stagger > * { animation: rise .55s cubic-bezier(.2,.7,.2,1) both; }
|
||
.stagger > *:nth-child(1){animation-delay:.04s}
|
||
.stagger > *:nth-child(2){animation-delay:.10s}
|
||
.stagger > *:nth-child(3){animation-delay:.16s}
|
||
.stagger > *:nth-child(4){animation-delay:.22s}
|
||
.stagger > *:nth-child(5){animation-delay:.28s}
|
||
.stagger > *:nth-child(6){animation-delay:.34s}
|
||
.stagger > *:nth-child(7){animation-delay:.40s}
|
||
.stagger > *:nth-child(8){animation-delay:.46s}
|
||
.stagger > *:nth-child(9){animation-delay:.52s}
|
||
.stagger > *:nth-child(10){animation-delay:.58s}
|
||
.stagger > *:nth-child(11){animation-delay:.64s}
|
||
.stagger > *:nth-child(12){animation-delay:.70s}
|
||
|
||
/* Responsive */
|
||
@media (max-width: 1240px) {
|
||
.span-3 { grid-column: span 4; }
|
||
.span-4 { grid-column: span 6; }
|
||
.span-5 { grid-column: span 6; }
|
||
.span-7 { grid-column: span 12; }
|
||
.span-8 { grid-column: span 12; }
|
||
}
|
||
@media (max-width: 820px) {
|
||
.shell { grid-template-columns: 1fr; }
|
||
.rail { position: static; height: auto; flex-direction: row; padding: 12px 16px; gap: 6px; }
|
||
.rail__sep { width: 1px; height: 24px; margin: 0 4px; }
|
||
.rail__foot { margin-top: 0; margin-left: auto; flex-direction: row; }
|
||
.main { padding: 18px; }
|
||
.hero { padding: 24px 20px; }
|
||
.hero__row { grid-template-columns: 1fr; }
|
||
.hero__big { text-align: left; }
|
||
.hero__big-row { justify-content: flex-start; }
|
||
.hero__title { font-size: 44px; }
|
||
.hero__big-num { font-size: 64px; }
|
||
.span-3, .span-4, .span-5, .span-6, .span-7, .span-8 { grid-column: span 12; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="theme-toggle">
|
||
<button id="t-light" class="is-active" onclick="setTheme('light')">Daylight</button>
|
||
<button id="t-dark" onclick="setTheme('dark')">Midnight</button>
|
||
</div>
|
||
|
||
<div class="shell">
|
||
|
||
<!-- RAIL -->
|
||
<aside class="rail">
|
||
<div class="rail__logo">N</div>
|
||
<button class="rail__btn is-active" title="Signal">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 12h4l3-9 4 18 3-9h4"/></svg>
|
||
</button>
|
||
<button class="rail__btn" title="Providers">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></svg>
|
||
</button>
|
||
<div class="rail__sep"></div>
|
||
<button class="rail__btn" title="Trackers">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="3"/><circle cx="12" cy="12" r="8"/><path d="M12 4v3M12 17v3M4 12h3M17 12h3"/></svg>
|
||
</button>
|
||
<button class="rail__btn" title="Templates">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 6h16M4 12h16M4 18h10"/></svg>
|
||
</button>
|
||
<button class="rail__btn" title="Targets">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/></svg>
|
||
<span class="badge">2</span>
|
||
</button>
|
||
<button class="rail__btn" title="Actions">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M5 12l3 3 6-6 6 6"/></svg>
|
||
</button>
|
||
<div class="rail__sep"></div>
|
||
<button class="rail__btn" title="Bots">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="4" y="4" width="16" height="16" rx="3"/><circle cx="9" cy="10" r="1.2"/><circle cx="15" cy="10" r="1.2"/><path d="M8 16c1.5 1 6.5 1 8 0"/></svg>
|
||
</button>
|
||
<button class="rail__btn" title="Commands">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 18l5-5 5 5 5-9"/></svg>
|
||
</button>
|
||
|
||
<div class="rail__foot">
|
||
<button class="rail__btn" title="Settings">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/></svg>
|
||
</button>
|
||
<div class="rail__avatar">A</div>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- MAIN -->
|
||
<main class="main">
|
||
|
||
<!-- TOP BAR -->
|
||
<div class="topbar">
|
||
<div class="crumb"><b>Control</b> · Signal overview</div>
|
||
<div class="grow"></div>
|
||
<div class="search">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg>
|
||
Search
|
||
<span class="kbd">⌘K</span>
|
||
</div>
|
||
<button class="icon-btn" title="Notifications">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10 21a2 2 0 0 0 4 0"/></svg>
|
||
</button>
|
||
<button class="new-btn">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M5 12h14M12 5v14"/></svg>
|
||
New tracker
|
||
</button>
|
||
</div>
|
||
|
||
<!-- HERO -->
|
||
<section class="hero">
|
||
<div class="hero__row">
|
||
<div>
|
||
<div class="hero__kicker"><span class="dot"></span>Live · all systems nominal</div>
|
||
<h1 class="hero__title">Tonight, <em>everything</em><br>is flowing.</h1>
|
||
<p class="hero__sub">
|
||
Four providers are listening, twelve trackers are armed, and the bridge has dispatched
|
||
<b>2 814 messages</b> across nineteen targets in the last 24 hours.
|
||
</p>
|
||
</div>
|
||
<div class="hero__big">
|
||
<div class="hero__big-label">throughput · 24h</div>
|
||
<div class="hero__big-num">2 814</div>
|
||
<div class="hero__big-row">
|
||
<span class="hero-pill"><b>99.7%</b> delivered</span>
|
||
<span class="hero-pill"><b>148ms</b> p50</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- BENTO -->
|
||
<section class="bento stagger">
|
||
|
||
<!-- Row 1: 4 stat tiles -->
|
||
<div class="tile tile--violet span-3">
|
||
<div class="tile__head">
|
||
<span class="tile__label">Providers</span>
|
||
<span class="tile__delta">+1</span>
|
||
</div>
|
||
<div class="tile__num">04</div>
|
||
<div class="tile__caption">Immich · Gitea · GitHub · RSS</div>
|
||
</div>
|
||
|
||
<div class="tile tile--mint span-3">
|
||
<div class="tile__head">
|
||
<span class="tile__label">Trackers armed</span>
|
||
<span class="tile__delta">+3 24h</span>
|
||
</div>
|
||
<div class="tile__num">12<span class="frac">/14</span></div>
|
||
<div class="tile__caption"><b>2 paused</b> awaiting credentials</div>
|
||
</div>
|
||
|
||
<div class="tile tile--honey span-3">
|
||
<div class="tile__head">
|
||
<span class="tile__label">Targets</span>
|
||
<span class="tile__delta">+2 wk</span>
|
||
</div>
|
||
<div class="tile__num">19</div>
|
||
<div class="tile__caption">5 channels · TG · Matrix · Mail · ntfy · Discord</div>
|
||
</div>
|
||
|
||
<div class="tile tile--coral span-3">
|
||
<div class="tile__head">
|
||
<span class="tile__label">Failures · 24h</span>
|
||
<span class="tile__delta">−4</span>
|
||
</div>
|
||
<div class="tile__num">02</div>
|
||
<div class="tile__caption">Auto-recovered · SMTP backoff</div>
|
||
</div>
|
||
|
||
<!-- Row 2 — Signal stream (large) + Providers stack (right) -->
|
||
|
||
<div class="tile tile--surface signal-tile span-7 row-3">
|
||
<div class="signal-tile__head">
|
||
<h2 class="signal-tile__title">Signal stream <small>2 814 events / 24h</small></h2>
|
||
<div class="seg">
|
||
<button class="is-active">All</button>
|
||
<button>Assets</button>
|
||
<button>Cmds</button>
|
||
<button>Fails</button>
|
||
</div>
|
||
</div>
|
||
<div class="signal-list">
|
||
|
||
<div class="signal" style="--avatar-bg: var(--tile-violet); --avatar-fg: white;">
|
||
<div class="signal__avatar">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><rect x="3" y="5" width="18" height="14" rx="2.5"/><circle cx="9" cy="11" r="2"/><path d="M3 17l5-5 4 4 3-3 6 6"/></svg>
|
||
</div>
|
||
<div>
|
||
<div class="signal__head"><span class="v">Immich added</span> <b>14 assets</b> <span class="v">to</span> <b>«Семейный 2025»</b></div>
|
||
<div class="signal__sub"><span class="ch">family-photos</span><span class="arrow">→</span><span class="ch">@family · telegram</span><span class="arrow">→</span><span class="ch">assets_added.ru</span></div>
|
||
</div>
|
||
<div class="signal__when"><b>02:14</b>just now</div>
|
||
</div>
|
||
|
||
<div class="signal" style="--avatar-bg: var(--tile-mint); --avatar-fg: var(--tile-mint-fg);">
|
||
<div class="signal__avatar">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><circle cx="12" cy="12" r="9"/><path d="M9 8l3-3 3 3M9 16l3 3 3-3M5 12h14"/></svg>
|
||
</div>
|
||
<div>
|
||
<div class="signal__head"><span class="v">Gitea pushed</span> <b>3 commits</b> <span class="v">to</span> <b>notify-bridge/main</b></div>
|
||
<div class="signal__sub"><span class="ch">repo-changes</span><span class="arrow">→</span><span class="ch">#dev-room · matrix</span></div>
|
||
</div>
|
||
<div class="signal__when"><b>02:13</b>17s ago</div>
|
||
</div>
|
||
|
||
<div class="signal" style="--avatar-bg: var(--tile-cobalt); --avatar-fg: white;">
|
||
<div class="signal__avatar">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><path d="M22 2L11 13M22 2l-7 20-4-9-9-4z"/></svg>
|
||
</div>
|
||
<div>
|
||
<div class="signal__head"><span class="v">Telegram bot received</span> <b>/recent</b> <span class="v">from</span> <b>@alex</b></div>
|
||
<div class="signal__sub"><span class="ch">@notifybridge_bot</span><span class="arrow">→</span><span class="ch">resolved 5 · 142ms</span></div>
|
||
</div>
|
||
<div class="signal__when"><b>02:13</b>36s ago</div>
|
||
</div>
|
||
|
||
<div class="signal" style="--avatar-bg: var(--tile-honey); --avatar-fg: var(--tile-honey-fg);">
|
||
<div class="signal__avatar">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="M8.5 13.5l7 4M8.5 10.5l7-4"/></svg>
|
||
</div>
|
||
<div>
|
||
<div class="signal__head"><span class="v">Immich shared link</span> <b>expired</b> <span class="v">on</span> <b>«Прага 24»</b></div>
|
||
<div class="signal__sub"><span class="ch">link-watch</span><span class="arrow">→</span><span class="ch">photos@dolgolyov.dev · email</span></div>
|
||
</div>
|
||
<div class="signal__when"><b>02:12</b>1m ago</div>
|
||
</div>
|
||
|
||
<div class="signal" style="--avatar-bg: var(--tile-coral); --avatar-fg: white;">
|
||
<div class="signal__avatar">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><path d="M22 4H2l8 9v7l4 2v-9z"/></svg>
|
||
</div>
|
||
<div>
|
||
<div class="signal__head"><span class="v">Email</span> · <b>SMTP retry</b> <span class="v">on</span> <b>smtp.fastmail.com</b></div>
|
||
<div class="signal__sub"><span class="ch">backoff 2.4s</span><span class="arrow">→</span><span class="ch">delivered on attempt 2/3</span></div>
|
||
</div>
|
||
<div class="signal__when"><b>02:11</b>3m ago</div>
|
||
</div>
|
||
|
||
<div class="signal" style="--avatar-bg: var(--tile-rose); --avatar-fg: var(--tile-rose-fg);">
|
||
<div class="signal__avatar">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><rect x="3" y="4" width="18" height="16" rx="3"/><path d="M3 9h18M8 14h2M14 14h2"/></svg>
|
||
</div>
|
||
<div>
|
||
<div class="signal__head"><span class="v">Action</span> <b>memory_dispatch</b> <span class="v">ran for</span> <b>«Один год назад»</b></div>
|
||
<div class="signal__sub"><span class="ch">6 recipients</span><span class="arrow">→</span><span class="ch">2 telegram · 3 matrix · 1 ntfy</span></div>
|
||
</div>
|
||
<div class="signal__when"><b>02:09</b>4m ago</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Provider tiles - right column -->
|
||
<div class="tile tile--cobalt prov-tile span-5">
|
||
<div class="tile__head">
|
||
<span class="tile__label">Top provider</span>
|
||
<div class="tile__icon-circle">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="5" width="18" height="14" rx="2"/><circle cx="9" cy="11" r="2"/><path d="M3 17l5-5 4 4 3-3 6 6"/></svg>
|
||
</div>
|
||
</div>
|
||
<div class="prov-tile__name"><span class="pulse"></span>Immich</div>
|
||
<div class="prov-tile__sub">photos.dolgolyov.dev · 8 trackers</div>
|
||
<div class="prov-tile__num">1 942<small>events 24h</small></div>
|
||
</div>
|
||
|
||
<div class="tile tile--bone prov-tile span-3">
|
||
<div class="tile__head">
|
||
<span class="tile__label">Provider</span>
|
||
<div class="tile__icon-circle">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="9"/><path d="M9 8l3-3 3 3M9 16l3 3 3-3M5 12h14"/></svg>
|
||
</div>
|
||
</div>
|
||
<div class="prov-tile__name"><span class="pulse" style="color: var(--ok)"></span>Gitea</div>
|
||
<div class="prov-tile__sub">git.dolgolyov-family.by</div>
|
||
<div class="prov-tile__num">368<small>24h</small></div>
|
||
</div>
|
||
|
||
<div class="tile tile--bone prov-tile span-2" style="grid-column: span 2;">
|
||
<div class="tile__head">
|
||
<span class="tile__label">RSS</span>
|
||
</div>
|
||
<div class="prov-tile__name" style="font-size: 14px"><span class="pulse" style="color: var(--mute); animation: none; opacity: 0.5"></span>7 feeds</div>
|
||
<div class="prov-tile__sub">idle 14m</div>
|
||
<div class="prov-tile__num" style="font-size: 28px">416</div>
|
||
</div>
|
||
|
||
<!-- Row 3 — chart wide, health, channels -->
|
||
|
||
<div class="tile tile--surface chart-tile span-7">
|
||
<div class="tile__head">
|
||
<span class="tile__label">Pulse · 7 days</span>
|
||
<div class="seg">
|
||
<button>24h</button>
|
||
<button class="is-active">7d</button>
|
||
<button>30d</button>
|
||
</div>
|
||
</div>
|
||
<svg class="chart-svg" viewBox="0 0 700 180" preserveAspectRatio="none">
|
||
<defs>
|
||
<linearGradient id="bg1" x1="0" x2="0" y1="0" y2="1">
|
||
<stop offset="0%" stop-color="#6d4ce6" stop-opacity="0.4"/>
|
||
<stop offset="100%" stop-color="#6d4ce6" stop-opacity="0"/>
|
||
</linearGradient>
|
||
<linearGradient id="bg2" x1="0" x2="0" y1="0" y2="1">
|
||
<stop offset="0%" stop-color="#ff6f5b" stop-opacity="0.35"/>
|
||
<stop offset="100%" stop-color="#ff6f5b" stop-opacity="0"/>
|
||
</linearGradient>
|
||
</defs>
|
||
<path fill="url(#bg1)" d="M0 140 C 70 100, 140 110, 200 80 S 320 60, 380 90 S 500 50, 570 70 S 660 100, 700 80 L 700 180 L 0 180 Z"/>
|
||
<path fill="none" stroke="#6d4ce6" stroke-width="2.5" d="M0 140 C 70 100, 140 110, 200 80 S 320 60, 380 90 S 500 50, 570 70 S 660 100, 700 80"/>
|
||
<path fill="url(#bg2)" d="M0 160 C 80 140, 160 145, 240 130 S 360 120, 420 135 S 540 110, 610 125 S 680 145, 700 135 L 700 180 L 0 180 Z"/>
|
||
<path fill="none" stroke="#ff6f5b" stroke-width="2.5" d="M0 160 C 80 140, 160 145, 240 130 S 360 120, 420 135 S 540 110, 610 125 S 680 145, 700 135"/>
|
||
<line x1="500" y1="20" x2="500" y2="180" stroke="rgba(0,0,0,0.12)" stroke-dasharray="3 3"/>
|
||
<circle cx="500" cy="62" r="6" fill="#6d4ce6" stroke="white" stroke-width="2"/>
|
||
<text x="510" y="44" fill="#0c0d11" font-size="11" font-weight="600" font-family="JetBrains Mono">Sun 21:00 · 312/h</text>
|
||
</svg>
|
||
<div class="chart-legend">
|
||
<span><i style="background:#6d4ce6"></i>Assets · 1 942</span>
|
||
<span><i style="background:#ff6f5b"></i>Commands · 488</span>
|
||
<span><i style="background:#1f9d56"></i>Sharing · 312</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Health tile -->
|
||
<div class="tile tile--ink span-2" style="grid-column: span 2;">
|
||
<div class="tile__head">
|
||
<span class="tile__label">Health</span>
|
||
<div class="tile__icon-circle">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M22 12h-4l-3 9-6-18-3 9H2"/></svg>
|
||
</div>
|
||
</div>
|
||
<div class="health-rows">
|
||
<div class="health-row"><span class="key">Uptime</span><span class="val">14d 06h</span></div>
|
||
<div class="health-row"><span class="key">Queue</span><span class="val">000</span></div>
|
||
<div class="health-row"><span class="key">DB</span><span class="val"><span class="dot"></span>OK</span></div>
|
||
<div class="health-row"><span class="key">SMTP</span><span class="val"><span class="dot"></span>OK</span></div>
|
||
<div class="health-row"><span class="key">Web</span><span class="val"><span class="dot"></span>OK</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Channels tile -->
|
||
<div class="tile tile--rose span-3">
|
||
<div class="tile__head">
|
||
<span class="tile__label">Channels live</span>
|
||
<div class="tile__icon-circle">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/></svg>
|
||
</div>
|
||
</div>
|
||
<div class="channels-grid">
|
||
<div class="channel-chip">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><path d="M22 2L11 13M22 2l-7 20-4-9-9-4z"/></svg>
|
||
Telegram <small>9</small>
|
||
</div>
|
||
<div class="channel-chip">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><rect x="3" y="3" width="18" height="18" rx="2"/></svg>
|
||
Matrix <small>4</small>
|
||
</div>
|
||
<div class="channel-chip">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><path d="M4 4h16v16H4z"/><path d="M4 4l8 8 8-8"/></svg>
|
||
Email <small>3</small>
|
||
</div>
|
||
<div class="channel-chip">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><path d="M12 2a7 7 0 0 0-7 7v5l-2 3h18l-2-3V9a7 7 0 0 0-7-7z"/></svg>
|
||
ntfy <small>2</small>
|
||
</div>
|
||
<div class="channel-chip">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><circle cx="12" cy="12" r="9"/></svg>
|
||
Discord <small>1</small>
|
||
</div>
|
||
<div class="channel-chip" style="opacity: 0.55">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"><path d="M12 5v14M5 12h14"/></svg>
|
||
Add
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Compose tile — full width -->
|
||
<div class="tile tile--ink compose-tile span-12">
|
||
<div>
|
||
<h3 class="compose-tile__title">Pick a source. Choose a channel. <em>Compose the wire.</em></h3>
|
||
<p class="compose-tile__sub">
|
||
The composer walks you from provider → tracker → template → target in four steps,
|
||
with live preview at every stage. Or paste a webhook URL and we'll infer the rest.
|
||
</p>
|
||
</div>
|
||
<div class="compose-tile__cta">
|
||
<button class="ghost-btn-dark">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>
|
||
Import JSON
|
||
</button>
|
||
<button class="primary-btn-light">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
|
||
Start composing
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
</section>
|
||
</main>
|
||
</div>
|
||
|
||
<script>
|
||
function setTheme(t) {
|
||
document.documentElement.setAttribute('data-theme', t);
|
||
document.getElementById('t-light').classList.toggle('is-active', t === 'light');
|
||
document.getElementById('t-dark').classList.toggle('is-active', t === 'dark');
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|