admin: paint the dev server's chrome in ink blue
A working copy passed for the deployment till you read the footer's fine print;
now a run with no release wears ink blue, its header and footer filled with the tint.
Assisted-by: Claude Opus 5 via Claude Code
diff --git a/docs/DESIGN.md b/docs/DESIGN.md
index c850540..bbc83f4 100644
--- a/docs/DESIGN.md
+++ b/docs/DESIGN.md
@@ -41,6 +41,8 @@ What that inheritance actually means:
`_components/<name>.md` rather than guessing from a sibling.
- **One accent, held constant.** Pro-tacts sets `--gl-color-accent` once and
never shows two accents in a view. `-ink` and `-soft` re-derive themselves.
+ The one swap is by run, not by view: a dev server repoints it to ink blue on
+ every screen (see the footer, below).
- `--gl-color-success` and `--gl-color-danger` are **fixed** — they mean
confirmed and destructive, never decoration, never emphasis.
- Surface contrast does the elevation work: a bounded surface reads by
@@ -92,7 +94,9 @@ Under every screen sits the footer, the header's counterpart, holding what no
search can turn up because none of it is a record: the version answering,
whether debug logging is recording, and a link to device setup. A run with no
release behind it says "dev server" in the version's place, since a working
-copy dressed as the deployment is the confusion the line exists to end. Debug
+copy dressed as the deployment is the confusion the line exists to end. The
+same run fills the header and footer with its accent, so the difference shows
+before a word of either is read. Debug
logging appears only while it is on, written `+debug` — a flag on the build,
not a sentence beside it — and a quiet log has nothing to say.
diff --git a/lib/pro_tacts/admin/layout.rb b/lib/pro_tacts/admin/layout.rb
index 2907189..8b1900e 100644
--- a/lib/pro_tacts/admin/layout.rb
+++ b/lib/pro_tacts/admin/layout.rb
@@ -41,7 +41,11 @@ module ProTacts
def view_template
doctype
- html(lang: "en") do
+ # A run with no release behind it, the footer's "dev server",
+ # marks the root, and admin.css repaints the accent and the
+ # chrome for it: a working copy should not pass for the
+ # deployment at a glance (docs/DESIGN.md).
+ html(lang: "en", **(ProTacts.config.version ? {} : {data: {server: "dev"}})) do
head do
meta(charset: "utf-8")
meta(name: "viewport", content: "width=device-width, initial-scale=1")
diff --git a/public/admin.css b/public/admin.css
index de3fdc8..7bdc604 100644
--- a/public/admin.css
+++ b/public/admin.css
@@ -369,6 +369,31 @@ textarea:focus {
margin-left: auto;
}
+/* A run with no release behind it (Layout marks the root; the footer
+ names it "dev server") wears Gloss's ink blue instead of the default
+ accent, and the chrome bars fill with it, so a working copy cannot
+ pass for the deployment at a glance. The whole root repoints rather
+ than the bars alone, so a view still shows one accent. Clay was
+ passed over for sitting too near danger. The fill is the accent
+ under accent-fg, the pairing Gloss's primary button uses;
+ accent-soft would be a pale band in dark mode, where tokens.css
+ never derives it again. */
+:root[data-server="dev"] {
+ --gl-color-accent: var(--gl-accent-ink-blue);
+}
+:root[data-server="dev"] :is(.admin-header, .admin-footer) {
+ background: var(--gl-color-accent);
+ border-color: var(--gl-color-accent);
+}
+:root[data-server="dev"] :is(.admin-header a, .admin-footer .type-label) {
+ color: var(--gl-color-accent-fg);
+}
+/* The one focus ring is drawn in the accent, which vanishes against a
+ bar filled with it. */
+:root[data-server="dev"] :is(.admin-header, .admin-footer) :focus-visible {
+ outline-color: var(--gl-color-accent-fg);
+}
+
/* The viewport-tall column the footer's `margin-top: auto` measures
against. Gloss's own body rule sets type and surface and leaves
layout to the page, which until there was a footer meant nothing at
diff --git a/test/pro_tacts/admin/test_footer.rb b/test/pro_tacts/admin/test_footer.rb
index 91fea5d..11bc16e 100644
--- a/test/pro_tacts/admin/test_footer.rb
+++ b/test/pro_tacts/admin/test_footer.rb
@@ -71,4 +71,16 @@ class AdminFooterTest < Minitest::Test
refute_includes last_response.body, "+debug"
end
+
+ def test_an_unversioned_run_marks_the_page_for_the_dev_theme
+ with_env({})
+
+ assert_includes last_response.body, %(<html lang="en" data-server="dev">)
+ end
+
+ def test_a_release_leaves_the_page_unmarked
+ with_env("VERSION" => "20260904-1822-a1b2c3d")
+
+ refute_includes last_response.body, "data-server"
+ end
end