Files
margin-mail/src/screens/connectmail.css
T
pj eb59cb5f8d build the app, and ship it on Linux and Windows as well as macOS
The client itself: the sync engine and mirror, the Gmail and IMAP providers,
the screener, the three boxes and two piles, compose and send, the sanitiser
and tracker stripping, contacts, clips, backup, notifications and the guide.

The pipeline that ships it. Three runners now build in parallel and the
publish gate wants all four platform keys in latest.json before a release
leaves draft. Linux gets two more packages Tauri does not build: a flatpak
repackaged from the deb against GNOME 48, and a Nix package that relinks the
deb against nixpkgs so it runs as a native Wayland client rather than through
Xwayland. CI runs the Rust suite on all three desktops rather than on Linux
alone, and rebuilds the flatpak manifest on every push to main.

Two things that were only ever exercised on macOS and were wrong everywhere
else. The menu bar was built by adjusting the submenus macOS is given, so on
a platform whose default menu has no File or View the new File menu landed
after Edit, Check for Updates landed nowhere, and the three places and the
reading pane had no menu at all. The deb declared libwebkit2gtk-4.1-0 and
libgtk-3-0 twice, because tauri.conf.json named the dependencies Tauri
already emits.

The updater key exists now, so releases can sign their artifacts.
2026-09-06 12:15:30 +05:30

218 lines
5.7 KiB
CSS

/* The add-account flow: the address on the same centred stage as the welcome, then the sign-in
panel, and the servers in a sheet over it. The type, the ink and the paragraph widths are the
welcome screen's own and are shared with it rather than restated, so the panels are one screen.
What is here is the arrangement of the pieces, plus the two columns the sheet needs. */
/* The address, which is the whole of the first step: one field and one button, each as wide as
the column they are in and so as wide as each other, so the two read as one gesture. On the
stage the button is larger than a button anywhere else in the app, for the same reason it is the
only one there, and the field is a size up with it. In a sheet they are the panel's ordinary
size and the panel's full width, like every other field in one. */
.imap-address {
display: flex;
flex-direction: column;
gap: 14px;
width: 100%;
max-width: 26em;
text-align: left;
}
.imap-address .field {
width: 100%;
}
.welcome .imap-address .field-input {
padding: 9px 12px;
font-size: var(--t-4);
}
.welcome .imap-address .button {
min-height: 38px;
padding: 0 20px;
border-radius: var(--r-md);
font-size: var(--t-4);
}
.sheet .imap-address {
max-width: none;
}
/* The button, the field's width, and while a lookup is out the way to stop it beside it at its
own. */
.imap-go {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
}
.imap-go .button[data-variant="primary"] {
flex: 1;
}
/* The way to skip the lookup, under everything else on the address step: a ghost button in a
paragraph of its own, so it reads as an aside rather than as a second way in. */
.imap-aside {
margin: 14px 0 0;
}
.imap-form {
display: flex;
flex-direction: column;
gap: 14px;
width: 100%;
max-width: 26em;
text-align: left;
}
.imap-actions {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
margin-top: 4px;
}
/* Centred only on the stage, which is a column of centred text. Settings hosts the same flow in a
sheet, where everything else in the panel starts at the left edge and a row of buttons floating
in the middle would be the only thing that did not. */
.welcome .imap-actions {
justify-content: center;
}
/* The same panels in a sheet. On the stage each of these paragraphs holds itself off whatever is
above it, because a centred column has no other spacing; a panel body is a flex column with a gap
already, so the margins would be counted twice. Nothing else about the flow changes between the
two hosts, which is the point of it being one component. */
.sheet .welcome-line,
.sheet .welcome-privacy,
.sheet .welcome-trouble,
.sheet .imap-aside {
margin: 0;
}
/* The one thing a left edge exposes that a centred column hid. A ghost button carries the same
horizontal padding as a filled one, so on its own on a line it starts a button's padding in from
everything above it, and the field that does start at the edge is right there to compare it
with. Pulled back by exactly that padding rather than by an eyeballed number. */
.sheet .imap-aside .button {
margin-left: -12px;
}
/* A name and a value: the two servers on the panel that says what was found, and the four facts on
a certificate. The names line up in a column narrow enough that the values still read as a list
rather than as a table. */
.imap-facts {
margin: 0;
width: 100%;
max-width: 34em;
display: flex;
flex-direction: column;
gap: 7px;
text-align: left;
}
/* On the stage the list sits between a paragraph and the form, neither of which is a sheet's
evenly spaced body, so it carries its own room, and it is the form's width so the two share a
left edge in the centred column. */
.welcome .imap-facts {
margin: 6px 0 20px;
max-width: 26em;
}
.imap-fact {
display: grid;
grid-template-columns: 8.5em 1fr;
gap: 10px;
align-items: baseline;
}
.imap-fact dt {
color: var(--ink-faint);
font-size: var(--t-1);
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.imap-fact dd {
margin: 0;
min-width: 0;
font-size: var(--t-3);
font-variant-numeric: tabular-nums;
/* Somebody else's string, which is worth being able to select and paste. */
user-select: text;
}
/* A fingerprint is sixty-four characters that have to be compared against another sixty-four, so
it wraps wherever it must rather than pushing the panel wider than the window. */
.imap-fact dd[data-wrap] {
overflow-wrap: anywhere;
line-height: 1.5;
}
.imap-lead {
margin: 0;
font-size: var(--t-4);
line-height: 1.5;
}
.imap-note {
margin: 0;
color: var(--ink-soft);
font-size: var(--t-2);
line-height: 1.55;
}
/* The server's own words, verbatim. They are usually written for whoever runs the server rather
than for the person holding the laptop, which is why the sentence above them is ours. */
.imap-said {
margin: -6px 0 0;
color: var(--danger-ink);
font-size: var(--t-2);
line-height: 1.5;
user-select: text;
}
.imap-advice {
margin: -6px 0 0;
font-size: var(--t-3);
line-height: 1.5;
}
.imap-legs {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.imap-leg {
display: flex;
flex-direction: column;
gap: 12px;
min-width: 0;
}
.imap-leg-title {
margin: 0;
font-family: var(--font-heading);
font-weight: 500;
font-size: var(--t-4);
}
/* The sheet's buttons live in its foot, outside the form, so this is what Enter presses. */
.imap-enter {
display: none;
}
/* Two columns of five fields do not fit beside each other on a phone, and stacking them keeps the
order they are asked in: everything about incoming mail, then everything about outgoing. */
:root[data-phone] .imap-legs {
grid-template-columns: 1fr;
}
:root[data-phone] .imap-fact {
grid-template-columns: 1fr;
gap: 2px;
}