Compare commits

..

1 Commits

Author SHA1 Message Date
mix 61bf8e7f9b Update .dockerignore
test / test (push) Has been cancelled
2026-08-11 00:04:03 +03:00
2 changed files with 7 additions and 188 deletions
-179
View File
@@ -1,179 +0,0 @@
# Plan: visual-style
**Status:** agreed
**Version:** no bearing on semver — presentation only, no schema and no route
changes.
**Order:** independent of the feature roadmap; may be taken up between feature
items.
---
## Goal
Bring the control panel's surface in line with the mark that was approved in
[selfpost-proof.html](../assets/selfpost-proof.html): its palette, its
typography, and the plainness of its components. Today the panel is a default
blue-on-cool-grey admin theme standing next to a warm brick stamp, so the mark
reads as pasted onto someone else's page.
## Scope
**In:**
- `internal/web/view/static/panel.css` — colour tokens, typography, spacing,
every component rule.
- `internal/web/view/static/` — three self-hosted font files.
- Templates, only where a class has to be added or a wrapper introduced for a
rule to have something to attach to.
- `NOTICE` — the OFL attribution the font files oblige.
**Out:**
- Any change to what a page does, which pages exist, or what an operator has to
click. No new features, no copy rewriting.
- The navigation's position and the two-column shell. The proof's panel mock
shows a horizontal bar on a dark header; the panel's left column also carries
the per-page section index (`.sections` plus the scroll-spy in `panel.js`),
which that layout has nowhere to put. Keeping the column is a deliberate
divergence from the mock, not an oversight.
- The mark files themselves (`logo.svg`, `logo-compact.svg`, `favicon.*`) —
already drawn, already converted to outlines.
## Constraint that shapes everything
The panel's Content-Security-Policy is a plain `default-src 'self'` with no
inline-style exemption ([security.md](../security.md)). Every rule lives in
`panel.css`; a `style="..."` attribute in a template is blocked and silently
does nothing. Self-hosted fonts are served from the panel's own origin and are
therefore already covered — no CSP change is needed, and none may be made.
## Typography
IBM Plex, self-hosted. The mark is Plex converted to outlines, so the panel
setting its own name in Segoe UI or Cantarell is the seam this whole item
exists to close.
| File | Covers | Size |
|---|---|---|
| `static/ibm-plex-sans.woff2` | variable, weights 100700, latin | 45.7 KB |
| `static/ibm-plex-mono-400.woff2` | mono regular, latin | 14.8 KB |
| `static/ibm-plex-mono-600.woff2` | mono semibold, latin | 15.7 KB |
76 KB in total, in a 20 MB binary. The variable file replaces what would
otherwise be five static weights and lets the scale below use 300 and 500
without paying per weight.
Monospace is the one the operator actually reads: DKIM records, `mail.log`
lines, application logins, socket paths, generated passwords. `ui-monospace`
resolves to Consolas, SF Mono or DejaVu Sans Mono depending on the operator's
machine, and those differ in advance width — the six-column send log wraps
differently for each. A shipped mono makes those tables one layout.
| Role | Family | Size | Weight |
|---|---|---|---|
| Body | sans | 15px / 1.5 | 400 |
| `h1` | sans | 1.55rem, tracking 0.01em | 300 |
| `h2` | sans | 1.05rem | 600 |
| `label` | sans | 0.9rem | 600 |
| Nav entry / active | sans | 0.95rem | 400 / 600 |
| `th` | **mono**, uppercase, tracking 0.08em | 0.75rem | 500 |
| `.st` status badge | **mono** | 0.78rem | 500 |
| `.code`, `.mono`, `.metric` | **mono** | 0.85rem | 400 |
`font-display: swap`, so a cold load shows the system stack for a frame rather
than blank text.
## Colour tokens
Names stay as they are wherever they already exist: the dark scheme reassigns
the same custom properties, which is why no rule in the file needs
`!important`. Warm neutrals replace the cool greys; brick becomes the accent.
| Token | Light | Dark |
|---|---|---|
| `--bg` | `#F4F2ED` | `#16181B` |
| `--fg` | `#12161C` | `#E9E6E0` |
| `--muted` | `#6B7684` | `#9AA1A9` |
| `--card-bg` | `#FFFFFF` | `#1D2024` |
| `--border` | `#DEDCD7` | `#2C2F34` |
| `--control-border` | `#CBC8C1` | `#3A3E44` |
| `--input-bg` | `#FFFFFF` | `#14161A` |
| `--code-bg` | `#EFEDE9` | `#14161A` |
| `--surface-bg` | `#EAE7E0` | `#23262B` |
| `--accent-fill` / `--on-accent` | `#7A3B2E` / `#FFFFFF` | `#8E4535` / `#FFFFFF` |
| `--accent-text` | `#7A3B2E` | `#CE7B66` |
| `--nav-active-bg` | `#EDE4DE` | `#2A1F1B` |
Brick splits into a fill and a text value because `#7A3B2E` on `#16181B` is
about 2:1 — unreadable as a dark-scheme link. The fill lightens just enough to
keep white on it above 4.5:1; the text value lightens further.
Status families (`--st-ok-*`, `--st-warn-*`, `--st-error-*`, `--st-unknown-*`),
the flash, the credential card and `--danger-*` keep their hues and are only
warmed to sit on paper. The one thing to watch is brick against `st-error` red:
the proof rejected several candidate colours precisely so that the mark would
not read as a status, and the same test now applies to every brick button
standing in a row of `error` badges.
## Components
Everything already in `panel.css`, in the order it appears there: card, form
controls, buttons (filled, outlined, danger), flash, table, status badge,
`.code`, nav (brand, links, sections, session), application list and its
disclosure panels, credential card, status page meters and facts, delivery
timeline, log tables, split layout, encrypt fields, footer.
Two component-level changes rather than pure repaints, both forced by the
accent:
- Row actions (`td.actions a.danger`, `Delete`) become outlined instead of
filled. A filled red button in a table row next to a filled brick button
reads as one block of colour.
- Nav entries carry the active state as brick text on a warm tint rather than
the current blue tint.
## Order of work
1. Fonts into `static/`, `@font-face` and the type scale in `panel.css`,
`NOTICE` attribution. Nothing else changes shape.
2. Token block: light and dark, both schemes in one pass.
3. Chrome: `layout.html`'s nav, footer, shell.
4. Signed-out pages: `login`, `setup` — the mark and one card, where the seam
is worst.
5. `dashboard`, `domain_detail`, `domain_delete`.
6. `deliveries`, `deliveries_rows`, `delivery`.
7. `status` + `status_body`, `mail_queue*`, `system_log*`.
8. `backup`, `account`, `users`, `user_form`, `encrypt_fields`.
9. `CHANGELOG.md` under `[Unreleased]`.
## Verification
- Every page rendered locally and screenshotted in both schemes before and
after (`panel.exe` on Windows, headless Edge), including a 375px-wide pass —
the nav column and the wide tables are where a repaint breaks layout.
- Contrast: body text and every status badge at 4.5:1 or better against its own
background, UI borders at 3:1. Brick on white is 7.3:1 by the proof's own
measurement; the dark-scheme values above are the ones to re-check.
- `go build ./... && go vet ./... && go test ./...`; the template guards in
`internal/web/view/templates_test.go` must stay green, and the static-asset
ETag test grows to cover the three font files.
- No `style=` attribute anywhere in `templates/` — the CSP would drop it.
## Done when
- The panel and the mark read as one design in both schemes, at the reading
measure and on the wide data pages.
- Nothing an operator does changed: same pages, same controls, same copy.
- Fonts are served from the panel's own origin under the unchanged CSP, and the
image works with no network access.
- `NOTICE` credits IBM Plex (OFL-1.1); build, vet and tests are green.
## Risks
- **Visual regression across 21 templates.** The panel has pages that are only
reachable mid-workflow (the credential card, the delete confirmation, the
encrypt fields). Mitigation: the page order above is a checklist, and each
step is screenshotted rather than assumed.
- **Brick against the error red.** If the two fight in a real row of the send
log, the accent gets pulled back to the mark and the buttons stay neutral —
the mark's colour is fixed, the panel's accent is the negotiable one.
- **Thin weights on dark.** `h1` at 300 is the one place a variable font makes
it easy to go too light; check it on the dark scheme before keeping it.
+7 -9
View File
@@ -29,7 +29,7 @@ in `git log` and [CHANGELOG.md](../CHANGELOG.md).
| domain-admin | Domain administrator role | **agreed** | [plans/domain-admin.md](plans/domain-admin.md) |
| inbound-relay | Inbound relay (backup-MX / forwarding) | **agreed** | [plans/inbound-relay.md](plans/inbound-relay.md) |
| contributing | `CONTRIBUTING.md` | candidate | — |
| visual-style | Panel visual style | **agreed** | [plans/visual-style.md](plans/visual-style.md) |
| visual-style | Обновление визуального стиля | candidate | — |
| dmarc-reports | DMARC aggregate report ingestion and panel UI | candidate | [plans/dmarc-reports.md](plans/dmarc-reports.md) |
**Recommended order** (not binding): **domain-admin →
@@ -113,15 +113,13 @@ features. Styling must stay compatible with the panel CSP — rules live in
`panel.css`, not inline (see [security.md](security.md) and the stylesheet
header).
**Done when:** see [plans/visual-style.md](plans/visual-style.md). The agreed
direction is the mark's own — brick, warm paper, IBM Plex — taken from
[assets/selfpost-proof.html](assets/selfpost-proof.html); light and dark schemes
remain supported; readability and contrast are preserved.
**Done when:** the panel reflects an agreed visual direction (starting
reference: [assets/selfpost-proof.html](assets/selfpost-proof.html)); light and
dark schemes remain supported; readability and contrast are preserved.
**Dependencies / risks:** CSP constraints on how styles are applied (rules in
`panel.css`, never inline); visual regression across pages; the accent colour
must not read as a status badge.
**Order:** independent of the feature items; may be taken up between them.
**Dependencies / risks:** CSP constraints on how styles are applied; visual
regression across pages; low priority relative to functional work — take up
after explicit agreement, independently of the feature roadmap order.
**Version:** no bearing on semver.
---