docs: turn the accepted panel design into an enforceable contract

panel-redesign.md is rewritten for the accepted direction: three layers
(Bulma as shipped, adapters, own sp- components), the page layouts, what
an implementer must not do, and how that is enforced — guard tests that
land before any template, a design-first CI step, and acceptance by
evidence (test output plus a screenshot of every page beside its mockup,
reviewed by a model that did not write the step).

A components page shows every building block in every state; a screen
may be built from nothing else. panel/check.py lints the mockups against
the contract (class vocabulary, CSS bans on !important, id and page
selectors and stray widths, page structure) and writes
panel/outlines.json, the per-screen component skeleton an implementation
is compared with, so a different design cannot pass as this one.

Own modifier classes now carry the sp- prefix (sp-warn, sp-fail, sp-big,
sp-danger-zone, ...) so the vocabulary is machine-checkable; the lint
also caught a width set outside the layout in the mockup's own CSS.

Agent rule .cursor/rules/panel-design.mdc; roadmap row and section
updated (0/15, still candidate).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
mix
2026-09-21 20:55:18 +03:00
co-authored by Claude Fable 5.1
parent d1f22fbcc8
commit 1bcfca1586
38 changed files with 1402 additions and 256 deletions
@@ -63,7 +63,7 @@
<main>
<div class="container sp-page">
<div class="sp-head">
<div class="sp-postmark warn"><span>SELFPOST</span><b>WARN</b><span>1 OF 6 CHECKS</span></div>
<div class="sp-postmark sp-warn"><span>SELFPOST</span><b>WARN</b><span>1 OF 6 CHECKS</span></div>
<div class="sp-grow">
<p class="sp-kicker">mail.example.org</p>
<h1 class="title is-3">Mail is flowing. One thing needs attention.</h1>
@@ -77,7 +77,7 @@
<div class="sp-health">
<a href="health.html#machine"><span class="sp-h-icon"><i class="ti ti-cpu"></i></span><span><span class="sp-h-name">Machine</span><br><span class="sp-h-value">CPU 12 % · RAM 41 %</span><br><span class="sp-h-sub">↓ 18 kB/s · ↑ 44 kB/s</span></span></a>
<a href="health.html#processes"><span class="sp-h-icon"><i class="ti ti-server-cog"></i></span><span><span class="sp-h-name">Processes</span><br><span class="sp-h-value">5 of 5 running</span><br><span class="sp-h-sub">up 18 days</span></span></a>
<a href="health.html#certificate" class="warn"><span class="sp-h-icon"><i class="ti ti-certificate"></i></span><span><span class="sp-h-name">TLS certificate</span><br><span class="sp-h-value">Expires in 12 days</span><br><span class="sp-h-sub">renewal has not run</span></span></a>
<a href="health.html#certificate" class="sp-warn"><span class="sp-h-icon"><i class="ti ti-certificate"></i></span><span><span class="sp-h-name">TLS certificate</span><br><span class="sp-h-value">Expires in 12 days</span><br><span class="sp-h-sub">renewal has not run</span></span></a>
<a href="out-queue.html"><span class="sp-h-icon"><i class="ti ti-stack-2"></i></span><span><span class="sp-h-name">Queues</span><br><span class="sp-h-value">Both empty</span><br><span class="sp-h-sub">outbound and inbound</span></span></a>
<a href="health.html#sockets"><span class="sp-h-icon"><i class="ti ti-plug-connected"></i></span><span><span class="sp-h-name">Milter sockets</span><br><span class="sp-h-value">2 of 2 answering</span><br><span class="sp-h-sub">opendkim, journal</span></span></a>
<a href="health.html#hostname"><span class="sp-h-icon"><i class="ti ti-arrows-exchange"></i></span><span><span class="sp-h-name">Reverse DNS</span><br><span class="sp-h-value">Forward = reverse</span><br><span class="sp-h-sub">203.0.113.25</span></span></a>