Compare commits

...
14 Commits
Author SHA1 Message Date
Kristian Wind 7770ba9844 Merge pull request #54 from kristianwind/tasks-first-tap-rounded
CI / OpenAPI is valid (push) Successful in 14s
CI / End-to-end (push) Successful in 11m2s
CI / Docker image builds (push) Successful in 2m40s
Release / Build and publish image (push) Failing after 8s
CI / Go (push) Failing after 15m27s
Rows: open on the first tap on iPhone, round the hover highlight
2026-09-03 22:23:08 +02:00
kristianwindandClaude Opus 4.8 55b8e438ad fix(rows): open on the first tap on iPhone, and round the hover highlight
On a touch screen a :hover on the tap target makes iOS spend the first tap
applying the hover and only open on the second — the double-tap Kristian hit
on tasks (and notes). The row hover is gated behind @media (hover: hover)
now, so a touch has no hover to apply and the first tap opens. The note
row's action buttons, which the hover used to reveal, are shown outright on
touch instead. And the task-row hover highlight is a rounded box (border
radius on the row), the same corner as a note in the list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 22:15:23 +02:00
Kristian Wind 1607a22f0c Merge pull request #53 from kristianwind/charcoal-separators
CI / OpenAPI is valid (push) Successful in 11s
CI / End-to-end (push) Successful in 9m56s
CI / Docker image builds (push) Successful in 2m2s
Release / Build and publish image (push) Failing after 5s
CI / Go (push) Failing after 15m10s
Charcoal: lighter day separators in the note list
2026-09-03 20:54:56 +02:00
kristianwindandClaude Opus 4.8 8a5dfef41a fix(theme): lighter day separators in Charcoal
In Charcoal the note-list day separators used --ground, the darkest colour
in the theme, so they read as dark bars on the lighter list. They take the
menu's own resting grey (#2d3133) now — the colour "Projekter" sits on —
via a --note-group-bg fallback token, so every other theme keeps --ground.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 20:46:51 +02:00
Kristian Wind 1a610eaac4 Merge pull request #52 from kristianwind/notes-single-tap
CI / OpenAPI is valid (push) Successful in 11s
CI / End-to-end (push) Successful in 10m25s
CI / Docker image builds (push) Successful in 1m58s
Release / Build and publish image (push) Failing after 6s
CI / Go (push) Failing after 15m11s
Notes: open on the first tap, not the second
2026-09-03 20:35:30 +02:00
kristianwindandClaude Opus 4.8 c2d4ce0179 fix(notes): open a note on the first tap, not the second
On a phone the list/editor switch keyed on the loaded note, which arrives a
moment after the tap — so the first tap looked like nothing happened and
people tapped again. It keys on the selected id now, set the instant a row
is tapped, so the pane switches at once; the back button is there
immediately and the body fills in when it arrives, with a quiet pane rather
than the "pick a note" prompt in the half-second between.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 20:27:28 +02:00
Kristian Wind a1b8cc6ddc Merge pull request #51 from kristianwind/notes-mobile-detail
CI / OpenAPI is valid (push) Successful in 10s
CI / End-to-end (push) Successful in 8m51s
CI / Docker image builds (push) Successful in 1m58s
Release / Build and publish image (push) Failing after 5s
CI / Go (push) Failing after 14m24s
Notes on a phone: show the note (master-detail layout)
2026-09-03 19:15:05 +02:00
kristianwindandClaude Opus 4.8 8a2c46f5ea fix(notes): show the note on a phone — one pane at a time
On a phone the note list and the editor stacked in one column, so a tapped
note opened below a full-height list, out of sight — "kan vælge en note men
kan ikke se indholdet". Now it is master-detail: the list fills the screen
until a note is opened, the editor takes over once one is, and an iOS-style
"‹ Noter" at the top of the editor goes back. The cards drop their border
and corners on one column, where there is nothing beside them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 19:07:02 +02:00
Kristian Wind 8d42f34065 Merge pull request #50 from kristianwind/charcoal-apple-colors
CI / OpenAPI is valid (push) Successful in 9s
CI / End-to-end (push) Successful in 8m47s
CI / Docker image builds (push) Successful in 1m48s
Release / Build and publish image (push) Failing after 6s
CI / Go (push) Failing after 14m30s
Match Charcoal theme to Apple Notes' exact colours
2026-09-03 17:51:16 +02:00
kristianwindandClaude Opus 4.8 905ceebc06 fix(theme): match Charcoal to Apple Notes' sampled colours
Kristian sent the exact values; the first Charcoal was a neutral grey guess
and missed them. Now: three panel greys, lightest sidebar (#2d3133) to
darkest editor (#1e1e1e) with the list (#242b2e) between — the reverse of
the usual sunken-is-darkest order, so the editor takes its own --editor-bg
rather than sharing the list's surface. The accent is amber: the selected
menu item is solid #ffce35 with dark text, a selected note is gold #a78c26
with dark text, and the section headings drop to a quiet grey (#8a8e90).

Each per-element colour is a fallback token only Charcoal sets, so every
other theme reads through to the shared token unchanged. Verified the
computed values land on Kristian's samples exactly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 17:42:55 +02:00
Kristian Wind 87c557941a Merge pull request #49 from kristianwind/theme-charcoal-polish
CI / OpenAPI is valid (push) Successful in 9s
CI / End-to-end (push) Successful in 8m47s
CI / Docker image builds (push) Successful in 1m47s
Release / Build and publish image (push) Failing after 5s
CI / Go (push) Failing after 14m25s
Charcoal theme, elegant selection, rounded note list, confirm sign-out
2026-09-03 16:37:44 +02:00
Kristian Wind 0e1e803486 Merge pull request #48 from kristianwind/totp-qr
2FA: show a scannable QR code when enabling two-factor auth
2026-09-03 16:37:36 +02:00
kristianwindandClaude Opus 4.8 1dc9751a33 test(e2e): sign out with the two-step confirm
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 16:29:18 +02:00
kristianwindandClaude Opus 4.8 b81f8f67cc feat(ui): Charcoal theme, elegant selection, rounded note list, confirm sign-out
- A new Charcoal theme — neutral dark greys on the menu, note list and
  editor instead of the default's faint green cast, with matching inks;
  the green accent stays. It joins the theme picker on its own (the picker
  is data-driven from THEMES).
- The text selection is a translucent wash of the accent, not the old
  near-invisible tint and not a solid slab — visible on white and on the
  dark surfaces, keeping the text's own colour.
- The note list is a rounded card now, the same corner and border as the
  editor beside it, with a few pixels more air around the menu and the list.
- Signing out asks first: a second click within a few seconds confirms, so
  a button the pointer passes over does not drop you at the login screen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 16:27:55 +02:00
40 changed files with 217 additions and 29 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 KiB

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 KiB

After

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 KiB

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 370 KiB

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 KiB

After

Width:  |  Height:  |  Size: 355 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 KiB

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

+6 -1
View File
@@ -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();
+52 -2
View File
@@ -210,6 +210,52 @@
--shadow-lg: 0 8px 32px rgb(0 0 0 / 0.4);
}
/* Kul — the greys of Apple Notes' dark mode, to Kristian's own sampled values.
Three panel greys, lightest sidebar to darkest editor — the reverse of the usual
sunken-is-darkest order, which is why the editor gets its own --editor-bg rather
than sharing --surface-raised with the list. The accent turns amber, and the
selected menu item, selected note and section headings each get a fallback token
so this theme can hit its colours without touching any other. */
[data-theme='charcoal'] {
--ground: #1e1e1e;
--surface: #2a3033;
--surface-raised: #242b2e; /* the note list */
--surface-sunken: #2d3133; /* the menu / sidebar — lightest here */
--line: #34393b;
--line-strong: #414749;
--ink: #ffffff;
--ink-muted: #dcdcdc;
--ink-faint: #9ba0a2;
/* Amber, Apple's Notes accent. The bright value is the selected menu item; the
dark text rides on top of it. */
--accent: #ffce35;
--accent-hover: #ffd75a;
--accent-sunken: #ffce35;
--accent-ink: #1e1e1e;
/* Per-element, and only here — every other theme falls back to the shared token
in the var() calls that read these. */
--editor-bg: #1e1e1e; /* the text field, a shade below the list */
--note-on-bg: #a78c26; /* a selected note in the list — gold */
--note-on-ink: #1e1e1e; /* dark text on the gold */
--nav-active-ink: #1e1e1e; /* dark text on the amber menu item */
--heading-ink: #8a8e90; /* PROJEKTER and the group names — quiet grey */
--note-group-bg: #2d3133; /* day separators take the menu's resting grey, not the darker ground */
--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 +421,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
+41 -7
View File
@@ -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}
<span class="offline" title={t('nav.offlineHint')}>{t('nav.offline')}</span>
{/if}
<button class="user" onclick={signOut}>
<button class="user" class:confirming={confirmSignOut} onclick={onSignOutClick}>
<span class="avatar" style="background: {app.user?.avatar_color}">
{app.user?.name?.[0]?.toUpperCase() ?? '?'}
</span>
<span class="user-name">{app.user?.name}</span>
<span class="signout">{t('nav.signOut')}</span>
<span class="user-name">{confirmSignOut ? t('nav.signOutConfirm') : app.user?.name}</span>
<span class="signout">{confirmSignOut ? '' : t('nav.signOut')}</span>
</button>
</div>
</div>
@@ -1091,14 +1108,16 @@
display: flex;
flex-direction: column;
gap: var(--s5);
padding: var(--s4) var(--s3);
/* A few pixels more air down each side than the rows strictly need, so the
menu breathes rather than sitting flush against its own edges. */
padding: var(--s4) calc(var(--s3) + 3px);
background: var(--surface-sunken);
border-right: 1px solid var(--line);
/* Selve bjælken ruller ikke længere — .scroller gør. `hidden` frem for
ingenting, fordi den stadig er den yderste kant: løber en række over,
skal den klippes her og ikke skubbe kolonnen bredere. */
overflow: hidden;
padding-left: max(var(--s3), env(safe-area-inset-left));
padding-left: max(calc(var(--s3) + 3px), env(safe-area-inset-left));
position: relative;
}
@@ -1317,7 +1336,9 @@
h2 {
font-size: var(--menu-size);
font-weight: 600;
color: var(--ink);
/* Kul sets these headings to a quiet grey (--heading-ink); every other theme
falls back to the reading ink and keeps them bold and bright. */
color: var(--heading-ink, var(--ink));
}
/* The heading's mark, in the muted ink so the bold name still leads. Sized and
@@ -1572,7 +1593,10 @@
in both themes. */
a.active {
background: var(--accent-sunken);
color: var(--ink);
/* On a solid accent (Kul's amber menu item) the label goes dark via
--nav-active-ink; on the tinted accent-sunken every other theme uses, it
falls back to the reading ink. */
color: var(--nav-active-ink, var(--ink));
font-weight: 600;
}
@@ -1695,6 +1719,16 @@
background: var(--surface);
}
/* Asking to confirm: the row goes to the danger tint and the name is replaced by
"click again", so the second click is plainly the one that signs out. */
.user.confirming {
background: var(--danger-sunken);
}
.user.confirming .user-name {
color: var(--danger);
}
.avatar {
width: 22px;
height: 22px;
+10 -2
View File
@@ -228,13 +228,21 @@
align-items: flex-start;
padding: var(--s3) var(--s2);
border-bottom: 1px solid var(--line);
border-radius: var(--radius);
transition:
opacity var(--medium) var(--ease),
transform var(--medium) var(--ease);
}
.row:hover {
background: var(--surface);
/* Hover only where there is a real pointer. On a touch screen a :hover on the tap
target makes iOS spend the first tap applying the hover and only open on the
second — the "double-tap" on iPhone. With no hover to apply, the first tap opens
the task. The rounded corners are on the row itself, so the highlight is a
rounded box like a note in the list. */
@media (hover: hover) {
.row:hover {
background: var(--surface);
}
}
/* The exit: a short lift and fade, so completing something reads as the task
+3
View File
@@ -119,6 +119,7 @@ export const da = {
'nav.calendar': 'Kalender',
'nav.settings': 'Indstillinger',
'nav.signOut': 'Log ud',
'nav.signOutConfirm': 'Tryk igen for at logge ud',
'nav.main': 'Hovedmenu',
'nav.search': 'Søg',
'nav.searchLong': 'Søg i opgaver og projekter',
@@ -843,6 +844,8 @@ export const da = {
// --- the themes -------------------------------------------------------------------
'theme.dark': 'Nordlys',
'theme.darkNote': 'Mørk med grøn accent.',
'theme.charcoal': 'Kul',
'theme.charcoalNote': 'Neutral mørkegrå.',
'theme.dusk': 'Skumring',
'theme.duskNote': 'Mørk og varm, med rav.',
'theme.light': 'Dagslys',
+3
View File
@@ -115,6 +115,7 @@ export const en = {
'nav.calendar': 'Calendar',
'nav.settings': 'Settings',
'nav.signOut': 'Sign out',
'nav.signOutConfirm': 'Click again to sign out',
'nav.main': 'Main menu',
'nav.search': 'Search',
'nav.searchLong': 'Search tasks and projects',
@@ -836,6 +837,8 @@ export const en = {
// --- the themes -------------------------------------------------------------------
'theme.dark': 'Northern lights',
'theme.darkNote': 'Dark, with a green accent.',
'theme.charcoal': 'Charcoal',
'theme.charcoalNote': 'Neutral dark grey.',
'theme.dusk': 'Dusk',
'theme.duskNote': 'Dark and warm, with amber.',
'theme.light': 'Daylight',
+1
View File
@@ -1006,6 +1006,7 @@ export const completedView = new CompletedView();
*/
export const THEMES = [
{ id: 'dark', name: 'theme.dark', note: 'theme.darkNote', dark: true },
{ id: 'charcoal', name: 'theme.charcoal', note: 'theme.charcoalNote', dark: true },
{ id: 'dusk', name: 'theme.dusk', note: 'theme.duskNote', dark: true },
{ id: 'light', name: 'theme.light', note: 'theme.lightNote', dark: false },
{ id: 'paper', name: 'theme.paper', note: 'theme.paperNote', dark: false },
+101 -17
View File
@@ -707,7 +707,10 @@
}}
/>
<div class="notes">
<!-- `has-note` drives the phone layout: one column, showing the list until a note
is opened and the editor once one is. On a wide screen both are always up and
the class does nothing. -->
<div class="notes" class:has-note={selectedId}>
<aside>
<div class="head">
<h1>{t('notes.title')}</h1>
@@ -916,7 +919,15 @@
</aside>
<section class="editor">
{#if selected}
{#if selectedId}
<!-- Keyed on the id, which is set the instant a row is tapped — not on the
loaded note, which arrives a moment later. On a phone that moment was the
whole bug: the pane did not switch until the body had loaded, so the first
tap looked like nothing and people tapped again. -->
<!-- Phone only (hidden on a wide screen by CSS): the way back to the list,
since there the editor fills the screen and the list is not beside it. -->
<button class="back" onclick={() => open(null)}>‹ {t('notes.title')}</button>
{#if selected}
<NoteEditor
note={selected}
notes={notes}
@@ -1050,6 +1061,12 @@
{/if}
</div>
</footer>
{:else}
<!-- Chosen, but its full text is still loading. Keep the pane (so the tap
felt like it landed) and stay quiet — the "pick a note" line is for
when nothing is chosen at all, not for this half-second. -->
<p class="empty" aria-busy="true"></p>
{/if}
{:else}
<p class="empty">{t('notes.pickOne')}</p>
{/if}
@@ -1068,8 +1085,9 @@
against the sidebar's rule, which reads as a rendering fault rather than
as a layout. */
/* Luft hele vejen rundt om arket. Højre og bund var nul, dengang editoren
ingen kant havde og ingenting kunne støde imod. */
padding: var(--s3) var(--s4) var(--s3) var(--s4);
ingen kant havde og ingenting kunne støde imod. Et par pixels mere om
notelisten, så kortet ikke ligger klods op ad menuen. */
padding: var(--s3) var(--s4) var(--s3) calc(var(--s4) + 3px);
display: grid;
grid-template-columns: minmax(220px, 300px) 1fr;
gap: var(--s4);
@@ -1083,13 +1101,15 @@
gap: var(--s2);
min-height: 0;
min-width: 0;
border-right: 1px solid var(--line);
padding-right: var(--s3);
/* A rounded card, the same corner and border as the editor beside it — the
list is its own sheet, not a column ruled off the page. */
border: 1px solid var(--line);
border-radius: var(--radius);
/* White in light, a nuance lighter than the ground in dark — the note list
is a surface you read down, so it lifts off the page like the editor does.
--surface-raised is #fff in the light themes and one step up in the dark. */
background: var(--surface-raised);
padding-left: var(--s3);
padding: var(--s3);
}
.head {
@@ -1386,7 +1406,10 @@
top: 0;
z-index: 1;
margin: 0 0 var(--s1);
background: var(--ground);
/* --ground everywhere but Kul, where the ground is the darkest thing on screen
and a day separator on it reads as a dark bar. There it takes the menu's own
resting colour instead, via --note-group-bg. */
background: var(--note-group-bg, var(--ground));
border-radius: var(--radius);
}
@@ -1472,13 +1495,38 @@
white-space: nowrap;
}
.row:hover {
background: var(--surface);
/* Pointer only. On a touch screen a :hover on the tap target costs a tap — iOS
spends the first applying the hover and opens on the second. Gated, the first
tap opens the note. The row's buttons are shown outright on touch below, since
there is no hover to reveal them. */
@media (hover: hover) {
.row:hover {
background: var(--surface);
}
}
@media (hover: none) {
.star,
.archive-one {
opacity: 1;
}
}
.row.on {
background: var(--surface-raised);
color: var(--ink);
background: var(--note-on-bg, var(--surface-raised));
color: var(--note-on-ink, var(--ink));
}
/* On a themed selection colour (Kul's gold), the row's own quieter tiers go dark
too, or the date and the filed line vanish into it. Other themes have no
--note-on-ink, so these fall back to their normal muted inks. */
.row.on .when,
.row.on .filed {
color: var(--note-on-ink, var(--ink-muted));
}
.row.on .filed-icon {
color: var(--note-on-ink, var(--ink-faint));
}
/* Samme størrelse som en opgavetitel. En note og en opgave er to ting af samme
@@ -1574,8 +1622,10 @@
min-height: 0;
min-width: 0;
/* A nuance lighter than the ground in dark, still white in light — matches
the note list beside it so the two read as one writing surface. */
background: var(--surface-raised);
the note list beside it so the two read as one writing surface. Kul gives
the text field its own darker grey via --editor-bg; other themes fall back
to the shared surface so the list and the editor stay the same colour. */
background: var(--editor-bg, var(--surface-raised));
border: 1px solid var(--line);
border-radius: var(--radius);
/* Luft nok til at teksten ikke rører kanten.
@@ -1894,14 +1944,48 @@
font-size: var(--text-sm);
}
/* The way back to the list on a phone — an iOS-style "‹ Noter" at the top of the
editor. Hidden on a wide screen, where the list is always beside the editor. */
.back {
display: none;
align-self: flex-start;
align-items: center;
gap: var(--s1);
margin-bottom: var(--s2);
padding: var(--s1) 0;
font-size: var(--text-base);
color: var(--accent);
}
@media (max-width: 700px) {
.notes {
grid-template-columns: 1fr;
padding: 0;
gap: 0;
}
aside {
border-right: 0;
padding-right: 0;
/* One pane at a time. The two-column card layout has no room on a phone, so
the list shows until a note is opened and the editor takes over once one is
— the back button is the way between them. Without this the editor stacked
below a full-height list, so a tapped note opened out of sight. */
.notes.has-note aside {
display: none;
}
.notes:not(.has-note) .editor {
display: none;
}
/* Full-bleed: the card border and rounded corners are for sitting beside
another card, and on one column there is nothing beside it. */
aside,
.editor {
border: 0;
border-radius: 0;
}
.back {
display: inline-flex;
}
}
</style>