Compare commits

...
Author SHA1 Message Date
Kristian Wind 1f9f14099b Merge pull request #41 from kristianwind/calendar-lighter-pastels
CI / OpenAPI is valid (push) Successful in 53s
CI / End-to-end (push) Successful in 9m3s
CI / Docker image builds (push) Successful in 2m10s
Release / Build and publish image (push) Failing after 7s
CI / Go (push) Failing after 15m11s
Calendar: lighter grid, per-calendar pastels, today marked at top
2026-09-03 13:17:31 +02:00
kristianwindandClaude Opus 4.8 6cf63113df feat(calendar): lighter grid, per-calendar pastels, today marked at top
The calendar was a grey grid where every event was the same sunken block
edged in a colour you had to already know. Now the day itself is the
brightest surface and each event is a soft, dusty wash of its own
calendar's colour — so a screen of them reads as colour laid on white,
and two calendars are told apart at a glance. Tasks stay outlined cards,
the thing you can pick up, against the solid washes you cannot.

Today is marked where the day is named: its number sits in a filled disc
at the top of the column, the same one the month grid gives it, over a
faint wash down the whole column.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 13:09:07 +02:00
Kristian Wind e24a0fa849 Merge pull request #40 from kristianwind/sidebar-header-unify
Unify section and group headers with icons; scrollbar flush to the divider
2026-09-03 13:02:15 +02:00
kristianwindandClaude Opus 4.8 1c223a2c26 fix(sidebar): scrollbar flush to the divider, and match the group test
The scrollbar thumb centred a 4px bar in a 10px track behind a
transparent border, so it floated three pixels shy of the right edge.
The thumb is the track now — a thin 6px rounded bar sitting flush
against the divider line, where a scrollbar belongs.

The group heading is a heading now, not a project row: the smoke test
measured a group against the projects filed under it and read the
section icon as a dot. It measures a group against "Projekter" — the
tier it shares — and reads the icon both headings carry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 12:54:05 +02:00
kristianwindandClaude Opus 4.8 a9c90ee6f1 feat(ui): unify section and group headers with icons
System sections (Projects, Filters, Labels) and user groups (Work,
Home) now share one design: a bold label at menu size, a leading
folder/funnel/tag/people icon, and an always-visible fold chevron.
Groups drop their colour dot for the same folder icon, so the sidebar
reads as one consistent hierarchy instead of two visual languages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 12:34:07 +02:00
Kristian Wind dc4a584d5f Merge pull request #39 from kristianwind/sidebar-scrollbar-flush
fix(sidebar): scrollbar flush to the edge, thin and dim
2026-09-03 12:22:58 +02:00
35 changed files with 163 additions and 115 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 306 KiB

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 KiB

After

Width:  |  Height:  |  Size: 334 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: 263 KiB

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 KiB

After

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 KiB

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 228 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: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 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: 43 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 61 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: 45 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: 41 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

+27 -36
View File
@@ -383,19 +383,19 @@ test('en projektgruppe kan foldes, fyldes og slettes uden at tage projekterne me
await expect(heading).toBeVisible();
await expect(sidebar.getByText('Træk et projekt herop')).toBeVisible();
// A group's name must be readable in full, and must start where a project's
// name starts.
// A group's name must be readable in full, and must line up with the other
// headings — not with the projects filed under it.
//
// Both halves are here because both were once broken at the same time and for
// different reasons. "Omdøb" and "Slet" sat in the flow reserving their width
// even while invisible, so ARBEJDE was drawn as "ARBE"; and the fold chevron
// sat before the name, pushing a group 22px further in than the projects it
// contains — so a group read as if it were filed under them. Every assertion
// in this file passed through both, because both buttons still worked.
// The clipping half is here because it was once broken: "Omdøb" and "Slet" sat
// in the flow reserving their width even while invisible, so ARBEJDE was drawn
// as "ARBE". The alignment half changed meaning with the redesign: a group now
// carries a fold chevron and a section icon just like "Projekter" above it, and
// belongs to that heading tier rather than to the project rows below.
const shape = await sidebar.locator('.folder-head').evaluate((el) => {
const link = el.querySelector('h2 a');
const name = { ...link.querySelector('.dot').getBoundingClientRect().toJSON() };
// The last child of the link is the name itself; the dot is a span before it.
// The leading mark is now the section icon, the same folder/funnel/tag glyph
// the system headings carry — a group and a section read identically.
const name = { ...link.querySelector('.head-icon').getBoundingClientRect().toJSON() };
return {
clipped: link.scrollWidth > link.clientWidth + 1,
left: name.left,
@@ -407,17 +407,17 @@ test('en projektgruppe kan foldes, fyldes og slettes uden at tage projekterne me
expect(shape.clipped, 'gruppens navn bliver klippet').toBe(false);
expect(shape.count, 'navnet og tallet overlapper').toBeGreaterThanOrEqual(shape.right);
// Measured dot to dot, not box to box: both rows begin with the same coloured
// mark, and it is the only thing in them that means the same on both sides.
// Comparing the group's inner link with the project's outer box reported the
// row's own padding as a misalignment.
const projectLeft = await sidebar
.getByRole('link', { name: 'Regnskab' })
.evaluate((el) => el.querySelector('.dot').getBoundingClientRect().left);
// A group is a heading, not a project row: it belongs to the same tier as
// "Projekter" and the other system sections — chevron, icon, bold name — and
// starts where they start, not where the projects filed under it do. Measured
// icon to icon, the one mark both headings share.
const sectionLeft = await sidebar
.getByRole('heading', { name: 'Projekter' })
.evaluate((el) => el.querySelector('.head-icon').getBoundingClientRect().left);
expect(
Math.abs(shape.left - projectLeft),
`gruppen starter ${Math.round(shape.left - projectLeft)}px fra projekterne`
).toBeLessThanOrEqual(2);
Math.abs(shape.left - sectionLeft),
`gruppen starter ${Math.round(shape.left - sectionLeft)}px fra sektionsoverskrifterne`
).toBeLessThanOrEqual(4);
// Dragged in, then dragged back out onto "Projekter" — which is the reason
// that heading is a drop target at all: with every project filed away there
@@ -440,18 +440,13 @@ test('en projektgruppe kan foldes, fyldes og slettes uden at tage projekterne me
'false'
);
// En foldet gruppe står med sin chevron fremme permanent, og den lå oven i
// prikken med et felt i --surface bag sig — en lys firkant ud for navnet på
// den sænkede bjælke, hele tiden. Nu tones prikken ud i stedet, så der er
// ingenting at male henover den med.
const chevron = await sidebar
// A group's chevron is in the flow now, the same one the system sections carry —
// no absolute mark with a --surface field behind it, so a folded group no longer
// leaves a pale square beside its name on the sunken bar.
const chevronBg = await sidebar
.locator('.folder-head .chevron-button')
.evaluate((el) => ({
background: getComputedStyle(el).backgroundColor,
dot: getComputedStyle(el.closest('.folder-head').querySelector('.group-dot')).opacity
}));
expect(chevron.background, 'chevronen har en firkant bag sig').toBe('rgba(0, 0, 0, 0)');
expect(chevron.dot, 'prikken ligger stadig under chevronen').toBe('0');
.evaluate((el) => getComputedStyle(el).backgroundColor);
expect(chevronBg, 'chevronen har en firkant bag sig').toBe('rgba(0, 0, 0, 0)');
await sidebar.getByRole('button', { name: /^Fold Arbejde/ }).click();
@@ -467,11 +462,7 @@ test('en projektgruppe kan foldes, fyldes og slettes uden at tage projekterne me
// button on click.
await expect(sidebar.getByLabel('Gruppens navn')).toBeVisible();
await sidebar.getByLabel('Gruppens navn').press('Enter');
const painted = await sidebar
.locator('.folder-head .group-dot')
.evaluate((el) => getComputedStyle(el).backgroundColor);
expect(painted, 'gruppens prik fik ikke sin farve').not.toBe('rgba(0, 0, 0, 0)');
await expect(sidebar.getByRole('link', { name: 'Arbejde', exact: true })).toBeVisible();
// The heading itself is *not* indented — only what is filed under it. A heading
// that starts further in than the rows above it says the heading is inside
+49 -17
View File
@@ -651,6 +651,7 @@
<div
class="allday"
data-allday={iso(date)}
class:today={iso(date) === todayISO}
class:over={over === iso(date)}
ondragover={(e) => onDragOver(e, date)}
ondragleave={() => (over = null)}
@@ -876,12 +877,16 @@
overflow: hidden;
}
/* White, not the sidebar's sunken ground: a calendar reads lightest when the
day itself is the brightest thing on the screen and the events are the soft
colour laid on it — the opposite of the grey grid it was, where the events
had to shout to be seen at all. */
.corner,
.head,
.gutter,
.allday,
.daycol {
background: var(--ground);
background: var(--surface);
}
.head {
@@ -889,6 +894,16 @@
text-align: center;
}
/* Today's whole column, faintly, so the eye finds it before it reads a number —
the marker on the date above is the label, this is the glow it sits in. Kept
under the events, so a pastel block still reads as its own calendar's colour
rather than as this wash tinted. */
.head.today,
.allday.today,
.daycol.today {
background: color-mix(in oklab, var(--accent) 6%, var(--surface));
}
.head .wd {
display: block;
font-size: var(--text-xs);
@@ -901,9 +916,19 @@
font-size: var(--text-sm);
}
/* The marker at the top the day is named by: today's number in a filled disc,
the same one the month grid gives today, so "this is today" is one glance in
either view rather than a colour you have to already know to read. */
.head.today .num {
color: var(--accent);
color: var(--accent-ink);
background: var(--accent);
border-radius: var(--radius-full);
width: 20px;
height: 20px;
display: inline-grid;
place-items: center;
font-weight: 560;
margin-top: 1px;
}
.gutter {
@@ -977,6 +1002,10 @@
/* Placeringen kommer fra `place()` som en inline `style`; alt andet står her.
To ting på samme tid deler bredden, så `margin-right` er den ene hårstrå
luft, der gør to kasser til to kasser. */
/* A soft wash of the calendar's own colour rather than a grey block edged in it:
each calendar keeps a dusty, unmistakable nuance, and a screen of them reads
as colour laid on white instead of a grid of grey bars. The left edge stays,
a shade stronger than the fill, so the block still has a spine. */
.tevent {
position: absolute;
margin-right: 2px;
@@ -984,16 +1013,20 @@
padding: 1px var(--s1);
border-radius: var(--radius-sm);
border-left: 3px solid var(--event-colour, var(--line-strong));
background: var(--surface-sunken);
color: var(--ink-muted);
background: color-mix(in oklab, var(--event-colour, var(--line-strong)) 16%, var(--surface));
color: var(--ink);
font-size: var(--text-xs);
line-height: 1.3;
text-align: left;
text-decoration: none;
}
/* A task is a card you can pick up, not an event you cannot — so on the white
column it is an outlined card, where an event is a solid wash. The priority
colour rides the left edge, as it does everywhere else. */
.tevent.task {
background: var(--surface-raised);
background: var(--surface);
box-shadow: inset 0 0 0 1px var(--line);
border-left-color: var(--line-strong);
color: var(--ink);
cursor: grab;
@@ -1101,7 +1134,8 @@
text-align: left;
padding: 1px var(--s1);
border-radius: var(--radius-sm);
background: var(--surface-raised);
background: var(--surface);
box-shadow: inset 0 0 0 1px var(--line);
border-left: 2px solid var(--line-strong);
color: var(--ink);
overflow: hidden;
@@ -1120,7 +1154,7 @@
}
.chip:hover {
background: var(--surface);
background: var(--surface-sunken);
}
/* An event reads as a different kind of thing at a glance, before any of the
@@ -1140,8 +1174,8 @@
padding: 1px var(--s1);
border-radius: var(--radius-sm);
border-left: 3px solid var(--event-colour);
background: var(--surface-sunken);
color: var(--ink-muted);
background: color-mix(in oklab, var(--event-colour) 16%, var(--surface));
color: var(--ink);
text-decoration: none;
overflow: hidden;
text-overflow: ellipsis;
@@ -1156,7 +1190,7 @@
}
.event:hover {
background: var(--surface);
background: color-mix(in oklab, var(--event-colour) 26%, var(--surface));
color: var(--ink);
}
@@ -1165,7 +1199,7 @@
every calendar anybody has used. */
.event.allday {
border-left: none;
background: color-mix(in oklab, var(--event-colour) 22%, var(--ground));
background: color-mix(in oklab, var(--event-colour) 22%, var(--surface));
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--event-colour) 45%, transparent);
}
@@ -1267,20 +1301,18 @@
padding: 1px var(--s1);
border-radius: var(--radius-sm);
border-left: 2px solid var(--line-strong);
background: var(--surface-raised);
background: var(--surface);
box-shadow: inset 0 0 0 1px var(--line);
}
.calendar.week .chip[data-priority='1'] {
border-left-color: var(--p1);
background: var(--surface-raised);
}
.calendar.week .chip[data-priority='2'] {
border-left-color: var(--p2);
background: var(--surface-raised);
}
.calendar.week .chip[data-priority='3'] {
border-left-color: var(--p3);
background: var(--surface-raised);
}
/* Readable again in the week, for the reason the task chips are: a
@@ -1292,12 +1324,12 @@
padding: 1px var(--s1);
border-radius: var(--radius-sm);
border-left: 3px solid var(--event-colour);
background: var(--surface-sunken);
background: color-mix(in oklab, var(--event-colour) 16%, var(--surface));
}
.calendar.week .event.allday {
border-left: none;
background: color-mix(in oklab, var(--event-colour) 22%, var(--ground));
background: color-mix(in oklab, var(--event-colour) 22%, var(--surface));
}
.calendar.week .at {
+87 -62
View File
@@ -690,6 +690,64 @@
The whole heading is the target, not the chevron. At this size a lone chevron
is something you miss, and the name is where the eye already is.
-->
<!-- One monochrome mark per kind of heading, so a section and a group read as the
same kind of thing — a folder of projects, a funnel of filters, a tag of
labels — instead of one being a faint label and the other a coloured dot. -->
{#snippet sectionIcon(key)}
{#if key === 'filters'}
<svg class="head-icon" viewBox="0 0 16 16" aria-hidden="true">
<path
d="M2.2 3.4h11.6L9.3 8.8v3.4L6.7 10.9V8.8z"
fill="none"
stroke="currentColor"
stroke-width="1.4"
stroke-linejoin="round"
/>
</svg>
{:else if key === 'labels'}
<svg class="head-icon" viewBox="0 0 16 16" aria-hidden="true">
<path
d="M7.7 2.3H13v5.3l-5.3 5.3-5.3-5.3z"
fill="none"
stroke="currentColor"
stroke-width="1.4"
stroke-linejoin="round"
/>
<circle cx="10.2" cy="4.9" r="0.95" fill="currentColor" />
</svg>
{:else if key === 'shared'}
<svg class="head-icon" viewBox="0 0 16 16" aria-hidden="true">
<circle cx="6.2" cy="5.6" r="2.1" fill="none" stroke="currentColor" stroke-width="1.4" />
<path
d="M2.6 12.8c0-2.1 1.7-3.3 3.6-3.3s3.6 1.2 3.6 3.3"
fill="none"
stroke="currentColor"
stroke-width="1.4"
stroke-linecap="round"
/>
<path
d="M11 9.6c1.5.2 2.6 1.3 2.6 3.2"
fill="none"
stroke="currentColor"
stroke-width="1.4"
stroke-linecap="round"
/>
<circle cx="11.2" cy="5.6" r="1.7" fill="none" stroke="currentColor" stroke-width="1.4" />
</svg>
{:else}
<!-- Projekter and every group: a folder of projects. -->
<svg class="head-icon" viewBox="0 0 16 16" aria-hidden="true">
<path
d="M2 4.6a1 1 0 011-1h3.1l1.4 1.5H13a1 1 0 011 1v6.3a1 1 0 01-1 1H3a1 1 0 01-1-1z"
fill="none"
stroke="currentColor"
stroke-width="1.4"
stroke-linejoin="round"
/>
</svg>
{/if}
{/snippet}
{#snippet foldHeading(key, label)}
<h2 class="fold">
<button
@@ -704,6 +762,7 @@
>
<path d="M6 9l6 6 6-6" />
</svg>
{@render sectionIcon(key)}
{label}
</button>
</h2>
@@ -916,11 +975,7 @@
}, 200);
}}
>
<span
class="dot group-dot"
style="background: {colorVar(group.color)}"
aria-hidden="true"
></span>
{@render sectionIcon('group')}
{group.name}
</a>
</h2>
@@ -1087,14 +1142,16 @@
}
.scroller::-webkit-scrollbar {
width: 10px;
width: 6px;
}
/* No transparent border and no padding-box clip: those centred a 4px bar in a
10px track, so the thumb floated three pixels shy of the divider. The bar is
the track now — a thin rounded thumb sitting flush against the line on the
right, which is where a scrollbar belongs. */
.scroller::-webkit-scrollbar-thumb {
background: var(--line-strong);
border-radius: 999px;
border: 3px solid transparent;
background-clip: padding-box;
}
.scroller::-webkit-scrollbar-track {
@@ -1267,12 +1324,22 @@
background: var(--surface-sunken);
}
/* Every heading — the system sections and the user's groups — reads the same:
a mark, then a bold plainly-cased name. What used to set them apart (one a
faint uppercase label, the other a bold name with a coloured dot) is gone. */
h2 {
font-size: var(--text-xs);
font-weight: 560;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--ink-faint);
font-size: var(--menu-size);
font-weight: 600;
color: var(--ink);
}
/* The heading's mark, in the muted ink so the bold name still leads. Sized and
nudged like a row's own mark, so the icons line up down the sidebar. */
.head-icon {
width: 14px;
height: 14px;
flex: none;
color: var(--ink-muted);
}
/* Only the square icon buttons — "+" and the folder — and asked for by class
@@ -1373,39 +1440,17 @@
klods ud for navnet permanent, fordi chevronen bliver stående, når gruppen
er lukket. Prikken tones ud i stedet for at blive dækket — det er samme
skifte, uden noget at male henover den med. */
/* A group folds from its own chevron, the same one the system sections carry —
in the flow before the name now, not an absolute mark that appeared on hover,
so a group and a section read identically at rest. The name beside it is still
a link to the group's page; the chevron is the second intention. */
.chevron-button {
position: absolute;
left: calc(var(--s2) - 5px);
width: 18px;
height: 18px;
flex: none;
width: 14px;
height: 14px;
display: grid;
place-items: center;
border-radius: var(--radius-sm);
color: inherit;
opacity: 0;
/* Fordi prikken herunder tones ud frem for at blive dækket. En `opacity`
under 1 laver en stakkontekst og maler elementet, som var det placeret
med `z-index: 0` — så prikken, der står senere i DOM'en, lagde sig oven
på knappen i det øjeblik den forsvandt. Den var usynlig og tog stadig
klikket: prøven brugte tredive sekunder på at folde en gruppe, der ikke
ville foldes. Ét lag op, og rækkefølgen er den samme som før. */
z-index: 1;
}
.folder-head:hover .chevron-button,
.chevron-button:focus-visible,
.chevron-button[aria-expanded='false'] {
opacity: 1;
}
/* Præcis de tre tilfælde ovenfor, læst nedad i stedet for opad: står chevronen
der, er prikken væk. `opacity` og ikke `display`, for de to ligger oven i
hinanden — forsvandt prikken ud af flowet, ville navnet rykke sig hver gang
pilen kom frem. */
.folder-head:hover .group-dot,
.folder-head:has(.chevron-button:focus-visible) .group-dot,
.folder-head:has(.chevron-button[aria-expanded='false']) .group-dot {
opacity: 0;
}
.chevron-button:hover {
@@ -1485,14 +1530,6 @@
white-space: nowrap;
}
/* The group's own mark, between the chevron and the name — inside the fold
button, so it cannot push the heading in. It is a mark now and not a
control: the colour is chosen while renaming, which is the other edit to
the same thing. */
.group-dot {
flex: none;
}
/* Projects sit at the same left margin whether or not they are in an area —
one straight edge down the whole sidebar reads calmer than a staircase, and
the bold area heading above already does the grouping the indent used to. */
@@ -1508,18 +1545,6 @@
padding-left: var(--s2);
}
/* An area is the sidebar's own heading — Things treats it as bold and plainly
cased, a thing the eye lands on, not another faint uppercase label like the
system sections. So an area's name is set apart while "Projekter", "Filtre"
and "Etiketter" stay quiet. */
.folder-head h2 {
font-size: var(--menu-size);
font-weight: 600;
text-transform: none;
letter-spacing: 0;
color: var(--ink);
}
/* Inside the rename form now, so it needs no padding of its own — the form
already sits where the heading did. */
.renaming {