Files
selfpost/internal/web/static/panel.css
T
mix 08943caae1 panel: lay the nav bar out as two rows on purpose
It stopped fitting on one line once the entries grew icons: six of them
need about 660px and the session block another 260px, against the 738px
the panel is wide. Flex was already wrapping it, but the wrap put the
session left-aligned directly under the entries, where it read as a third
row of navigation.

So: entries on the first row, session pushed to the right edge on the
second. The two blocks now read as two blocks. Buying the ~200px back by
shortening labels was the other option and would have undone the recent
work naming each entry after its page.

Rows rather than columns -- a two-column grid of entries measured a third
taller (107px against 83px) and was no easier to read. Entries stay first
in document order, so tabbing still reaches the pages before Sign out.

Checked at 1200, 768, 600 and 375px: no horizontal overflow, and below
768 the entries wrap to two rows as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 22:39:08 +03:00

178 lines
11 KiB
CSS

/* Panel stylesheet. It lives in a file rather than in a <style> block in the
layout so the panel's Content-Security-Policy can be a plain
"default-src 'self'" with no inline-style exemption (phase 14.A). Any rule
added here must therefore stay here: an inline style="..." attribute in a
template is blocked by that policy and silently does nothing. */
:root { color-scheme: light dark; }
* { box-sizing: border-box; }
body {
font: 15px/1.5 system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
margin: 0; padding: 2rem 1rem; background: #f6f7f9; color: #1b1f24;
}
@media (prefers-color-scheme: dark) {
body { background: #14171a; color: #e6e8eb; }
.card { background: #1d2125 !important; border-color: #2b3138 !important; }
input { background: #14171a !important; color: inherit !important; border-color: #2b3138 !important; }
}
main { max-width: 42rem; margin: 0 auto; }
h1 { font-size: 1.4rem; margin: 0 0 1rem; }
.card {
background: #fff; border: 1px solid #e2e5e9; border-radius: 10px;
padding: 1.5rem; margin: 0 auto;
}
.card.narrow { max-width: 24rem; }
label { display: block; font-weight: 600; margin: 0.9rem 0 0.3rem; }
input {
width: 100%; padding: 0.55rem 0.7rem; font-size: 1rem;
border: 1px solid #cfd4da; border-radius: 6px; background: #fff;
}
/* One vocabulary for actions. Anything that performs an action looks like a
button: a <button>, or an <a> carrying .btn/.danger where the action is a
plain navigation (the delete confirmation page, the full queue view).
Several of these used to render as bold blue text instead — a POST wrapped
in form.inline, a <details> toggle, the delete links — which read as links
and left two appearances for the same kind of control. They all get the
button look now: filled for a card's own action, and the compact outlined
variant further down where actions cluster (table rows, the nav bar). Bare
<a> is left for links that read as part of a sentence or a list. */
button, a.btn, a.danger {
display: inline-block; margin-top: 1.2rem; padding: 0.6rem 1.1rem;
font: inherit; font-size: 1rem; font-weight: 600; text-decoration: none;
color: #fff; background: #2563eb; border: 0; border-radius: 6px; cursor: pointer;
}
button:hover, a.btn:hover { background: #1d4ed8; }
.error { color: #b42318; margin: 0.6rem 0 0; font-weight: 600; }
.muted { color: #6b7280; }
.topbar { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 1.2rem; }
.topbar .actions { display: flex; gap: 0.9rem; align-items: baseline; }
/* form.inline only exists so a POST can sit next to other content without a
form's block layout; its button is styled like any other. */
form.inline { display: inline; margin: 0; }
main { max-width: 48rem; }
.card + .card { margin-top: 1.2rem; }
.flash { background: #ecfdf3; border: 1px solid #abefc6; color: #067647; padding: 0.7rem 1rem; border-radius: 8px; margin-bottom: 1.2rem; }
@media (prefers-color-scheme: dark) { .flash { background: #0d2818 !important; border-color: #1a5336 !important; color: #75d99b !important; } }
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 0.5rem 0.4rem; border-bottom: 1px solid #e2e5e9; }
@media (prefers-color-scheme: dark) { th, td { border-color: #2b3138 !important; } }
th { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.03em; color: #6b7280; }
td.actions { text-align: right; }
.code { display: block; white-space: pre-wrap; word-break: break-all; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 0.85rem; background: #f0f2f4; border: 1px solid #e2e5e9; border-radius: 6px; padding: 0.7rem 0.8rem; margin: 0.3rem 0 0; }
@media (prefers-color-scheme: dark) { .code { background: #14171a !important; border-color: #2b3138 !important; } }
h2 { font-size: 1.05rem; margin: 0 0 0.4rem; }
.back { display: inline-block; margin-bottom: 1rem; }
/* Build version, closing every authenticated page. Quiet on purpose: it is
reference material, not something to read on the way past. */
.version { margin-top: 1.6rem; text-align: right; font-size: 0.8rem; color: #6b7280; }
select, textarea {
width: 100%; padding: 0.55rem 0.7rem; font-size: 1rem;
border: 1px solid #cfd4da; border-radius: 6px; background: #fff; color: inherit;
font-family: inherit;
}
textarea { resize: vertical; }
@media (prefers-color-scheme: dark) {
select, textarea { background: #14171a !important; color: inherit !important; border-color: #2b3138 !important; }
}
button.danger, a.danger { background: #b42318; }
button.danger:hover, a.danger:hover { background: #912018; }
td.actions form.inline, td.actions details { margin: 0.4rem 0 0 0.5rem; }
/* The disclosure toggle is an action too, so it is drawn as a button (see the
compact rule below); the marker is dropped because the pressed background
already shows the open state. */
td.actions summary { display: inline-block; list-style: none; cursor: pointer; }
td.actions summary::-webkit-details-marker { display: none; }
details form { margin-top: 0.6rem; }
.credential { border-color: #f5c518; background: #fffbeb; }
@media (prefers-color-scheme: dark) { .credential { background: #2a2408 !important; border-color: #6b5a10 !important; } }
/* Panel navigation: rendered once from the layout, so it is present on every
authenticated page without each content template having to include it. */
/* Two deliberate rows, not one. The six page entries need about 660px and the
session block another 260px, against the 738px the panel is wide — so the bar
was wrapping on its own, and the session landed left-aligned directly under
the entries, reading as a third row of navigation. Shortening labels would buy
the ~200px back but undo the point of naming each entry after its page. Rows
rather than columns: a two-column grid of entries came out a third taller
(107px against 83px) and no easier to read. Entries stay first, in the
document order, so tabbing reaches the pages before Sign out. */
.nav {
display: flex; flex-direction: column; align-items: stretch;
gap: 0.5rem; margin-bottom: 1.2rem; padding-bottom: 0.6rem;
border-bottom: 1px solid #e2e5e9;
}
@media (prefers-color-scheme: dark) { .nav { border-color: #2b3138 !important; } }
.nav .links, .nav .session { display: flex; flex-wrap: wrap; gap: 0.2rem 0.9rem; align-items: center; }
/* Pushed to the far edge so the two rows read as two blocks rather than as one
ragged list that happened to wrap. */
.nav .session { justify-content: flex-end; }
/* Each entry pairs an icon with its label, so the entry itself is a flex row
rather than a run of text — that is also why the bar centres its items
instead of aligning them on the text baseline. Account is included: it is a
page like the others and would otherwise be the one bare word in the bar. */
.nav a, .nav [aria-current] {
display: inline-flex; align-items: center; gap: 0.4rem;
padding: 0.2rem 0.5rem; border-radius: 6px;
}
.nav [aria-current] {
font-weight: 600; color: #1b1f24; background: #e6ebf5; box-shadow: inset 0 -2px 0 #2563eb;
}
@media (prefers-color-scheme: dark) {
.nav [aria-current] { color: #e6e8eb !important; background: #22303f !important; }
}
/* Sign out carries an icon too, so it needs the same row layout; its padding
and colours come from the compact button rule further down. */
.nav button { display: inline-flex; align-items: center; gap: 0.4rem; }
/* The icons draw in the entry's own colour, so the active entry's darker text,
a link's blue and Sign out's red all carry through without a rule apiece. */
.nav .icon { width: 1rem; height: 1rem; flex: none; }
/* Status badges: one vocabulary (ok/warn/error/unknown) shared by the server
status page and the per-domain DNS checks, so a colour means the same thing
everywhere. The class suffix is the check's own status value. */
.st {
display: inline-block; padding: 0.05rem 0.45rem; border-radius: 999px;
font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
vertical-align: middle; border: 1px solid transparent;
}
.st-ok { background: #ecfdf3; color: #067647; border-color: #abefc6; }
.st-warn { background: #fffaeb; color: #b54708; border-color: #fedf89; }
.st-error { background: #fef3f2; color: #b42318; border-color: #fecdca; }
.st-unknown { background: #f0f2f4; color: #6b7280; border-color: #e2e5e9; }
@media (prefers-color-scheme: dark) {
.st-ok { background: #0d2818 !important; color: #75d99b !important; border-color: #1a5336 !important; }
.st-warn { background: #2e2308 !important; color: #f5c86b !important; border-color: #6b5210 !important; }
.st-error { background: #2d1211 !important; color: #f5a29b !important; border-color: #6b201a !important; }
.st-unknown { background: #22262b !important; color: #9aa3ad !important; border-color: #2b3138 !important; }
}
.code-row { display: flex; align-items: flex-start; gap: 0.5rem; }
.code-row .code { flex: 1; min-width: 0; }
/* Compact outlined button: same affordance as the filled one but quiet enough
that several can sit together without shouting — the Copy buttons beside a
value, the per-application actions in a table row. Sign out overrides this
with .danger below since signing out is a deliberate, singular action. */
button.copy, td.actions button, td.actions summary, td.actions a.danger, .nav button {
margin: 0; padding: 0.45rem 0.7rem; font-size: 0.8rem; font-weight: 600;
border-radius: 6px; white-space: nowrap;
background: #eef1f5; color: #2563eb; border: 1px solid #cfd4da;
}
button.copy:hover, td.actions button:hover, td.actions summary:hover,
td.actions a.danger:hover, .nav button:hover { background: #e2e7ee; }
button.copy { flex: none; margin-top: 0.3rem; }
td.actions details[open] > summary { background: #dde3ec; }
td.actions button.danger, td.actions a.danger, .nav button.danger {
color: #b42318; background: #fef3f2; border-color: #fecdca;
}
td.actions button.danger:hover, td.actions a.danger:hover, .nav button.danger:hover { background: #fee4e2; }
@media (prefers-color-scheme: dark) {
button.copy, td.actions button, td.actions summary, td.actions a.danger, .nav button {
background: #22262b !important; border-color: #2b3138 !important;
}
button.copy:hover, td.actions button:hover, td.actions summary:hover,
td.actions a.danger:hover, .nav button:hover { background: #2b3138 !important; }
td.actions details[open] > summary { background: #313841 !important; }
td.actions button.danger, td.actions a.danger, .nav button.danger {
color: #f5a29b !important; background: #2d1211 !important; border-color: #6b201a !important;
}
td.actions button.danger:hover, td.actions a.danger:hover, .nav button.danger:hover { background: #3d1a18 !important; }
}