release: 0.4.0: Domain-admin groundwork, send-log auth, packaging fixes

The project's mark is now in use rather than only on file. The README opens
Added:
  - The project's mark is now in use rather than only on file. The README opens
Changed:
  - panel: the sign-in and setup pages are now a column the width of their own
  - panel: the three monitoring pages — Deliveries, Mail queue, System log — are
Fixed:
  - panel: Deliveries now shows the subject as text rather than as its MIME
  - panel: table cells may now break inside a word, so no single long value can
  - panel: the Applications list on a domain page no longer comes apart. It was a

Full detail: CHANGELOG.md (0.4.0).
This commit is contained in:
mix
2026-09-22 15:24:51 +03:00
parent af9f89b628
commit 72b09d60a6
21 changed files with 317 additions and 86 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

+8
View File
@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" role="img" aria-label="SelfPost">
<!-- SelfPost · https://codeberg.org/mix/selfpost · AGPL-3.0
Wordmark set in IBM Plex Sans (OFL) and converted to outlines: the
file needs no font installed to render as drawn. -->
<path d="M7.80 5.00 L13.00 5.00 A2.8 2.8 0 0 0 18.60 5.00 L23.80 5.00 A2.8 2.8 0 0 0 29.40 5.00 L34.60 5.00 A2.8 2.8 0 0 0 40.20 5.00 L45.40 5.00 A2.8 2.8 0 0 0 51.00 5.00 L56.20 5.00 A2.8 2.8 0 0 0 59.00 7.80 L59.00 13.00 A2.8 2.8 0 0 0 59.00 18.60 L59.00 23.80 A2.8 2.8 0 0 0 59.00 29.40 L59.00 34.60 A2.8 2.8 0 0 0 59.00 40.20 L59.00 45.40 A2.8 2.8 0 0 0 59.00 51.00 L59.00 56.20 A2.8 2.8 0 0 0 56.20 59.00 L51.00 59.00 A2.8 2.8 0 0 0 45.40 59.00 L40.20 59.00 A2.8 2.8 0 0 0 34.60 59.00 L29.40 59.00 A2.8 2.8 0 0 0 23.80 59.00 L18.60 59.00 A2.8 2.8 0 0 0 13.00 59.00 L7.80 59.00 A2.8 2.8 0 0 0 5.00 56.20 L5.00 51.00 A2.8 2.8 0 0 0 5.00 45.40 L5.00 40.20 A2.8 2.8 0 0 0 5.00 34.60 L5.00 29.40 A2.8 2.8 0 0 0 5.00 23.80 L5.00 18.60 A2.8 2.8 0 0 0 5.00 13.00 L5.00 7.80 A2.8 2.8 0 0 0 7.80 5.00 Z" fill="#F3EDE1" stroke="#12161C" stroke-width="0.8" stroke-linejoin="round" />
<rect x="11" y="11" width="42" height="42" fill="#7A3B2E" />
<path d="M24.71 43.31Q22.47 43.31 21.01 42.47Q19.56 41.62 18.54 40.3L19.27 39.72Q20.23 40.97 21.49 41.71Q22.76 42.45 24.73 42.45Q26.99 42.45 28.23 41.39Q29.46 40.32 29.46 38.32Q29.46 36.94 28.94 36.15Q28.42 35.36 27.51 34.94Q26.6 34.52 25.49 34.29L23.74 33.95Q21.95 33.61 20.92 32.93Q19.9 32.24 19.44 31.29Q18.99 30.34 18.99 29.22Q18.99 27.63 19.69 26.59Q20.39 25.55 21.66 25.05Q22.94 24.54 24.63 24.54Q26.66 24.54 28.01 25.24Q29.36 25.94 30.14 27.11L29.41 27.66Q28.63 26.54 27.46 25.97Q26.29 25.4 24.58 25.4Q22.42 25.4 21.18 26.33Q19.95 27.27 19.95 29.19Q19.95 30.47 20.48 31.23Q21.01 32 21.92 32.42Q22.83 32.83 23.95 33.07L25.69 33.41Q27.54 33.74 28.57 34.46Q29.59 35.17 30 36.15Q30.4 37.12 30.4 38.24Q30.4 39.91 29.71 41.02Q29.02 42.14 27.73 42.73Q26.45 43.31 24.71 43.31Z M36.45 43H33.01V24.85H41.18Q42.87 24.85 44.06 25.55Q45.26 26.26 45.91 27.52Q46.56 28.78 46.56 30.47Q46.56 32.16 45.91 33.42Q45.26 34.68 44.06 35.38Q42.87 36.08 41.18 36.08H36.45ZM36.45 27.84V33.12H40.87Q41.54 33.12 42.01 32.87Q42.48 32.63 42.74 32.17Q43 31.72 43 31.07V29.87Q43 29.19 42.74 28.75Q42.48 28.31 42.01 28.08Q41.54 27.84 40.87 27.84Z" fill="#F6EDE2" />
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

+8
View File
@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 100" width="220" height="100" role="img" aria-label="SelfPost">
<!-- SelfPost · https://codeberg.org/mix/selfpost · AGPL-3.0
Wordmark set in IBM Plex Sans (OFL) and converted to outlines: the
file needs no font installed to render as drawn. -->
<path d="M10.20 8.00 L12.83 8.00 A2.2 2.2 0 0 0 17.23 8.00 L19.87 8.00 A2.2 2.2 0 0 0 24.27 8.00 L26.90 8.00 A2.2 2.2 0 0 0 31.30 8.00 L33.94 8.00 A2.2 2.2 0 0 0 38.34 8.00 L40.97 8.00 A2.2 2.2 0 0 0 45.37 8.00 L48.01 8.00 A2.2 2.2 0 0 0 52.41 8.00 L55.04 8.00 A2.2 2.2 0 0 0 59.44 8.00 L62.08 8.00 A2.2 2.2 0 0 0 66.48 8.00 L69.11 8.00 A2.2 2.2 0 0 0 73.51 8.00 L76.14 8.00 A2.2 2.2 0 0 0 80.54 8.00 L83.18 8.00 A2.2 2.2 0 0 0 87.58 8.00 L90.21 8.00 A2.2 2.2 0 0 0 94.61 8.00 L97.25 8.00 A2.2 2.2 0 0 0 101.65 8.00 L104.28 8.00 A2.2 2.2 0 0 0 108.68 8.00 L111.32 8.00 A2.2 2.2 0 0 0 115.72 8.00 L118.35 8.00 A2.2 2.2 0 0 0 122.75 8.00 L125.39 8.00 A2.2 2.2 0 0 0 129.79 8.00 L132.42 8.00 A2.2 2.2 0 0 0 136.82 8.00 L139.46 8.00 A2.2 2.2 0 0 0 143.86 8.00 L146.49 8.00 A2.2 2.2 0 0 0 150.89 8.00 L153.52 8.00 A2.2 2.2 0 0 0 157.92 8.00 L160.56 8.00 A2.2 2.2 0 0 0 164.96 8.00 L167.59 8.00 A2.2 2.2 0 0 0 171.99 8.00 L174.63 8.00 A2.2 2.2 0 0 0 179.03 8.00 L181.66 8.00 A2.2 2.2 0 0 0 186.06 8.00 L188.70 8.00 A2.2 2.2 0 0 0 193.10 8.00 L195.73 8.00 A2.2 2.2 0 0 0 200.13 8.00 L202.77 8.00 A2.2 2.2 0 0 0 207.17 8.00 L209.80 8.00 A2.2 2.2 0 0 0 212.00 10.20 L212.00 12.80 A2.2 2.2 0 0 0 212.00 17.20 L212.00 19.80 A2.2 2.2 0 0 0 212.00 24.20 L212.00 26.80 A2.2 2.2 0 0 0 212.00 31.20 L212.00 33.80 A2.2 2.2 0 0 0 212.00 38.20 L212.00 40.80 A2.2 2.2 0 0 0 212.00 45.20 L212.00 47.80 A2.2 2.2 0 0 0 212.00 52.20 L212.00 54.80 A2.2 2.2 0 0 0 212.00 59.20 L212.00 61.80 A2.2 2.2 0 0 0 212.00 66.20 L212.00 68.80 A2.2 2.2 0 0 0 212.00 73.20 L212.00 75.80 A2.2 2.2 0 0 0 212.00 80.20 L212.00 82.80 A2.2 2.2 0 0 0 212.00 87.20 L212.00 89.80 A2.2 2.2 0 0 0 209.80 92.00 L207.17 92.00 A2.2 2.2 0 0 0 202.77 92.00 L200.13 92.00 A2.2 2.2 0 0 0 195.73 92.00 L193.10 92.00 A2.2 2.2 0 0 0 188.70 92.00 L186.06 92.00 A2.2 2.2 0 0 0 181.66 92.00 L179.03 92.00 A2.2 2.2 0 0 0 174.63 92.00 L171.99 92.00 A2.2 2.2 0 0 0 167.59 92.00 L164.96 92.00 A2.2 2.2 0 0 0 160.56 92.00 L157.92 92.00 A2.2 2.2 0 0 0 153.52 92.00 L150.89 92.00 A2.2 2.2 0 0 0 146.49 92.00 L143.86 92.00 A2.2 2.2 0 0 0 139.46 92.00 L136.82 92.00 A2.2 2.2 0 0 0 132.42 92.00 L129.79 92.00 A2.2 2.2 0 0 0 125.39 92.00 L122.75 92.00 A2.2 2.2 0 0 0 118.35 92.00 L115.72 92.00 A2.2 2.2 0 0 0 111.32 92.00 L108.68 92.00 A2.2 2.2 0 0 0 104.28 92.00 L101.65 92.00 A2.2 2.2 0 0 0 97.25 92.00 L94.61 92.00 A2.2 2.2 0 0 0 90.21 92.00 L87.58 92.00 A2.2 2.2 0 0 0 83.18 92.00 L80.54 92.00 A2.2 2.2 0 0 0 76.14 92.00 L73.51 92.00 A2.2 2.2 0 0 0 69.11 92.00 L66.48 92.00 A2.2 2.2 0 0 0 62.08 92.00 L59.44 92.00 A2.2 2.2 0 0 0 55.04 92.00 L52.41 92.00 A2.2 2.2 0 0 0 48.01 92.00 L45.37 92.00 A2.2 2.2 0 0 0 40.97 92.00 L38.34 92.00 A2.2 2.2 0 0 0 33.94 92.00 L31.30 92.00 A2.2 2.2 0 0 0 26.90 92.00 L24.27 92.00 A2.2 2.2 0 0 0 19.87 92.00 L17.23 92.00 A2.2 2.2 0 0 0 12.83 92.00 L10.20 92.00 A2.2 2.2 0 0 0 8.00 89.80 L8.00 87.20 A2.2 2.2 0 0 0 8.00 82.80 L8.00 80.20 A2.2 2.2 0 0 0 8.00 75.80 L8.00 73.20 A2.2 2.2 0 0 0 8.00 68.80 L8.00 66.20 A2.2 2.2 0 0 0 8.00 61.80 L8.00 59.20 A2.2 2.2 0 0 0 8.00 54.80 L8.00 52.20 A2.2 2.2 0 0 0 8.00 47.80 L8.00 45.20 A2.2 2.2 0 0 0 8.00 40.80 L8.00 38.20 A2.2 2.2 0 0 0 8.00 33.80 L8.00 31.20 A2.2 2.2 0 0 0 8.00 26.80 L8.00 24.20 A2.2 2.2 0 0 0 8.00 19.80 L8.00 17.20 A2.2 2.2 0 0 0 8.00 12.80 L8.00 10.20 A2.2 2.2 0 0 0 10.20 8.00 Z" fill="#F3EDE1" stroke="#12161C" stroke-width="0.7" stroke-linejoin="round" />
<rect x="15" y="15" width="190" height="70" fill="#7A3B2E" />
<path d="M61.06 66.41Q58.14 66.41 56.23 65.3Q54.33 64.2 53 62.46L53.96 61.72Q55.21 63.35 56.86 64.32Q58.51 65.29 61.1 65.29Q64.05 65.29 65.67 63.89Q67.28 62.5 67.28 59.88Q67.28 58.08 66.6 57.04Q65.92 56 64.73 55.46Q63.54 54.92 62.08 54.61L59.8 54.17Q57.46 53.73 56.12 52.83Q54.77 51.92 54.18 50.68Q53.58 49.44 53.58 47.98Q53.58 45.91 54.5 44.55Q55.42 43.19 57.08 42.52Q58.75 41.86 60.96 41.86Q63.61 41.86 65.38 42.78Q67.15 43.7 68.17 45.23L67.22 45.94Q66.2 44.48 64.67 43.73Q63.14 42.98 60.89 42.98Q58.07 42.98 56.46 44.21Q54.84 45.43 54.84 47.95Q54.84 49.61 55.54 50.61Q56.23 51.62 57.42 52.16Q58.61 52.71 60.08 53.01L62.35 53.45Q64.77 53.9 66.11 54.83Q67.45 55.77 67.98 57.04Q68.51 58.32 68.51 59.78Q68.51 61.95 67.61 63.42Q66.71 64.88 65.02 65.64Q63.34 66.41 61.06 66.41Z M78.56 66.41Q76.28 66.41 74.64 65.35Q72.99 64.3 72.09 62.29Q71.18 60.29 71.18 57.36Q71.18 54.44 72.07 52.42Q72.95 50.39 74.57 49.36Q76.18 48.32 78.46 48.32Q80.57 48.32 82.17 49.37Q83.76 50.43 84.67 52.35Q85.57 54.27 85.57 56.89V57.43H72.44V58.35Q72.44 61.51 74.06 63.43Q75.67 65.35 78.6 65.35Q80.64 65.35 82.08 64.35Q83.53 63.35 84.27 61.41L85.19 61.92Q84.44 63.96 82.74 65.18Q81.04 66.41 78.56 66.41ZM78.46 49.34Q76.56 49.34 75.21 50.21Q73.87 51.07 73.16 52.66Q72.44 54.24 72.44 56.34V56.48H84.27V56.28Q84.27 54.17 83.54 52.62Q82.81 51.07 81.5 50.21Q80.19 49.34 78.46 49.34Z M93.72 66H91.17Q90.42 66 90.06 65.63Q89.7 65.25 89.7 64.57V40.84H90.89V64.95H93.72Z M97.92 66V49.78H94.83V48.73H97.92V42.57Q97.92 41.76 98.33 41.3Q98.74 40.84 99.59 40.84H102.99V41.89H99.11V48.73H102.99V49.78H99.11V66Z M109.88 66H105.39V42.27H116.07Q118.28 42.27 119.84 43.19Q121.41 44.1 122.26 45.75Q123.11 47.4 123.11 49.61Q123.11 51.82 122.26 53.47Q121.41 55.12 119.84 56.04Q118.28 56.96 116.07 56.96H109.88ZM109.88 46.18V53.08H115.66Q116.55 53.08 117.16 52.76Q117.77 52.43 118.11 51.84Q118.45 51.24 118.45 50.39V48.83Q118.45 47.95 118.11 47.37Q117.77 46.79 117.16 46.48Q116.55 46.18 115.66 46.18Z M132.75 66.41Q130.24 66.41 128.38 65.27Q126.53 64.13 125.53 62.04Q124.53 59.95 124.53 57.09Q124.53 54.24 125.53 52.18Q126.53 50.12 128.38 48.98Q130.24 47.84 132.75 47.84Q135.3 47.84 137.16 48.98Q139.01 50.12 140.01 52.18Q141.02 54.24 141.02 57.09Q141.02 59.95 140.01 62.04Q139.01 64.13 137.16 65.27Q135.3 66.41 132.75 66.41ZM132.75 62.91Q134.49 62.91 135.47 61.83Q136.46 60.76 136.46 58.76V55.46Q136.46 53.45 135.47 52.4Q134.49 51.35 132.75 51.35Q131.09 51.35 130.08 52.4Q129.08 53.45 129.08 55.46V58.76Q129.08 60.76 130.08 61.83Q131.09 62.91 132.75 62.91Z M149.47 66.41Q146.92 66.41 145.19 65.54Q143.45 64.67 142.13 63.14L144.78 60.56Q145.77 61.68 146.94 62.33Q148.11 62.97 149.64 62.97Q151.21 62.97 151.9 62.43Q152.6 61.89 152.6 60.93Q152.6 60.15 152.11 59.69Q151.61 59.23 150.42 59.06L148.66 58.83Q146.75 58.59 145.43 57.94Q144.1 57.3 143.42 56.17Q142.74 55.05 142.74 53.45Q142.74 50.87 144.59 49.36Q146.45 47.84 149.47 47.84Q151.21 47.84 152.45 48.17Q153.69 48.49 154.64 49.12Q155.59 49.75 156.41 50.63L153.86 53.18Q153.08 52.37 151.99 51.82Q150.9 51.28 149.61 51.28Q148.25 51.28 147.58 51.77Q146.92 52.26 146.92 53.11Q146.92 54 147.45 54.46Q147.98 54.92 149.23 55.12L151.04 55.36Q153.96 55.77 155.37 57.08Q156.78 58.38 156.78 60.59Q156.78 62.29 155.88 63.62Q154.98 64.95 153.33 65.68Q151.68 66.41 149.47 66.41Z M168.09 66H164.97Q162.72 66 161.55 64.83Q160.38 63.65 160.38 61.48V51.69H157.76V48.25H159.12Q160.1 48.25 160.46 47.79Q160.82 47.33 160.82 46.42V43.39H164.73V48.25H168.37V51.69H164.73V62.53H168.09Z" fill="#F6EDE2" />
</svg>

After

Width:  |  Height:  |  Size: 7.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

+89 -19
View File
@@ -17,6 +17,13 @@ body {
}
main { max-width: 42rem; margin: 0 auto; }
h1 { font-size: 1.4rem; margin: 0 0 1rem; }
/* The full mark, on the two pages that have no navigation bar to carry the
compact one. It takes the column's width so its edges line up with the card
below it, capped at that column's own 24rem; height stays automatic because
the stamp's proportions are part of the mark and it is never scaled unevenly.
The subtitle stops resolving below 280px, which a 320px viewport still clears
once the body's padding is taken off. */
.mark { display: block; width: 100%; max-width: 24rem; height: auto; margin-bottom: 1.4rem; }
.card {
background: #fff; border: 1px solid #e2e5e9; border-radius: 10px;
padding: 1.5rem; margin: 0 auto;
@@ -50,14 +57,47 @@ button:hover, a.btn:hover { background: #1d4ed8; }
form's block layout; its button is styled like any other. */
form.inline { display: inline; margin: 0; }
main { max-width: 48rem; }
/* 48rem is a reading measure: right for the forms and prose that make up most
of the panel, and the width the navigation bar's two rows were sized for. The
three monitoring pages hold data instead — seven columns of send-log, and raw
mail.log lines that are long by nature — and at that width the send-log's
Subject and Status were fighting over the last inch while the log pages wrapped
every second line. They get a wider measure; every other page keeps the narrow
one. The class comes from the layout, which stamps the page name onto <main>. */
main.page-deliveries, main.page-mail_queue, main.page-system_log { max-width: 64rem; }
/* The signed-out pages are a single card and nothing else, and .card.narrow
centres itself inside whatever holds it — so at the panel's usual width the
card floated in the middle while the mark and the heading stayed at the far
left, three alignments on a page with four elements. Narrowing the column to
the card's own width makes the three line up and puts the block as a whole in
the middle of the page. */
main.page-login, main.page-setup { max-width: 24rem; }
.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; }
/* A table column is at least as wide as the longest unbreakable run inside it,
and the panel's tables are full of runs with nothing to break on: email
addresses, domains, queue ids. One 40-character recipient was enough to widen
the send-log past its card and hang Status over the edge. Cells may break mid
word, so a column can always be squeezed to the width available. */
th, td { text-align: left; padding: 0.5rem 0.4rem; border-bottom: 1px solid #e2e5e9; overflow-wrap: anywhere; }
/* The exception: a timestamp broken across two lines is unreadable, and it is
short enough to never be the reason a row does not fit. */
td.time { white-space: nowrap; }
@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; }
/* Subject is the one cell whose text we do not control. Breaking mid word (the
rule above) keeps it inside the card, but a long subject would do it by
growing the row several lines tall, which buries the rows around it. So the
subject is clipped to one line instead, with the whole of it in the tooltip.
The clamp sits on an inner block box rather than the cell because max-width
on a <td> is only advisory in the automatic table layout. */
td.subject span {
display: block; max-width: 18rem;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.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; } }
@@ -77,12 +117,28 @@ textarea { resize: vertical; }
}
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; }
.actions summary { display: inline-block; list-style: none; cursor: pointer; }
.actions summary::-webkit-details-marker { display: none; }
/* Applications are a list of blocks, not table rows. As a table it fell apart:
four columns of which the last held six controls — two of them <details>
panels with textareas — never fit the panel's 48rem. The controls wrapped
into a staircase, .code on the login cell grew into a slab as tall as the
row, and the two text cells sat on the baseline halfway down it. One block
per application gives the identity a line of its own and the controls a row
of their own, at the width they actually need. */
.apps { list-style: none; margin: 1.2rem 0 0; padding: 0; }
.app { padding: 0.9rem 0; border-top: 1px solid #e2e5e9; }
.app:last-child { padding-bottom: 0; }
@media (prefers-color-scheme: dark) { .app { border-color: #2b3138 !important; } }
.app-login { margin: 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 600; }
.app-addr { margin: 0.15rem 0 0; word-break: break-all; }
.app .actions { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.7rem; }
/* An open panel claims a row to itself: its textareas and number inputs want
the block's full width, not the width of the summary that opened them. */
.app .actions > details[open] { flex: 1 0 100%; }
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; } }
@@ -107,9 +163,21 @@ details form { margin-top: 0.6rem; }
}
@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
/* The top row: mark at one edge, session block at the other. Splitting them to
the edges is what makes the two rows read as two blocks rather than as one
ragged list that happened to wrap. */
.nav .top { display: flex; align-items: center; justify-content: space-between; gap: 0.9rem; }
.nav .session { justify-content: flex-end; }
/* The mark is a link, but not one of the bar's entries: it takes none of the
padding and rounding the entry rule below applies, so its own edge lines up
with the page rather than sitting half a step inside it. The stamp carries
about 4px of field inside the file at this size, which is what puts it level
with the icons of the row underneath. */
.nav .brand { padding: 0; }
/* width/height are on the element too, so the row reserves the space before the
SVG has loaded; these keep the ratio if the box is ever squeezed. The stamp's
proportions are part of the mark — it is never scaled unevenly. */
.nav .brand img { display: block; width: 110px; height: auto; }
/* 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
@@ -152,30 +220,32 @@ details form { margin-top: 0.6rem; }
.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 {
value, the controls of a table row or of an application block. Sign out
overrides this with .danger below since signing out is a deliberate,
singular action. .actions is the shared hook: a cell that holds controls, or
the control row of an application. */
button.copy, .actions button, .actions summary, .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:hover, .actions button:hover, .actions summary:hover,
.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 {
.actions details[open] > summary { background: #dde3ec; }
.actions button.danger, .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; }
.actions button.danger:hover, .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 {
button.copy, .actions button, .actions summary, .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 {
button.copy:hover, .actions button:hover, .actions summary:hover,
.actions a.danger:hover, .nav button:hover { background: #2b3138 !important; }
.actions details[open] > summary { background: #313841 !important; }
.actions button.danger, .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; }
.actions button.danger:hover, .actions a.danger:hover, .nav button.danger:hover { background: #3d1a18 !important; }
}