Settle on one visual language

The interface had drifted into two of everything. The calendar and its
popovers were built around a blue accent the rest of the app had long since
replaced with green, five different sizes served the same class of small
label, and page sections were a stack of identical bordered cards that gave
no sense of what mattered most. Sections now separate by space and a hairline,
the overview leads with its headline figure at a size that says so, and the
palette, type scale and spacing live in one place as variables rather than
scattered literals.

Two things were not styled at all. The sign-in screen was an unstyled form in
the top-left corner, and the tip cards had no rules whatsoever despite their
markup already carrying a severity, so every tip rendered identically with a
plain green square for its dismiss control.

The calendar was also unusable on a narrow screen: the preset rail never
collapsed and covered the last three columns of the grid.
This commit is contained in:
2026-09-18 01:39:34 +02:00
parent f2b3920cbc
commit 296b596778
15 changed files with 757 additions and 433 deletions
+163 -31
View File
@@ -20,9 +20,9 @@
align-items: center;
justify-content: center;
padding: var(--sp-5);
background-color: var(--c-bg);
background-color: var(--c-surface);
border-radius: var(--radius);
border: 1px solid var(--c-border);
box-shadow: var(--shadow-sm);
}
.overview-metrics__value {
@@ -157,36 +157,48 @@
color: var(--c-text-muted);
}
/* Hero */
/* Hero — the headline figure. This is the one element on Översikt allowed
* a tinted background; everything below it gives up cards/borders in favor
* of whitespace precisely so this keeps reading as the most important thing
* on the page (see AGENTS.md's "clear hierarchy per screen"). */
.dashboard-hero {
padding: var(--sp-5);
padding: var(--sp-6) var(--sp-6);
margin-bottom: var(--sp-6);
border-radius: var(--radius);
border-left: 4px solid var(--c-accent);
border-left: 3px solid var(--c-accent);
background-color: var(--c-accent-weak);
}
.dashboard-hero--warning {
border-left-color: var(--c-warning);
border-left-color: var(--c-danger);
background-color: var(--c-danger-weak);
}
.dashboard-hero__message {
margin: 0;
font-size: var(--fs-xl);
font-weight: 600;
font-size: var(--fs-2xl);
font-weight: 700;
line-height: 1.25;
letter-spacing: -0.01em;
color: var(--c-text);
}
/* Shown while headline figures are still the statutory assumption (no FK
* fetch or manual entry has happened yet) — see `Dashboard.tsx`. */
.dashboard__fetch-actions {
display: flex;
gap: var(--sp-3);
flex-wrap: wrap;
}
.dashboard__estimate-badge {
display: inline-block;
margin: var(--sp-3) 0;
padding: var(--sp-1) var(--sp-3);
border-radius: 999px;
border-radius: var(--radius-full);
font-size: var(--fs-sm);
font-weight: 600;
background-color: #fef8e7;
background-color: var(--c-warning-weak);
color: var(--c-warning);
cursor: help;
}
@@ -196,6 +208,16 @@
display: flex;
flex-direction: column;
gap: var(--sp-4);
margin-bottom: var(--sp-6);
}
.age4-bars__title {
font-size: var(--fs-base);
font-weight: 600;
color: var(--c-text-muted);
text-transform: uppercase;
letter-spacing: 0.02em;
margin-bottom: 0;
}
.age4-bars__row {
@@ -210,16 +232,17 @@
.age4-bars__track {
width: 100%;
height: 20px;
background-color: var(--c-bg);
border-radius: var(--radius);
height: 10px;
background-color: var(--c-surface);
border-radius: var(--radius-full);
overflow: hidden;
border: 1px solid var(--c-border);
box-shadow: inset 0 0 0 1px var(--c-border);
}
.age4-bars__fill {
height: 100%;
background-color: var(--c-accent);
border-radius: var(--radius-full);
transition: width 0.3s ease;
}
@@ -240,6 +263,16 @@
display: flex;
flex-direction: column;
gap: var(--sp-3);
margin-bottom: var(--sp-6);
}
.year-timeline__title {
font-size: var(--fs-base);
font-weight: 600;
color: var(--c-text-muted);
text-transform: uppercase;
letter-spacing: 0.02em;
margin-bottom: var(--sp-1);
}
.year-timeline__row {
@@ -258,10 +291,10 @@
.year-timeline__track {
position: relative;
flex: 1;
height: 28px;
background-color: var(--c-bg);
border-radius: var(--radius);
border: 1px solid var(--c-border);
height: 24px;
background-color: var(--c-surface);
border-radius: var(--radius-sm);
box-shadow: inset 0 0 0 1px var(--c-border);
overflow: hidden;
}
@@ -269,27 +302,39 @@
position: absolute;
top: 0;
height: 100%;
min-width: 2px;
min-width: 3px;
border: none;
cursor: pointer;
padding: 0;
transition: opacity 0.15s;
}
.year-timeline__band:hover {
opacity: 0.85;
}
.year-timeline__band:hover,
.year-timeline__band:focus-visible {
outline: 2px solid var(--c-text);
outline-offset: -2px;
}
/* Plan Fold (collapsed plan-proposal summary) */
/* Plan Fold (collapsed plan-proposal summary) — these stay bordered even
* though the plain content sections around them dropped their cards: a
* <details> disclosure control needs a visible boundary so it reads as
* something to click, not another paragraph of content. */
.plan-fold,
.dashboard__more-details {
border: 1px solid var(--c-border);
border-radius: var(--radius);
padding: var(--sp-4);
padding: var(--sp-4) var(--sp-5);
background-color: var(--c-surface);
}
.plan-fold + .plan-fold,
.dashboard__more-details + .dashboard__more-details {
margin-top: var(--sp-4);
}
.plan-fold__summary,
.dashboard__more-details summary {
cursor: pointer;
@@ -312,11 +357,11 @@ button {
}
button:hover:not(:disabled) {
background-color: #1f5a3b;
background-color: var(--c-accent-hover);
}
button:active:not(:disabled) {
background-color: #0f4a2f;
background-color: var(--c-accent-active);
}
/* Secondary button */
@@ -418,6 +463,14 @@ button.ghost:hover:not(:disabled) {
margin-bottom: var(--sp-4);
}
.settings-page__label {
font-size: var(--fs-base);
}
.settings-page__select {
max-width: 320px;
}
.settings-page__checkbox-label {
display: flex;
align-items: center;
@@ -468,7 +521,7 @@ button.ghost:hover:not(:disabled) {
}
.settings-page__button:not(:disabled):hover {
background-color: #1f5a3b;
background-color: var(--c-accent-hover);
}
.settings-page__button:focus-visible {
@@ -545,7 +598,7 @@ button.ghost:hover:not(:disabled) {
border-radius: 999px;
font-size: var(--fs-sm);
font-weight: 400;
background-color: #fef8e7;
background-color: var(--c-warning-weak);
color: var(--c-warning);
cursor: help;
}
@@ -559,7 +612,7 @@ button.ghost:hover:not(:disabled) {
}
.vacation-days-table__save:not(:disabled):hover {
background-color: #1f5a3b;
background-color: var(--c-accent-hover);
}
.vacation-days-table__save:focus-visible {
@@ -704,13 +757,13 @@ legend {
}
.day-overrides-input__status--working {
background-color: #fef3c7;
color: #92400e;
background-color: var(--c-warning-weak);
color: var(--c-warning);
}
.day-overrides-input__status--off {
background-color: #dbeafe;
color: #1e40af;
background-color: var(--c-success-weak);
color: var(--c-success);
}
.day-overrides-input__item-note {
@@ -918,6 +971,85 @@ legend {
font-size: var(--fs-sm);
}
/* Tip Card (Optimization Tips, Översikt) — previously had no CSS at all,
* so every tip fell back to a plain `<button>` for its dismiss control
* (a solid accent-green square) and no visual grouping. The severity
* modifier classes already existed on the markup; only the color-coding
* they imply was missing. */
.tip-card {
padding: var(--sp-4);
border-left: 3px solid var(--c-border);
background-color: var(--c-surface);
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.tip-card + .tip-card {
margin-top: var(--sp-3);
}
.tip-card--info {
border-left-color: var(--c-text-faint);
}
.tip-card--warning {
border-left-color: var(--c-warning);
background-color: var(--c-warning-weak);
}
.tip-card--action {
border-left-color: var(--c-accent);
background-color: var(--c-accent-weak);
}
.tip-card__header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: var(--sp-3);
margin-bottom: var(--sp-1);
}
.tip-card__title {
margin: 0;
font-size: var(--fs-base);
font-weight: 600;
color: var(--c-text);
}
.tip-card__dismiss {
flex-shrink: 0;
width: 24px;
height: 24px;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
color: var(--c-text-muted);
border: none;
border-radius: var(--radius-sm);
font-size: var(--fs-base);
line-height: 1;
cursor: pointer;
transition: background-color 0.15s, color 0.15s;
}
.tip-card__dismiss:hover {
background-color: rgba(0, 0, 0, 0.06);
color: var(--c-text);
}
.tip-card__dismiss:focus-visible {
outline: 2px solid var(--c-accent);
outline-offset: 1px;
}
.tip-card__body {
margin: 0;
font-size: var(--fs-sm);
color: var(--c-text-muted);
}
/* Responsive */
@media (max-width: 640px) {
[data-testid='metrics-list'] {