mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
Bundle four pending template skills and retag eight related skills to video/hyperframes so the categorization and i18n fallback coverage can be reviewed and merged in one pass. Co-authored-by: Tuola Ge <gexingli@refly.ai> Co-authored-by: Cursor <cursoragent@cursor.com>
138 lines
9 KiB
HTML
138 lines
9 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
<title>Field Notes Editorial Report Example</title>
|
|
<style>
|
|
:root {
|
|
--paper: #f4f0e8;
|
|
--ink: #181715;
|
|
--ink-soft: rgba(24, 23, 21, 0.72);
|
|
--lime: #c9d57a;
|
|
--pink: #e4b8cc;
|
|
--peach: #e9cbaf;
|
|
--line-pink: #e6a2bc;
|
|
--line-yellow: #ddd06a;
|
|
--line-ink: #1d1d1d;
|
|
--radius: 28px;
|
|
}
|
|
* { box-sizing: border-box; }
|
|
html, body { margin: 0; height: 100%; }
|
|
body {
|
|
font-family: "Avenir Next", "Segoe UI", Inter, sans-serif;
|
|
background: radial-gradient(circle at 50% 40%, #f8f5ee 0%, var(--paper) 65%);
|
|
color: var(--ink);
|
|
}
|
|
.deck { width: min(1280px, 96vw); margin: 22px auto; border-radius: 22px; padding: 30px 30px 84px; position: relative; overflow: hidden; box-shadow: 0 18px 60px rgba(24,23,21,.12); background: var(--paper); }
|
|
.topline { display: flex; justify-content: space-between; color: var(--ink-soft); font-size: 12px; letter-spacing: .14em; text-transform: uppercase; margin-bottom: 18px; }
|
|
.panel { display: none; min-height: 560px; }
|
|
.panel.active { display: block; }
|
|
.metrics-grid { display: grid; grid-template-columns: 1.8fr 1fr; grid-template-rows: 1fr 1fr; gap: 18px; min-height: 520px; }
|
|
.hero, .card { border-radius: var(--radius); padding: 28px; }
|
|
.hero { grid-row: 1 / -1; background: var(--lime); display: flex; flex-direction: column; justify-content: space-between; }
|
|
.hero em { display: block; font-family: Georgia, serif; font-size: 32px; line-height: 1.2; font-style: italic; max-width: 560px; }
|
|
.hero .pct { font-family: Georgia, serif; font-size: 122px; line-height: .9; }
|
|
.card { background: #fff5; display: flex; flex-direction: column; justify-content: flex-end; }
|
|
.card.pink { background: var(--pink); } .card.peach { background: var(--peach); }
|
|
.card .label { font-size: 12px; letter-spacing: .16em; text-transform: uppercase; opacity: .8; }
|
|
.card .num { font-family: Georgia, serif; font-size: 78px; line-height: 1; }
|
|
.insight-grid { min-height: 520px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
|
|
.insight { border-radius: var(--radius); padding: 30px; transition: transform .25s ease, box-shadow .25s ease; }
|
|
.insight:hover { transform: translateY(-4px); box-shadow: 0 14px 34px rgba(24,23,21,.1); }
|
|
.insight h3 { margin: 10px 0 12px; font-size: 28px; font-family: Georgia, serif; }
|
|
.insight p { margin: 0; line-height: 1.6; color: var(--ink-soft); }
|
|
.insight:nth-child(1) { background: var(--pink); } .insight:nth-child(2) { background: var(--lime); } .insight:nth-child(3) { background: var(--peach); }
|
|
.retention { min-height: 520px; display: grid; grid-template-columns: .9fr 1.1fr; gap: 24px; align-items: center; }
|
|
.retention h2 { margin: 0 0 16px; font-size: 64px; line-height: 1.06; font-family: Georgia, serif; }
|
|
.retention p { color: var(--ink-soft); line-height: 1.7; }
|
|
.legend { margin-top: 22px; display: grid; gap: 10px; }
|
|
.legend .row { display: flex; align-items: center; gap: 10px; font-size: 14px; }
|
|
.legend i { width: 24px; height: 4px; border-radius: 2px; display: inline-block; }
|
|
.chart-wrap { background: #fff; border-radius: var(--radius); padding: 20px; box-shadow: 0 14px 44px rgba(24,23,21,.1); }
|
|
.chart-wrap svg { width: 100%; height: auto; display: block; }
|
|
.axis { font-size: 11px; fill: var(--ink-soft); }
|
|
.line { fill: none; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
|
|
.bottom { position: absolute; left: 30px; right: 30px; bottom: 20px; display: flex; justify-content: space-between; align-items: center; color: var(--ink-soft); font-size: 12px; letter-spacing: .08em; }
|
|
.pager { display: inline-flex; align-items: center; gap: 12px; background: #111; color: #f5f1ea; border-radius: 999px; padding: 8px 14px; border: 0; cursor: pointer; }
|
|
.pager:hover { background: #222; }
|
|
@media (max-width: 1100px) { .metrics-grid, .insight-grid, .retention { grid-template-columns: 1fr; } .hero { min-height: 300px; } .hero .pct { font-size: 84px; } .retention h2 { font-size: 44px; } }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<section class="deck">
|
|
<div class="topline"><span>Field Notes</span><span id="page-mark">vi</span></div>
|
|
<div class="panel active" id="panel-metrics">
|
|
<div class="metrics-grid">
|
|
<article class="hero"><em>of new accounts open the third email, up from 41% last quarter.</em><div class="pct" data-count="68">0%</div></article>
|
|
<article class="card pink"><div class="label">Long-form interviews</div><div class="num" data-count="28">0</div></article>
|
|
<article class="card peach"><div class="label">Teams shadowed</div><div class="num" data-count="9">0</div></article>
|
|
</div>
|
|
</div>
|
|
<div class="panel" id="panel-insights">
|
|
<div class="insight-grid">
|
|
<article class="insight"><strong>Insight #1</strong><h3>Trust is the onboarding</h3><p>Customers do not churn on day one because the product is hard. They churn when the early messages feel generic.</p></article>
|
|
<article class="insight"><strong>Insight #2</strong><h3>Power users dread upgrades</h3><p>The most engaged users value predictability. Keep upgrade narratives explicit and avoid surprise resets.</p></article>
|
|
<article class="insight"><strong>Insight #3</strong><h3>Support is product</h3><p>Half of feature requests are discoverability issues. Documentation and UI clarity lower roadmap noise.</p></article>
|
|
</div>
|
|
</div>
|
|
<div class="panel" id="panel-retention">
|
|
<div class="retention">
|
|
<div>
|
|
<h2>The curve bends around day three.</h2>
|
|
<p>Cohorts with a written welcome plus a human follow-up retain roughly 2x better than template-only cohorts by day 90.</p>
|
|
<div class="legend">
|
|
<div class="row"><i style="background:var(--line-pink)"></i><span>Templated welcome</span></div>
|
|
<div class="row"><i style="background:var(--line-yellow)"></i><span>Written welcome</span></div>
|
|
<div class="row"><i style="background:var(--line-ink)"></i><span>Written + human reply</span></div>
|
|
</div>
|
|
</div>
|
|
<div class="chart-wrap">
|
|
<svg viewBox="0 0 560 280" aria-label="Retention line chart">
|
|
<g stroke="rgba(24,23,21,.1)"><line x1="56" y1="40" x2="530" y2="40"></line><line x1="56" y1="90" x2="530" y2="90"></line><line x1="56" y1="140" x2="530" y2="140"></line><line x1="56" y1="190" x2="530" y2="190"></line><line x1="56" y1="240" x2="530" y2="240"></line></g>
|
|
<text class="axis" x="24" y="44">100</text><text class="axis" x="34" y="244">0</text><text class="axis" x="56" y="264">D0</text><text class="axis" x="286" y="264">D30</text><text class="axis" x="506" y="264">D90</text>
|
|
<path class="line" id="line1" stroke="var(--line-pink)" d="M56,52 C146,84 220,140 300,176 C372,205 450,224 530,236"></path>
|
|
<path class="line" id="line2" stroke="var(--line-yellow)" d="M56,52 C150,66 226,104 304,132 C390,156 460,172 530,180"></path>
|
|
<path class="line" id="line3" stroke="var(--line-ink)" d="M56,52 C150,60 230,84 306,100 C392,114 462,126 530,134"></path>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="bottom"><span>April 29, 2026</span><button id="pager" class="pager">◀ <span id="pager-text">6 / 12</span> ▶</button><span>Field Notes · Vol. III</span></div>
|
|
</section>
|
|
<script>
|
|
const panels = ["metrics", "insights", "retention"];
|
|
const marks = { metrics: "vi", insights: "iv", retention: "x" };
|
|
const pagerText = { metrics: "6 / 12", insights: "4 / 12", retention: "10 / 12" };
|
|
let idx = 0;
|
|
function showPanel(next) {
|
|
idx = next % panels.length;
|
|
const key = panels[idx];
|
|
document.querySelectorAll(".panel").forEach((el) => el.classList.remove("active"));
|
|
document.getElementById("panel-" + key).classList.add("active");
|
|
document.getElementById("page-mark").textContent = marks[key];
|
|
document.getElementById("pager-text").textContent = pagerText[key];
|
|
}
|
|
document.getElementById("pager").addEventListener("click", () => showPanel(idx + 1));
|
|
document.querySelectorAll("[data-count]").forEach((el) => {
|
|
const target = Number(el.getAttribute("data-count") || "0");
|
|
let start = null;
|
|
const unit = el.textContent.includes("%") ? "%" : "";
|
|
function tick(ts) {
|
|
if (!start) start = ts;
|
|
const p = Math.min((ts - start) / 900, 1);
|
|
el.textContent = String(Math.round(target * p)) + unit;
|
|
if (p < 1) requestAnimationFrame(tick);
|
|
}
|
|
requestAnimationFrame(tick);
|
|
});
|
|
["line1", "line2", "line3"].forEach((id, i) => {
|
|
const path = document.getElementById(id);
|
|
const len = path.getTotalLength();
|
|
path.style.strokeDasharray = String(len);
|
|
path.style.strokeDashoffset = String(len);
|
|
setTimeout(() => { path.style.transition = "stroke-dashoffset 1s ease"; path.style.strokeDashoffset = "0"; }, 300 + i * 120);
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|