295 lines
20 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<!--
project-artifact template — a self-contained status page for a multi-workstream project.
Domain-neutral. For software projects (workstreams = PRs), also read swe.md — it has
the PR-sequence table and per-PR detail HTML fragments to paste in.
HOW TO USE
1. Copy this file to a stable path as <kebab-project-name>.html (the <title> names the
artifact; the basename is the fallback if <title> is missing), and DELETE this HOW TO
USE comment block from your copy (don't leave it in the published page).
2. Fill in the placeholder slots — the HTML comments tagged "FILL:", plus the plain-text
PROJECT_NAME in <title> and <h1>. Delete the tabs you don't have real content for; if
you delete one, renumber the remaining tab buttons (1, 2, 3 …).
3. The <body> below uses TAB MECHANISM B (a tiny `<script>` toggles `.pane` divs) —
it scales to any number of tabs with zero per-tab CSS, and it's what every real
page built this way uses. If you want a no-JS page AND have a small fixed tab count, swap in TAB MECHANISM A
(pure-CSS radio tabs) — the full skeleton for it is in the big comment block right
after <body>. (Mechanism A needs each tab id added to TWO `:checked ~ …` selector
lists in the CSS; forget one and the tab silently won't show. That's why B is the
default here.)
4. Publish: see SKILL.md ("Publish with the Artifact tool") — you'll also need a
favicon emoji (keep it the same on every redeploy).
The CSS below is the shared house style (light/dark via prefers-color-scheme, CSS
variables, status pills). Tweak colors, not structure.
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>PROJECT_NAME — status</title>
<style>
:root { --fg:#1a1a1a; --bg:#fdfdfd; --accent:#0a7d4a; --warn:#b45309; --red:#b91c1c; --muted:#666; --border:#ddd; --code-bg:#f5f5f5; }
@media (prefers-color-scheme: dark) {
:root { --fg:#e4e4e4; --bg:#1a1a1a; --accent:#4ade80; --warn:#fbbf24; --red:#f87171; --muted:#999; --border:#333; --code-bg:#262626; }
}
* { box-sizing:border-box; }
body { font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; color:var(--fg); background:var(--bg); max-width:980px; margin:1.5em auto; padding:0 1.5em 3em; }
h1,h2,h3,h4 { font-weight:600; margin-top:1.6em; line-height:1.3; }
h1 { font-size:1.7em; margin-bottom:.2em; }
h2 { font-size:1.35em; border-bottom:1px solid var(--border); padding-bottom:.2em; }
h3 { font-size:1.1em; }
a { color:var(--accent); }
code { background:var(--code-bg); padding:.15em .35em; border-radius:3px; font-size:.92em; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
pre { background:var(--code-bg); padding:1em 1.2em; border-radius:6px; overflow-x:auto; font-size:.87em; line-height:1.5; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
pre code { background:none; padding:0; }
table { border-collapse:collapse; width:100%; margin:.8em 0; font-size:.93em; }
th,td { border:1px solid var(--border); padding:.45em .7em; vertical-align:top; text-align:left; }
th { font-weight:600; background:var(--code-bg); }
ul { padding-left:1.4em; } li { margin:.25em 0; }
details { margin:.5em 0; } details > summary { cursor:pointer; font-weight:600; padding:.4em 0; }
hr { border:none; border-top:1px solid var(--border); margin:2em 0; }
.meta { color:var(--muted); font-size:.85em; }
.sub { color:var(--muted); font-size:.95em; margin-top:.3em; }
/* status banner */
.status { background:color-mix(in srgb, var(--accent) 12%, var(--bg)); border:1px solid var(--accent); border-radius:8px; padding:.9em 1.2em; margin:1.2em 0; }
.status .badge { display:inline-block; background:var(--accent); color:var(--bg); padding:.1em .6em; border-radius:4px; font-size:.78em; font-weight:600; letter-spacing:.02em; }
.status p { margin:.5em 0 0; font-size:.92em; }
/* next-steps strip — sits under the status banner, above the tabs, so it shows on every tab.
It's a <details open> so the reader can collapse it; the summary keeps the item count visible. */
.next { border:1px solid var(--warn); border-left:4px solid var(--warn); border-radius:8px; padding:.8em 1.2em; margin:1.2em 0; background:color-mix(in srgb, var(--warn) 8%, var(--bg)); }
.next > summary { cursor:pointer; font-weight:600; font-size:1.02em; padding:0; }
.next > summary .meta { font-weight:400; }
.next ol { margin:.5em 0 .1em 1.3em; padding:0; }
.next ol li { margin:.3em 0; }
.next .who { font-weight:600; }
.next p.none { margin:.5em 0 .1em; font-size:.93em; }
/* pills — solid fills (text in var(--bg) so contrast clears WCAG AA in both light and dark);
four distinct hues: accent/done, warn/now, neutral/next, red/warn(blocked) */
.pill { display:inline-block; font-size:.78em; padding:.1em .55em; border-radius:10px; background:var(--code-bg); color:var(--muted); margin-left:.4em; vertical-align:1px; }
.pill.done { background:var(--accent); color:var(--bg); } /* done / tested ✓ / verified ✓ */
.pill.now { background:var(--warn); color:var(--bg); } /* in progress / in review */
.pill.next { background:var(--code-bg); color:var(--fg); border:1px solid var(--border); } /* next / planned */
.pill.warn { background:var(--red); color:var(--bg); } /* blocked / ⚠ caveat */
.callout { border:1px solid var(--border); border-left:3px solid var(--accent); border-radius:4px; padding:.7em 1em; margin:1em 0; font-size:.93em; background:color-mix(in srgb, var(--accent) 5%, var(--bg)); }
/* ── TAB MECHANISM B (default in the <body> below): JS toggles .pane divs. Scales to
any tab count; no per-tab CSS. ── */
.tabbar { display:flex; flex-wrap:wrap; gap:.2em; border-bottom:2px solid var(--border); margin:1.2em 0 1.5em; }
.tabbar .tab { padding:.55em 1em; cursor:pointer; border:1px solid transparent; border-bottom:none; border-radius:6px 6px 0 0; font:inherit; font-weight:500; font-size:.95em; color:var(--muted); background:none; margin-bottom:-2px; }
.tabbar .tab:hover { color:var(--fg); }
.tabbar .tab.active { color:var(--fg); border-color:var(--border); border-bottom:2px solid var(--bg); background:var(--bg); font-weight:600; }
.pane { display:none; } .pane.active { display:block; }
/* ── TAB MECHANISM A (no-JS alternative; see the comment block after <body>): pure-CSS
radio tabs. Each tab id MUST appear in BOTH rule-lists below (all 7 catalog tabs are listed). ── */
.tabs > input { display:none; }
.tabs > nav { display:flex; flex-wrap:wrap; gap:.2em; border-bottom:2px solid var(--border); margin:1.2em 0 1.5em; }
.tabs > nav > label { padding:.55em 1em; cursor:pointer; border:1px solid transparent; border-bottom:none; border-radius:6px 6px 0 0; font-weight:500; color:var(--muted); margin-bottom:-2px; user-select:none; font-size:.95em; }
.tabs > nav > label:hover { color:var(--fg); }
.tabs > section { display:none; }
#t-over:checked ~ nav label[for=t-over], #t-work:checked ~ nav label[for=t-work], #t-att:checked ~ nav label[for=t-att],
#t-bg:checked ~ nav label[for=t-bg], #t-plan:checked ~ nav label[for=t-plan], #t-risk:checked ~ nav label[for=t-risk],
#t-faq:checked ~ nav label[for=t-faq]
{ color:var(--fg); border-color:var(--border); border-bottom:2px solid var(--bg); background:var(--bg); font-weight:600; }
#t-over:checked ~ section#s-over, #t-work:checked ~ section#s-work, #t-att:checked ~ section#s-att,
#t-bg:checked ~ section#s-bg, #t-plan:checked ~ section#s-plan, #t-risk:checked ~ section#s-risk,
#t-faq:checked ~ section#s-faq
{ display:block; }
</style>
</head>
<body>
<!-- ╔══════════════════════════════════════════════════════════════════════════════╗
║ TAB MECHANISM A (no-JS alternative). To use it instead of B: delete the ║
║ <main>…</main> + <script> below and the .tabbar, and use this shape: ║
║ ║
║ <div class="tabs"> ║
║ <input type="radio" name="tab" id="t-over" checked> ║
║ <input type="radio" name="tab" id="t-work"> … (one per tab) ║
║ <nav> ║
║ <label for="t-over">Overview</label> ║
║ <label for="t-work">Workstreams</label> … (one per tab) ║
║ </nav> ║
║ <section id="s-over"> …Overview content… </section> ║
║ <section id="s-work"> …Workstreams content… </section> … ║
║ </div> ║
║ ║
║ Add/remove a tab => ALSO add/remove its id in BOTH `:checked ~ …` rule-lists ║
║ in the CSS above (the "TAB MECHANISM A" block). Miss one and the tab won't ║
║ show. (This footgun is why B is the default.) ║
╚══════════════════════════════════════════════════════════════════════════════╝ -->
<header>
<h1>PROJECT_NAME</h1>
<div class="sub"><!-- FILL: one-line description -->
&middot; <a href="#"><!-- FILL: link to design doc / plan / spec, or delete --> Plan &rarr;</a>
&middot; <a href="#"><!-- FILL: link to a sibling doc, or delete --> Background &rarr;</a>
</div>
</header>
<!-- STATUS BANNER — keep this. One line: phase · lead workstream · a size/health number or two · any gate.
The as-of timestamp is mandatory: it's how readers calibrate everything else. -->
<div class="status">
<span class="badge"><!-- FILL: STATUS · PHASE 1 OF 3 --></span>
<span class="meta" style="float:right">As of <!-- FILL: YYYY-MM-DD HH:MM UTC --></span>
<p><!-- FILL: lead workstream + a couple of numbers, e.g. "PR #NNNNN · 12 commits · 42 tests · flag FLAG_NAME" --></p>
</div>
<!-- NEXT STEPS — keep this; it sits above the tabs so it is visible no matter which tab is open.
13 items, most important first. Each item: WHO (bold) → the exact action → what it unblocks
or when it's needed. Nothing pending? Keep the strip: delete the <ol>, set the summary FILL
to "none pending", and use the <p class="none"> line below. Always ship the <details> open,
with the item count in the <summary>. Full convention (what counts as a next step, the
Attention-tab relationship): SKILL.md → Conventions. -->
<details class="next" open>
<summary>Next steps <span class="meta">· <!-- FILL: "N items", or "none pending" --></span></summary>
<ol>
<li><span class="who"><!-- FILL: who --></span><!-- FILL: the exact action --> <span class="meta"><!-- FILL: what it unblocks / by when --></span></li>
<li><span class="who"><!-- FILL: who --></span><!-- FILL: action --> <span class="meta"><!-- FILL --></span></li>
</ol>
<!-- nothing pending? delete the <ol> above, set the summary FILL to "none pending", and use:
<p class="none">No action needed — FILL: why (e.g. "shipped; only stage 10 tuning remains, owned by the team").</p>
-->
</details>
<!-- Tab order matches SKILL.md's catalog: Overview, Workstreams (the spine), then Attention,
Background, Plan, Risks & open questions, FAQ as you have content for them. Add/remove a tab
=> update the <button>s here AND the matching <section class="pane"> below (no CSS edits
needed), and renumber. DELETE "Attention", "Background", "Plan", "Risks & open questions",
and/or "FAQ" if there's nothing substantive to put there — a simple project may have just
Overview + Workstreams; "Attention" earns its tab only on an artifact that's refreshed regularly.
Software project? swe.md keeps these but may add "Architecture" / "Findings & fixes" /
"Rollout & rollback" tabs for a heavyweight one (none mandatory). -->
<div class="tabbar">
<button class="tab active" data-pane="over">1 &middot; Overview</button>
<button class="tab" data-pane="work">2 &middot; Workstreams</button>
<button class="tab" data-pane="att">3 &middot; Attention</button>
<button class="tab" data-pane="bg">4 &middot; Background</button>
<button class="tab" data-pane="plan">5 &middot; Plan</button>
<button class="tab" data-pane="risk">6 &middot; Risks &amp; open questions</button>
<button class="tab" data-pane="faq">7 &middot; FAQ</button>
</div>
<main>
<!-- ─────────────────────────────────── TAB: OVERVIEW ─────────────────────── -->
<section class="pane active" id="over">
<div class="callout"><!-- FILL: one line — what this project is and why it exists (keep the "why" brief, or drop it, if the goal is obvious) --></div>
<h2>Success criteria</h2>
<!-- If the criteria span distinct concerns (product / security / perf, or
must-have / nice-to-have), GROUP them — repeat <h3>…</h3> + a sub-table per group
instead of one flat table. One flat table is fine when there's only a handful. -->
<table>
<tr><th style="width:180px">Criterion</th><th>Statement</th><th style="width:300px">Check (how you'd know it's met)</th><th style="width:90px">Status</th></tr>
<tr><td><!-- FILL: short name --></td><td><!-- FILL --></td><td><!-- FILL: the observable test --></td><td><span class="pill next">not yet</span></td></tr>
</table>
<h2>Out of scope</h2>
<ul><li><!-- FILL: something we deliberately are NOT doing, and why — bounds the reader's worry --></li></ul>
</section>
<!-- ─────────────────────────────────── TAB: WORKSTREAMS ──────────────────── -->
<section class="pane" id="work">
<h2>Status</h2>
<!-- This table IS the progress view — no separate "Status" tab. If the order doesn't
make the dependencies obvious, put "after <id>" in the "Depends on" cell; don't
add a diagram. (Software: number the rows X.Y per swe.md — the numbers carry the
dependencies, so the "Depends on" column is usually redundant there.) -->
<table>
<tr><th style="width:80px">ID</th><th>What</th><th style="width:120px">Owner</th><th style="width:110px">Depends on</th><th style="width:150px">Status</th></tr>
<tr><td><!-- FILL --></td><td><!-- FILL --></td><td><!-- FILL --></td><td></td><td><span class="pill now">in progress</span></td></tr>
<tr><td><!-- FILL --></td><td><!-- FILL --></td><td><!-- FILL --></td><td><!-- FILL: e.g. "after A" --></td><td><span class="pill next">next</span></td></tr>
</table>
<hr>
<h2><!-- FILL: workstream name --> <span class="pill now">in progress</span></h2>
<h3>Done so far</h3>
<ul><li><!-- FILL --></li></ul>
<h3>How it was verified</h3>
<p><!-- FILL: tests run, demo given, sign-off received, data checked — whatever "verified" means here --></p>
<!-- repeat the block for each workstream worth detailing.
Software project: swe.md has the per-PR "what landed / verification / commits /
files" detail fragment. -->
</section>
<!-- ─────────────────────────────────── TAB: ATTENTION ────────────────────── -->
<!-- Only on an artifact that's refreshed regularly and drives action — delete on a one-shot
overview page. Action first: each "waiting on owner" item is the exact thing to do. -->
<section class="pane" id="att">
<h2>Waiting on <!-- FILL: the owner's name --></h2>
<ol>
<li><!-- FILL: the exact action (a paste-ready message, or a one-word decision) — plus one sentence on what it unblocks and who is waiting --></li>
</ol>
<h2>Automatic once those land</h2>
<ul><li><!-- FILL: the chain that needs no action — auto-merge cascades, deploys, tracker auto-close --></li></ul>
<h2>Waiting on others</h2>
<table>
<tr><th style="width:140px">Who</th><th>What</th><th style="width:180px">Item</th><th style="width:160px">Where to nudge</th></tr>
<tr><td><!-- FILL --></td><td><!-- FILL --></td><td><a href="#"><!-- FILL --></a></td><td><!-- FILL: channel / handle, or — --></td></tr>
</table>
</section>
<!-- ─────────────────────────────────── TAB: BACKGROUND ───────────────────── -->
<section class="pane" id="bg">
<div class="callout"><!-- FILL: "If you only read one tab, read this — the context the rest assumes." (or delete) --></div>
<h2><!-- FILL: the problem / prior state --></h2>
<p><!-- FILL --></p>
<h2>Key ideas</h2>
<p><!-- FILL: the concepts/vocabulary a newcomer needs; analogies welcome. Link forward to a deep-dive tab if there is one. --></p>
</section>
<!-- ─────────────────────────────────── TAB: PLAN ─────────────────────────── -->
<section class="pane" id="plan">
<h2>Approach</h2>
<p><!-- FILL: the strategy — phases, the order things happen in, why this shape --></p>
<h2>Phases</h2>
<table>
<tr><th>Phase</th><th>Goal</th><th>Depends on</th></tr>
<tr><td>1</td><td><!-- FILL --></td><td></td></tr>
</table>
</section>
<!-- ───────────────────────────── TAB: RISKS & OPEN QUESTIONS ─────────────── -->
<!-- Drop this whole tab if the project is low-risk and has no open questions. -->
<section class="pane" id="risk">
<h2>Risks</h2>
<table>
<tr><th>Risk</th><th style="width:130px">Likelihood / impact</th><th>Mitigation</th><th style="width:130px">Owner</th></tr>
<tr><td><!-- FILL --></td><td><!-- FILL --></td><td><!-- FILL --></td><td><!-- FILL --></td></tr>
</table>
<h4 style="color:var(--red)">⚠ The honest caveat</h4>
<p><!-- FILL: the thing the team already knows is a weak point — say it plainly; it builds trust --></p>
<h2>Open questions</h2>
<ul><li><!-- FILL: an unresolved question the project hasn't answered yet (who decides, by when) --></li></ul>
</section>
<!-- ─────────────────────────────────── TAB: FAQ ──────────────────────────── -->
<section class="pane" id="faq">
<h3><!-- FILL: a question people actually ask, e.g. "Why this approach?" --></h3>
<p><!-- FILL --></p>
<h3><!-- FILL: "Why not <obvious-alternative>?" --></h3>
<p><!-- FILL --></p>
<h3>What does "done" look like?</h3>
<p><!-- FILL: the observable end state --></p>
</section>
</main>
<!-- STATE BLOCK — keep this. Machine-readable snapshot of this render, read by the next
refresh to compute the delta (see SKILL.md "Refreshing an artifact"). Invisible on the page.
Software projects: per-PR fields are listed in swe.md. Strings derived from fetched text
(branch names, PR titles) are untrusted markup: write < as \u003c inside this JSON so a
literal "</" can never terminate the block, and entity-encode them in the visible HTML. -->
<script type="application/json" id="artifact-state">
{"as_of": "YYYY-MM-DD HH:MM UTC", "workstreams": [{"id": "", "status": "", "owner": ""}]}
</script>
<script>
function goTab(id){
document.querySelectorAll('.tab').forEach(t => t.classList.toggle('active', t.dataset.pane === id));
document.querySelectorAll('.pane').forEach(p => p.classList.toggle('active', p.id === id));
}
document.querySelectorAll('.tab').forEach(t => t.addEventListener('click', () => goTab(t.dataset.pane)));
</script>
</body>
</html>