diff --git a/web/e2e/smoke.spec.js b/web/e2e/smoke.spec.js
index 7ba54ee..a0fab27 100644
--- a/web/e2e/smoke.spec.js
+++ b/web/e2e/smoke.spec.js
@@ -2030,7 +2030,12 @@ test('en passkey kan registreres og logges ind med', async ({ browser, browserNa
// Now sign out and back in with it. No email typed: the device knows which
// account its key belongs to, which is also why this page cannot be used to
// find out who has an account here.
- await page.getByRole('navigation', { name: 'Hovedmenu' }).getByText('Log ud').click();
+ // Signing out asks first now: one click arms it, a second within a few seconds
+ // does it. The whole account row is the button; its label changes to the prompt.
+ const signOut = page.getByRole('navigation', { name: 'Hovedmenu' }).locator('.user');
+ await signOut.click();
+ await expect(signOut).toContainText('Tryk igen for at logge ud');
+ await signOut.click();
// `exact`, because "Log ind" is a substring of "Log ind med en passkey" and
// Playwright matches an accessible name loosely unless told otherwise.
await expect(page.getByRole('button', { name: 'Log ind', exact: true })).toBeVisible();
diff --git a/web/src/app.css b/web/src/app.css
index 40d29a4..7a3e702 100644
--- a/web/src/app.css
+++ b/web/src/app.css
@@ -210,6 +210,40 @@
--shadow-lg: 0 8px 32px rgb(0 0 0 / 0.4);
}
+/* Kul — a neutral dark grey, the greys of Apple Notes rather than the default's
+ faint green cast. The same green accent, so it still reads as verdande; only the
+ grounds, surfaces and inks turn to plain grey. */
+[data-theme='charcoal'] {
+ --ground: #1c1c1c;
+ --surface: #232323;
+ --surface-raised: #2b2b2b;
+ --surface-sunken: #171717;
+ --line: #363636;
+ --line-strong: #474747;
+
+ --ink: #ededed;
+ --ink-muted: #a4a4a4;
+ /* Light enough to clear 4.5:1 against the ground — the quiet tier of dates and
+ counts is the first to disappear if it is too dim. */
+ --ink-faint: #8e8e8e;
+
+ --accent: #5fbf8f;
+ --accent-hover: #6fcf9f;
+ --accent-sunken: #23332b80;
+ --accent-ink: #0d1411;
+
+ --p1: #cf6b6b;
+ --p2: #d69f5c;
+ --p3: #6b9ecf;
+ --p4: var(--ink-faint);
+
+ --danger: #cf6b6b;
+ --danger-sunken: #33201f;
+
+ --shadow: 0 1px 2px rgb(0 0 0 / 0.25);
+ --shadow-lg: 0 8px 32px rgb(0 0 0 / 0.4);
+}
+
/* Papir — warm light, closer to paper than to a screen. */
[data-theme='paper'] {
--ground: #f6f1e7;
@@ -375,9 +409,13 @@ button {
søgefelt. */
}
+/* A translucent wash of the accent, not a solid block and not the old near-invisible
+ tint. --accent-sunken sat a hair off the editor's own surface in dark, so a
+ selection could not be seen; a solid accent could, but read as a heavy slab. Mixing
+ the accent part-way into transparent lays a clear green film over the text while it
+ keeps its own colour — visible on white and on the dark surfaces alike. */
::selection {
- background: var(--accent-sunken);
- color: var(--ink);
+ background: color-mix(in oklab, var(--accent) 42%, transparent);
}
/* Scrollbars, made quiet. The default on Windows is a wide grey slab that
diff --git a/web/src/lib/components/Sidebar.svelte b/web/src/lib/components/Sidebar.svelte
index 2749ad8..4b27051 100644
--- a/web/src/lib/components/Sidebar.svelte
+++ b/web/src/lib/components/Sidebar.svelte
@@ -34,6 +34,23 @@
location.href = '/';
}
+ // Signing out is one click from a button the pointer passes over on its way to
+ // everything below it, and it drops you at the login screen — so it asks first.
+ // A second click within a few seconds confirms; anything else lets it lapse. Not
+ // a dialog: a two-step button is lighter and stays where the eye already is.
+ let confirmSignOut = $state(false);
+ let signOutTimer;
+ function onSignOutClick() {
+ if (confirmSignOut) {
+ clearTimeout(signOutTimer);
+ signOut();
+ return;
+ }
+ confirmSignOut = true;
+ clearTimeout(signOutTimer);
+ signOutTimer = setTimeout(() => (confirmSignOut = false), 3500);
+ }
+
let filters = $state([]);
let labels = $state([]);
@@ -1050,12 +1067,12 @@
{#if !app.connected}
{t('nav.offline')}
{/if}
-