1001 lines
40 KiB
HTML
1001 lines
40 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<meta name="robots" content="noindex, nofollow" />
|
|
<title>Daily Brief — Derez.ai</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=Inter:opsz,wght@14..32,400;14..32,500;14..32,600;14..32,700&display=swap" rel="stylesheet" />
|
|
<style>
|
|
:root {
|
|
--bg: #08080c;
|
|
--bg-card: #0e0e14;
|
|
--bg-inner: #0a0a0f;
|
|
--bg-hover: #16161f;
|
|
--border: #1e1e2a;
|
|
--border-hi: #2a2a3a;
|
|
--accent: #6c8cff;
|
|
--accent-dim: #1a1a3a;
|
|
--danger: #ef4444;
|
|
--danger-dim: #2a1018;
|
|
--success: #22c55e;
|
|
--success-dim: #0a1f12;
|
|
--warning: #f59e0b;
|
|
--warning-dim: #1f1508;
|
|
--text: #e8e8f0;
|
|
--text-muted: #787898;
|
|
--radius: 8px;
|
|
--radius-card: 14px;
|
|
--max-width: 960px;
|
|
}
|
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
html { scroll-behavior: smooth; -webkit-font-smoothing: antialiased; }
|
|
body {
|
|
font-family: "Inter", system-ui, -apple-system, sans-serif;
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
font-size: 14px;
|
|
line-height: 1.7;
|
|
padding: 40px 0;
|
|
}
|
|
a { color: var(--accent); text-decoration: none; }
|
|
a:hover { text-decoration: underline; }
|
|
.container {
|
|
max-width: var(--max-width);
|
|
margin: 0 auto;
|
|
padding: 0 24px;
|
|
}
|
|
code {
|
|
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
font-size: .875em;
|
|
}
|
|
|
|
/* ── Header ──────────────────────────── */
|
|
.header {
|
|
margin-bottom: 32px;
|
|
}
|
|
.header .date {
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
color: var(--text-muted);
|
|
letter-spacing: .02em;
|
|
margin-bottom: 4px;
|
|
}
|
|
.header h1 {
|
|
font-size: 22px;
|
|
font-weight: 700;
|
|
color: var(--text);
|
|
margin-bottom: 4px;
|
|
}
|
|
.header .sub {
|
|
font-size: 13px;
|
|
color: var(--text-muted);
|
|
}
|
|
.badge-row {
|
|
display: flex;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
margin-top: 12px;
|
|
}
|
|
.badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
padding: 3px 12px;
|
|
border-radius: 999px;
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
}
|
|
.badge.live { background: var(--success-dim); color: var(--success); border: 1px solid rgba(34,197,94,.2); }
|
|
.badge.warn { background: var(--warning-dim); color: var(--warning); border: 1px solid rgba(245,158,11,.2); }
|
|
.badge.info { background: var(--accent-dim); color: var(--accent); border: 1px solid rgba(108,140,255,.2); }
|
|
.updated { font-size: 11px; color: var(--text-muted); margin-top: 10px; }
|
|
|
|
/* ── Section ─────────────────────────── */
|
|
.section { margin-bottom: 36px; }
|
|
.section-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-bottom: 0;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
padding: 6px 0;
|
|
}
|
|
.section-header:hover { color: var(--accent); }
|
|
.section-header h2 {
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
}
|
|
.section-header:hover h2 { color: var(--accent); }
|
|
.section-header .count {
|
|
font-size: 12px;
|
|
color: var(--text-muted);
|
|
font-weight: 400;
|
|
}
|
|
.section-toggle {
|
|
color: var(--text-muted);
|
|
font-size: 14px;
|
|
margin-left: auto;
|
|
transition: transform .2s;
|
|
}
|
|
.section-toggle.collapsed { transform: rotate(-90deg); }
|
|
.section-body {
|
|
transition: max-height .25s ease, opacity .15s ease, margin .15s ease;
|
|
overflow: hidden;
|
|
max-height: 0;
|
|
opacity: 0;
|
|
margin: 0;
|
|
}
|
|
.section-body.open {
|
|
max-height: 20000px;
|
|
opacity: 1;
|
|
margin-top: 12px;
|
|
}
|
|
|
|
/* ── Goals Grid ──────────────────────── */
|
|
.goals-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
gap: 12px;
|
|
}
|
|
.goal-card {
|
|
background: var(--bg-card);
|
|
border-radius: var(--radius-card);
|
|
padding: 18px;
|
|
}
|
|
.goal-card .goal-label {
|
|
font-size: 10px;
|
|
font-weight: 500;
|
|
text-transform: uppercase;
|
|
letter-spacing: .06em;
|
|
color: var(--text-muted);
|
|
margin-bottom: 4px;
|
|
}
|
|
.goal-card .goal-current {
|
|
font-size: 26px;
|
|
font-weight: 700;
|
|
color: var(--text);
|
|
line-height: 1.2;
|
|
}
|
|
.goal-card .goal-target {
|
|
font-size: 14px;
|
|
color: var(--text-muted);
|
|
font-weight: 500;
|
|
}
|
|
.goal-card .goal-bar {
|
|
margin-top: 10px;
|
|
height: 4px;
|
|
background: var(--bg-inner);
|
|
border-radius: 2px;
|
|
overflow: hidden;
|
|
}
|
|
.goal-card .goal-bar-fill {
|
|
height: 100%;
|
|
border-radius: 2px;
|
|
transition: width .6s ease;
|
|
}
|
|
.goal-card .goal-bar-fill.green { background: var(--success); }
|
|
.goal-card .goal-bar-fill.blue { background: var(--accent); }
|
|
.goal-card .goal-bar-fill.yellow { background: var(--warning); }
|
|
.goal-card .goal-bar-fill.red { background: var(--danger); }
|
|
.goal-card .goal-sub {
|
|
font-size: 11px;
|
|
color: var(--text-muted);
|
|
margin-top: 4px;
|
|
}
|
|
|
|
/* ── Campaign Cards ──────────────────── */
|
|
.campaign-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr 1fr;
|
|
gap: 12px;
|
|
}
|
|
.campaign-card {
|
|
background: var(--bg-card);
|
|
border-radius: var(--radius-card);
|
|
padding: 18px;
|
|
}
|
|
.campaign-card h3 {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: .04em;
|
|
color: var(--accent);
|
|
margin-bottom: 10px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
.campaign-card .status-tag {
|
|
display: inline-block;
|
|
font-size: 10px;
|
|
padding: 2px 7px;
|
|
border-radius: 4px;
|
|
font-weight: 500;
|
|
}
|
|
.campaign-card .status-tag.active { background: var(--success-dim); color: var(--success); border: 1px solid rgba(34,197,94,.2); }
|
|
.campaign-card .status-tag.paused { background: var(--warning-dim); color: var(--warning); border: 1px solid rgba(245,158,11,.2); }
|
|
.campaign-card .status-tag.draft { background: rgba(120,120,152,.08); color: var(--text-muted); border: 1px solid transparent; }
|
|
.campaign-card .stat-row {
|
|
display: flex;
|
|
gap: 12px;
|
|
margin-bottom: 8px;
|
|
}
|
|
.campaign-card .stat-item {
|
|
text-align: center;
|
|
flex: 1;
|
|
}
|
|
.campaign-card .stat-num {
|
|
font-size: 20px;
|
|
font-weight: 700;
|
|
color: var(--text);
|
|
}
|
|
.campaign-card .stat-label {
|
|
font-size: 9px;
|
|
color: var(--text-muted);
|
|
text-transform: uppercase;
|
|
letter-spacing: .02em;
|
|
}
|
|
.campaign-card ul { list-style: none; margin-top: 6px; }
|
|
.campaign-card li {
|
|
font-size: 12px;
|
|
padding: 4px 0;
|
|
border-bottom: 1px solid rgba(30,30,42,.4);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
.campaign-card li:last-child { border-bottom: none; }
|
|
.campaign-card li .dot {
|
|
width: 6px; height: 6px;
|
|
border-radius: 50%;
|
|
flex-shrink: 0;
|
|
}
|
|
.dot.green { background: var(--success); }
|
|
.dot.red { background: var(--danger); }
|
|
.dot.yellow { background: var(--warning); }
|
|
|
|
/* ── Needs (checkboxes) ──────────────── */
|
|
.needs-card {
|
|
background: var(--bg-card);
|
|
border-radius: var(--radius-card);
|
|
padding: 20px 24px;
|
|
}
|
|
.needs-list { list-style: none; }
|
|
.needs-list li {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 12px;
|
|
padding: 8px 0;
|
|
border-bottom: 1px solid rgba(30,30,42,.4);
|
|
}
|
|
.needs-list li:last-child { border-bottom: none; }
|
|
.need-checkbox {
|
|
width: 20px;
|
|
height: 20px;
|
|
min-width: 20px;
|
|
border: 2px solid var(--border-hi);
|
|
border-radius: 5px;
|
|
flex-shrink: 0;
|
|
margin-top: 2px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
transition: all .15s;
|
|
}
|
|
.need-checkbox:hover { border-color: var(--accent); }
|
|
.need-checkbox.checked {
|
|
background: var(--success);
|
|
border-color: var(--success);
|
|
}
|
|
.need-checkbox.checked::after {
|
|
content: "✓";
|
|
color: #08080c;
|
|
font-size: 14px;
|
|
font-weight: 700;
|
|
}
|
|
.need-item.done .need-text {
|
|
color: var(--text-muted);
|
|
text-decoration: line-through;
|
|
}
|
|
.need-text {
|
|
font-size: 14px;
|
|
color: var(--text);
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* ── Comms ───────────────────────────── */
|
|
.comms-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 12px;
|
|
}
|
|
.comms-card {
|
|
background: var(--bg-card);
|
|
border-radius: var(--radius-card);
|
|
padding: 18px;
|
|
}
|
|
.comms-card h3 {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: .04em;
|
|
color: var(--accent);
|
|
margin-bottom: 10px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
.comms-card .comms-summary {
|
|
display: flex;
|
|
gap: 16px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.comms-card .comms-stat { text-align: center; }
|
|
.comms-card .comms-stat-num {
|
|
font-size: 20px;
|
|
font-weight: 700;
|
|
color: var(--text);
|
|
}
|
|
.comms-card .comms-stat-label {
|
|
font-size: 9px;
|
|
color: var(--text-muted);
|
|
text-transform: uppercase;
|
|
letter-spacing: .02em;
|
|
}
|
|
.comms-list { list-style: none; }
|
|
.comms-list li {
|
|
font-size: 12px;
|
|
padding: 5px 0;
|
|
border-bottom: 1px solid rgba(30,30,42,.4);
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 8px;
|
|
line-height: 1.5;
|
|
}
|
|
.comms-list li:last-child { border-bottom: none; }
|
|
.comms-list .comms-time {
|
|
color: var(--text-muted);
|
|
font-size: 11px;
|
|
white-space: nowrap;
|
|
flex-shrink: 0;
|
|
min-width: 48px;
|
|
}
|
|
.comms-list .comms-subj { color: var(--text); }
|
|
.comms-list .comms-detail {
|
|
color: var(--text-muted);
|
|
font-size: 11px;
|
|
}
|
|
.comms-list .comms-from {
|
|
color: var(--accent);
|
|
font-size: 11px;
|
|
}
|
|
.comms-alert {
|
|
background: var(--danger-dim);
|
|
border: 1px solid rgba(239,68,68,.2);
|
|
border-left: 3px solid var(--danger);
|
|
border-radius: var(--radius);
|
|
padding: 10px 14px;
|
|
margin-top: 8px;
|
|
font-size: 12px;
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 8px;
|
|
}
|
|
.comms-alert .alert-icon { color: var(--danger); flex-shrink: 0; font-size: 14px; }
|
|
.comms-alert .alert-body { color: var(--text); }
|
|
.comms-alert .alert-detail { color: var(--text-muted); font-size: 11px; margin-top: 2px; }
|
|
|
|
/* ── Daily routine ───────────────────── */
|
|
.grid-2 {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 16px;
|
|
}
|
|
.info-card {
|
|
background: var(--bg-card);
|
|
border-radius: var(--radius-card);
|
|
padding: 20px;
|
|
}
|
|
.info-card h3 {
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: .04em;
|
|
color: var(--accent);
|
|
margin-bottom: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
.cron-timeline {
|
|
position: relative;
|
|
padding-left: 24px;
|
|
}
|
|
.cron-timeline::before {
|
|
content: "";
|
|
position: absolute;
|
|
left: 7px;
|
|
top: 4px;
|
|
bottom: 4px;
|
|
width: 2px;
|
|
background: var(--border);
|
|
}
|
|
.cron-item {
|
|
position: relative;
|
|
padding: 4px 0 14px;
|
|
}
|
|
.cron-item::before {
|
|
content: "";
|
|
position: absolute;
|
|
left: -22px;
|
|
top: 8px;
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
background: var(--bg-card);
|
|
border: 2px solid var(--accent);
|
|
}
|
|
.cron-item.primary::before {
|
|
background: var(--accent);
|
|
box-shadow: 0 0 8px rgba(108,140,255,.4);
|
|
}
|
|
.cron-time {
|
|
font-size: 11px;
|
|
color: var(--accent);
|
|
font-weight: 600;
|
|
}
|
|
.cron-title {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
}
|
|
.cron-desc {
|
|
font-size: 12px;
|
|
color: var(--text-muted);
|
|
margin-top: 1px;
|
|
line-height: 1.5;
|
|
}
|
|
.highlight { color: var(--accent); }
|
|
|
|
/* ── Infos ───────────────────────────── */
|
|
.infos-card {
|
|
background: var(--bg-card);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-card);
|
|
padding: 20px 24px;
|
|
}
|
|
.infos-list { list-style: none; }
|
|
.infos-list li {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 10px;
|
|
padding: 7px 0;
|
|
border-bottom: 1px solid rgba(30,30,42,.4);
|
|
font-size: 13px;
|
|
color: var(--text);
|
|
line-height: 1.6;
|
|
}
|
|
.infos-list li:last-child { border-bottom: none; }
|
|
.infos-list li .info-label {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: .04em;
|
|
color: var(--accent);
|
|
white-space: nowrap;
|
|
flex-shrink: 0;
|
|
min-width: 100px;
|
|
}
|
|
.infos-list li .info-value {
|
|
color: var(--text);
|
|
}
|
|
|
|
@media (max-width: 900px) {
|
|
.campaign-grid { grid-template-columns: 1fr; }
|
|
.comms-grid { grid-template-columns: 1fr; }
|
|
.goals-grid { grid-template-columns: repeat(2, 1fr); }
|
|
.grid-2 { grid-template-columns: 1fr; }
|
|
}
|
|
@media (max-width: 500px) {
|
|
.goals-grid { grid-template-columns: 1fr; }
|
|
}
|
|
|
|
/* ── Blog ideas ──────────────────────────── */
|
|
.blog-idea-item {
|
|
display: flex;
|
|
gap: 16px;
|
|
padding: 20px 24px;
|
|
background: #0e0e14;
|
|
border: 1px solid #1a1a2e;
|
|
border-radius: 18px;
|
|
transition: border-color 0.2s, transform 0.2s;
|
|
align-items: flex-start;
|
|
margin-bottom: 16px;
|
|
}
|
|
.blog-idea-item:hover {
|
|
border-color: #6c8cff;
|
|
transform: translateY(-2px);
|
|
}
|
|
.blog-idea-checkbox {
|
|
flex-shrink: 0;
|
|
padding-top: 3px;
|
|
}
|
|
.blog-idea-checkbox input[type="checkbox"] {
|
|
accent-color: #6c8cff;
|
|
width: 17px;
|
|
height: 17px;
|
|
cursor: default;
|
|
}
|
|
.blog-idea-body { flex: 1; min-width: 0; }
|
|
.blog-idea-title {
|
|
font-weight: 700;
|
|
font-size: 16px;
|
|
color: #e8e8f0;
|
|
margin-bottom: 6px;
|
|
}
|
|
.blog-idea-desc {
|
|
font-size: 13px;
|
|
color: #888;
|
|
line-height: 1.7;
|
|
margin-bottom: 10px;
|
|
}
|
|
.blog-idea-meta {
|
|
display: flex;
|
|
gap: 6px;
|
|
flex-wrap: wrap;
|
|
}
|
|
.blog-idea-tag {
|
|
display: inline-block;
|
|
padding: 3px 12px;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
border-radius: 12px;
|
|
background: rgba(108,140,255,0.1);
|
|
color: #6c8cff;
|
|
border: 1px solid rgba(108,140,255,0.15);
|
|
letter-spacing: 0.02em;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
|
|
<!-- ════════ HEADER ════════ -->
|
|
<div class="header">
|
|
<div class="date" id="brief-date">Loading...</div>
|
|
<h1>Daily Brief — Q2 2026</h1>
|
|
<div class="badge-row">
|
|
<span class="badge live">● Site Live</span>
|
|
<span class="badge warn">● Prelaunch</span>
|
|
<span class="badge info">◉ 89 CRM Contacts</span>
|
|
</div>
|
|
<div class="updated" id="brief-updated">Last updated: —</div>
|
|
</div>
|
|
|
|
<!-- ════════ GOALS ════════ -->
|
|
<div class="section">
|
|
<div class="section-header" onclick="toggleSection('goals-section', this)">
|
|
<h2>🎯 Q2/2026 Goals</h2>
|
|
<span class="section-toggle collapsed">▼</span>
|
|
</div>
|
|
<div class="section-body" id="goals-section">
|
|
<div class="goals-grid" id="goals-grid"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ════════ CAMPAIGNS ════════ -->
|
|
<div class="section">
|
|
<div class="section-header" onclick="toggleSection('campaigns-section', this)">
|
|
<h2>📡 Campaigns</h2>
|
|
<span class="section-count count">overview</span>
|
|
<span class="section-toggle collapsed">▼</span>
|
|
</div>
|
|
<div class="section-body" id="campaigns-section">
|
|
<div class="campaign-grid" id="campaign-grid"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ════════ NEEDS ════════ -->
|
|
<div class="section">
|
|
<div class="section-header" onclick="toggleSection('needs-section', this)">
|
|
<h2>📦 Items Needed From You</h2>
|
|
<span class="section-count count">click to check off</span>
|
|
<span class="section-toggle collapsed">▼</span>
|
|
</div>
|
|
<div class="section-body" id="needs-section">
|
|
<div class="needs-card">
|
|
<ul class="needs-list" id="needs-list"></ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ════════ COMMS ════════ -->
|
|
<div class="section">
|
|
<div class="section-header" onclick="toggleSection('comms-section', this)">
|
|
<h2>✉ Communications</h2>
|
|
<span class="section-count count">important only</span>
|
|
<span class="section-toggle collapsed">▼</span>
|
|
</div>
|
|
<div class="section-body" id="comms-section">
|
|
<div class="comms-grid" id="comms-grid"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ════════ INFOS ════════ -->
|
|
<div class="section">
|
|
<div class="section-header" onclick="toggleSection('infos-section', this)">
|
|
<h2>📋 Infos</h2>
|
|
<span class="section-count count">look here for answers</span>
|
|
<span class="section-toggle collapsed">▼</span>
|
|
</div>
|
|
<div class="section-body" id="infos-section">
|
|
<div class="infos-card">
|
|
<ul class="infos-list" id="infos-list"></ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ════════ ROUTINE ════════ -->
|
|
<div class="section">
|
|
<div class="section-header" onclick="toggleSection('routine-section', this)">
|
|
<h2>⏰ Daily Routine</h2>
|
|
<span class="section-toggle collapsed">▼</span>
|
|
</div>
|
|
<div class="section-body" id="routine-section">
|
|
<div class="grid-2">
|
|
<div class="info-card">
|
|
<h3>⏱ 1-Hour Block — 09:00 PYST</h3>
|
|
<div class="cron-timeline">
|
|
<div class="cron-item primary">
|
|
<div class="cron-time">09:00 – 09:05</div>
|
|
<div class="cron-title">Dashboard review</div>
|
|
<div class="cron-desc">Review KPIs & overnight changes</div>
|
|
</div>
|
|
<div class="cron-item primary">
|
|
<div class="cron-time">09:05 – 09:15</div>
|
|
<div class="cron-title">Status sync</div>
|
|
<div class="cron-desc">Check needs, unblock items</div>
|
|
</div>
|
|
<div class="cron-item primary">
|
|
<div class="cron-time">09:15 – 09:45</div>
|
|
<div class="cron-title">Deep work</div>
|
|
<div class="cron-desc">Today's priorities — outreach, content, DMs</div>
|
|
</div>
|
|
<div class="cron-item primary">
|
|
<div class="cron-time">09:45 – 10:00</div>
|
|
<div class="cron-title">Wrap & queue</div>
|
|
<div class="cron-desc">Set tomorrow's priorities, log progress</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="info-card">
|
|
<h3>🤖 Cron Jobs</h3>
|
|
<div class="cron-timeline">
|
|
<div class="cron-item">
|
|
<div class="cron-time">03:00</div>
|
|
<div class="cron-title">📊 Dashboard update</div>
|
|
<div class="cron-desc">KPI snapshot to <code>data/operations.json</code></div>
|
|
</div>
|
|
<div class="cron-item">
|
|
<div class="cron-time">03:10</div>
|
|
<div class="cron-title">📈 SEO tracker</div>
|
|
<div class="cron-desc">Search Console impressions, keyword positions</div>
|
|
</div>
|
|
<div class="cron-item">
|
|
<div class="cron-time">03:20</div>
|
|
<div class="cron-title">🔗 Backlink monitor</div>
|
|
<div class="cron-desc">New referring domains flagged</div>
|
|
</div>
|
|
<div class="cron-item">
|
|
<div class="cron-time">03:30</div>
|
|
<div class="cron-title">💬 Social monitor</div>
|
|
<div class="cron-desc">Brand mentions & replies</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ════════ BLOG IDEAS ════════ -->
|
|
<div class="section">
|
|
<div class="section-header" onclick="toggleSection('blog-ideas-section', this)">
|
|
<h2>📝 Blog Post Ideas</h2>
|
|
<span class="section-count count">research notes in blog/ideas/</span>
|
|
<span class="section-toggle collapsed">▼</span>
|
|
</div>
|
|
<div class="section-body" id="blog-ideas-section">
|
|
<div class="blog-idea-item">
|
|
<div class="blog-idea-checkbox">
|
|
<input type="checkbox" />
|
|
</div>
|
|
<div class="blog-idea-body">
|
|
<div class="blog-idea-title">#001 — Why backing up an agent is so hard</div>
|
|
<div class="blog-idea-desc">After running all speed-runs (including competitor profiling), the system grew to 6.8G — with 69% outside /root. New data: dual-snapshot comparison showing sprawl worsens over time. Points to the competitor profiling speed-run as the trigger that pushed past 1G.</div>
|
|
<div class="blog-idea-meta">
|
|
<span class="blog-idea-tag">Technical</span>
|
|
<span class="blog-idea-tag">Backups</span>
|
|
<span class="blog-idea-tag">DevOps</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
/* ════════ DATA ════════ */
|
|
const goals = [
|
|
{ id: 'active-contacts', label: 'Active Contacts', current: 1, target: 60, note: 'CRM Cold → Won (88 on Hold excluded)' },
|
|
{ id: 'subscriptions', label: 'Subscriptions', current: 0, target: 50, note: 'Paying customers' },
|
|
{ id: 'influencers', label: 'Influencers', current: 0, target: 20, note: 'YT creators & affiliates' },
|
|
{ id: 'visitors', label: 'Page Visitors', current: 0, target: 10000, unit: '/mo', note: 'Monthly unique visitors' },
|
|
{ id: 'outreach-sent', label: 'Cold Emails Sent', current: 0, target: 100, note: 'First touch sent' },
|
|
{ id: 'crm-contacts', label: 'CRM Contacts', current: 89, target: 200, note: 'Total collected' },
|
|
];
|
|
|
|
const campaigns = [
|
|
{
|
|
label: '✉ Cold Mail', status: 'draft',
|
|
metrics: [{ v: 0, l: 'Drafted' }, { v: 0, l: 'Sent' }, { v: 0, l: 'Replied' }],
|
|
items: [
|
|
{ t: 'Coupons ready: friends950, creator950', ok: true },
|
|
{ t: 'Template signed as Mark', ok: true },
|
|
{ t: 'No contacts with real emails yet', ok: false },
|
|
]
|
|
},
|
|
{
|
|
label: '🎙 Influencer', status: 'paused',
|
|
metrics: [{ v: 60, l: 'Identified' }, { v: 0, l: 'Contacted' }, { v: 0, l: 'Onboarded' }],
|
|
items: [
|
|
{ t: '60 YT creators on Hold', ok: true },
|
|
{ t: 'Need business emails for top 20', ok: false },
|
|
{ t: 'Affiliate program TBD', ok: false },
|
|
]
|
|
},
|
|
{
|
|
label: '🔗 LinkedIn', status: 'draft',
|
|
metrics: [{ v: 0, l: 'Connections' }, { v: 0, l: 'Outreach' }, { v: 0, l: 'Replied' }],
|
|
items: [
|
|
{ t: 'No outreach started', ok: false },
|
|
{ t: 'Company page TBD', ok: false },
|
|
{ t: 'No content strategy defined', ok: false },
|
|
]
|
|
},
|
|
{
|
|
label: '🌐 SEO & Traffic', status: 'draft',
|
|
metrics: [{ v: 0, l: 'Visitors/mo' }, { v: 0, l: 'Blog Posts' }, { v: 0, l: 'Backlinks' }],
|
|
items: [
|
|
{ t: 'Plausible analytics live with 7 custom events', ok: true },
|
|
{ t: 'Need Google Search Console submission', ok: false },
|
|
{ t: 'Need blog posts (guest posts + own content)', ok: false },
|
|
{ t: 'Directory listings: Product Hunt, BetaList, G2', ok: false },
|
|
]
|
|
},
|
|
{
|
|
label: '🔗 Backlinks', status: 'draft',
|
|
metrics: [{ v: 0, l: 'Quality Links' }, { v: 0, l: 'Ref Domains' }, { v: 0, l: 'Guest Posts' }],
|
|
target: { links: 10, domains: 5, posts: 3 },
|
|
items: [
|
|
{ t: 'Need competitor backlink gap analysis', ok: false },
|
|
{ t: 'Guest post pitches to AI/DevOps blogs', ok: false },
|
|
{ t: 'HARO / Qwoted alerts for journalist queries', ok: false },
|
|
{ t: 'Directory submissions: Product Hunt, BetaList, G2', ok: false },
|
|
]
|
|
}
|
|
];
|
|
|
|
/* Top 5 needs — 2 done after Oliver's last update */
|
|
const NEEDS = [
|
|
{ id: "n1", text: "Business emails for top 20 YouTube creators — blocking cold email outreach", done: false },
|
|
{ id: "n2", text: "Coupon codes ready: creator950 ($9.50), friends950 ($9.50) — unlimited, includes OpenRouter credits", done: true },
|
|
{ id: "n3", text: "Product demo video (3 min screen recording)", done: false },
|
|
{ id: "n4", text: "Social media account access (X/Twitter + LinkedIn posting)", done: false },
|
|
{ id: "n5", text: "'Why I built Derez.ai' story — available on homepage", done: true },
|
|
];
|
|
|
|
/* ── Infos (action plan: 10K visitors/mo) ── */
|
|
const infos = [
|
|
{ label: 'YouTube Channel', value: '<a href="https://www.youtube.com/@derez_ai" target="_blank" style="color:#00f5ff">youtube.com/@derez_ai</a> — Deploy your own AI agent in 5 minutes. Speed runs, tutorials, Odoo integrations, and AI agent demos. Banner saved at assets/images/youtube-banner.svg (2048x1152).' },
|
|
{ label: 'Why not start?', value: 'No Search Console access yet — can\'t index site. No blog content drafted. No directory submissions. Need to unblock these first, then launch is days not weeks.' },
|
|
{ label: 'Blog Strategy', value: '2 posts/week minimum. Topics: "Deploy AI agents in 5 min" (tutorial), "Hermes agent setup guide" (tutorial), "Why agent hosting beats DIY" (comparison), "Cold email automation stack" (case study). Cross-post to Medium/Dev.to. Each post = 1 backlink target + long-tail SEO. Start with 4 cornerstone posts before directory submissions.' },
|
|
{ label: 'Phase 1 (Week 1)', value: 'Get Search Console access. Draft 2 cornerstone blog posts. Submit to Product Hunt + BetaList + AlternativeTo. Set up HARO/Qwoted alerts.' },
|
|
{ label: 'Phase 2 (Week 2)', value: 'Publish 2 posts. Guest post pitch to 5 AI/DevOps blogs. Start LinkedIn company page + 50 connection requests/week.' },
|
|
{ label: 'Phase 3 (Week 3-4)', value: 'Publish 4 more posts. Follow up guest post pitches. Directory listings done. Target: 500 unique visitors by end of month.' },
|
|
{ label: '10K Breakdown', value: 'SEO (organic): 40% = 4K. Direct/referral (directory + backlinks): 25% = 2.5K. Social (LinkedIn/X): 20% = 2K. Email/newsletter: 15% = 1.5K. Realistic 3-4 month trajectory.' },
|
|
];
|
|
|
|
/* ── Filtered comms — spam/sales/ads/work-for-you removed ── */
|
|
function isSpam(email) {
|
|
const lower = (email.subj + ' ' + email.from + ' ' + (email.detail || '')).toLowerCase();
|
|
const spamPatterns = [
|
|
'spam', 'advertisement', 'advert', 'work for you', 'work from home',
|
|
'make money', 'earn', 'investment opportunity', 'click here',
|
|
'buy now', 'limited offer', 'free money', 'congratulations',
|
|
'you\'ve won', 'marketing offer', 'promotion', 'partner offer',
|
|
'guest post', 'seo services', 'link building', 'content writing services',
|
|
];
|
|
return spamPatterns.some(p => lower.includes(p));
|
|
}
|
|
|
|
const rawInbox = [
|
|
{ id: 'i1', time: '14:44', from: 'Mail Delivery System', subj: 'Undelivered — the@123.de', detail: '421 Downstream server error — cold email bounced', alert: true, spam: true },
|
|
{ id: 'i2', time: '21:04', from: 'Mail Delivery System', subj: 'Undelivered — the@123.de', detail: '421 Downstream server error', alert: false, spam: true },
|
|
{ id: 'i3', time: '08:12', from: 'seo@boostmyrank.xyz', subj: 'Guest post opportunity for your site', detail: 'Wants to publish sponsored content', spam: true },
|
|
{ id: 'i4', time: '19:33', from: 'hannah@freelance.io', subj: 'I can help with your content marketing', detail: 'Offering writing services', spam: true },
|
|
];
|
|
|
|
const rawSent = [
|
|
{ time: 'Jun 09', to: 'o.arnold@projektbox.de', subj: 'setting up an agent for projektbox', spam: false },
|
|
{ time: 'Jun 08', to: 'oliver@odoo4projects.com', subj: 'managing your agents without SSH', spam: false },
|
|
];
|
|
|
|
const comms = {
|
|
inbox: {
|
|
total: rawInbox.filter(i => !i.spam).length,
|
|
total_spam_ignored: rawInbox.filter(i => i.spam).length,
|
|
items: rawInbox.filter(i => !i.spam),
|
|
},
|
|
sent: {
|
|
total: rawSent.filter(i => !i.spam).length,
|
|
items: rawSent.filter(i => !i.spam),
|
|
top_sent: 'Mark — Customer Success Agent'
|
|
},
|
|
note: 'Spam/sales filtered out. Only actionable items shown.'
|
|
};
|
|
|
|
/* ════════ RENDER ════════ */
|
|
function fmtTimestamp(date) {
|
|
const d = date || new Date();
|
|
const y = d.getFullYear();
|
|
const mo = String(d.getMonth() + 1).padStart(2, '0');
|
|
const day = String(d.getDate()).padStart(2, '0');
|
|
const h = String(d.getHours()).padStart(2, '0');
|
|
const mi = String(d.getMinutes()).padStart(2, '0');
|
|
return `${y}-${mo}-${day} ${h}:${mi}`;
|
|
}
|
|
|
|
function pct(cur, target) { return target > 0 ? Math.min(100, Math.round(cur / target * 100)) : 0; }
|
|
function barClass(p) { return p >= 80 ? 'green' : p >= 40 ? 'blue' : p >= 20 ? 'yellow' : 'red'; }
|
|
|
|
function toggleSection(id, header) {
|
|
const el = document.getElementById(id);
|
|
const toggle = header.querySelector('.section-toggle');
|
|
el.classList.toggle('open');
|
|
toggle.classList.toggle('collapsed');
|
|
}
|
|
|
|
function renderGoals() {
|
|
document.getElementById('goals-grid').innerHTML = goals.map(g => {
|
|
const p = pct(g.current, g.target);
|
|
const bc = barClass(p);
|
|
return `<div class="goal-card">
|
|
<div class="goal-label">${g.label}</div>
|
|
<div class="goal-current">${g.current}<span class="goal-target"> / ${g.target}${g.unit ? ' ' + g.unit : ''}</span></div>
|
|
<div class="goal-bar"><div class="goal-bar-fill ${bc}" style="width:${p}%"></div></div>
|
|
<div class="goal-sub">${g.note}</div>
|
|
</div>`;
|
|
}).join('');
|
|
}
|
|
|
|
function renderCampaigns() {
|
|
document.getElementById('campaign-grid').innerHTML = campaigns.map(c => {
|
|
const st = c.status === 'active' ? '<span class="status-tag active">● Active</span>'
|
|
: c.status === 'paused' ? '<span class="status-tag paused">● Paused</span>'
|
|
: '<span class="status-tag draft">Draft</span>';
|
|
return `<div class="campaign-card">
|
|
<h3>${c.label} ${st}</h3>
|
|
<div class="stat-row">${c.metrics.map(m => `<div class="stat-item"><div class="stat-num">${m.v}</div><div class="stat-label">${m.l}</div></div>`).join('')}</div>
|
|
${c.target ? `<div style="font-size:10px;color:var(--text-muted);margin-bottom:6px;">Target: ${c.target.links} quality links, ${c.target.domains} referring domains, ${c.target.posts} guest posts</div>` : ''}
|
|
<ul>${c.items.map(i => `<li><span class="dot ${i.ok ? 'green' : 'red'}"></span>${i.t}</li>`).join('')}</ul>
|
|
</div>`;
|
|
}).join('');
|
|
}
|
|
|
|
/* ── Needs (checkboxes) ── */
|
|
function getNeeds() {
|
|
try {
|
|
const saved = localStorage.getItem("derez-needs");
|
|
if (saved) {
|
|
const parsed = JSON.parse(saved);
|
|
return NEEDS.map(def => {
|
|
const s = parsed.find(p => p.id === def.id);
|
|
return s ? { ...def, done: s.done } : def;
|
|
});
|
|
}
|
|
} catch(e) {}
|
|
return NEEDS;
|
|
}
|
|
function toggleNeed(id) {
|
|
const needs = getNeeds();
|
|
const idx = needs.findIndex(n => n.id === id);
|
|
if (idx === -1) return;
|
|
needs[idx].done = !needs[idx].done;
|
|
localStorage.setItem("derez-needs", JSON.stringify(needs));
|
|
renderNeeds(needs);
|
|
}
|
|
function renderNeeds(needs) {
|
|
const list = document.getElementById("needs-list");
|
|
list.innerHTML = needs.map(n => `
|
|
<li class="need-item${n.done ? ' done' : ''}">
|
|
<span class="need-checkbox${n.done ? ' checked' : ''}" data-id="${n.id}" onclick="toggleNeed('${n.id}')"></span>
|
|
<span class="need-text">${n.text}</span>
|
|
</li>
|
|
`).join("");
|
|
}
|
|
|
|
function renderCommunications() {
|
|
const c = comms;
|
|
const inboxItems = c.inbox.items.map(i =>
|
|
`<li><span class="comms-time">${i.time}</span><span><span class="comms-from">${i.from}</span><br><span class="comms-subj">${i.subj}</span>${i.detail ? ' <span class="comms-detail">' + i.detail + '</span>' : ''}</span></li>`
|
|
).join('');
|
|
const alerts = c.inbox.items.filter(i => i.alert).map(a =>
|
|
`<div class="comms-alert"><span class="alert-icon">⚠</span><div><div class="alert-body">${a.body || a.subj}</div><div class="alert-detail">${a.detail || ''}</div></div></div>`
|
|
).join('');
|
|
const sentItems = c.sent.items.map(i =>
|
|
`<li><span class="comms-time">${i.time}</span><span><span class="comms-from">${i.to}</span><br><span class="comms-subj">${i.subj}</span></span></li>`
|
|
).join('');
|
|
|
|
const spamNote = comms.inbox.total_spam_ignored > 0
|
|
? `<div style="margin-top:8px;font-size:11px;color:var(--text-muted);">🧹 ${comms.inbox.total_spam_ignored} spam/sales filtered out</div>`
|
|
: '';
|
|
|
|
document.getElementById('comms-grid').innerHTML =
|
|
`<div class="comms-card">
|
|
<h3>📥 Inbox</h3>
|
|
<div class="comms-summary">
|
|
<div class="comms-stat"><div class="comms-stat-num">${c.inbox.total}</div><div class="comms-stat-label">Actionable</div></div>
|
|
<div class="comms-stat"><div class="comms-stat-num">${c.inbox.items.filter(i => i.alert).length}</div><div class="comms-stat-label">Alerts</div></div>
|
|
</div>
|
|
<ul class="comms-list">${inboxItems}</ul>
|
|
${alerts}
|
|
${spamNote}
|
|
</div>
|
|
<div class="comms-card">
|
|
<h3>📤 Sent</h3>
|
|
<div class="comms-summary">
|
|
<div class="comms-stat"><div class="comms-stat-num">${c.sent.total}</div><div class="comms-stat-label">Sent</div></div>
|
|
</div>
|
|
<ul class="comms-list">${sentItems}</ul>
|
|
<div style="margin-top:8px;font-size:11px;color:var(--text-muted);">
|
|
From: ${c.sent.top_sent} · ${c.note}
|
|
</div>
|
|
</div>`;
|
|
}
|
|
|
|
function renderInfos() {
|
|
document.getElementById('infos-list').innerHTML = infos.map(i =>
|
|
`<li><span class="info-label">${i.label}</span><span class="info-value">${i.value}</span></li>`
|
|
).join('');
|
|
}
|
|
|
|
async function fetchLiveData() {
|
|
try {
|
|
const res = await fetch('data/operations.json?t=' + Date.now());
|
|
if (!res.ok) throw new Error('Not found');
|
|
const d = await res.json();
|
|
if (d.date) document.getElementById('brief-date').textContent = d.date;
|
|
if (d.updated) document.getElementById('brief-updated').textContent = 'Last updated: ' + d.updated;
|
|
if (d.goals) d.goals.forEach((g, i) => { if (goals[i]) { goals[i].current = g.current; goals[i].note = g.note || goals[i].note; } });
|
|
renderGoals();
|
|
} catch { /* defaults */ }
|
|
}
|
|
|
|
/* ── Init ── */
|
|
document.getElementById('brief-date').textContent = fmtTimestamp();
|
|
renderGoals();
|
|
renderCampaigns();
|
|
renderNeeds(getNeeds());
|
|
renderCommunications();
|
|
renderInfos();
|
|
fetchLiveData();
|
|
</script>
|
|
</body>
|
|
</html> |