Zeiterfassung - Neue Tabelle time_entry mit started_at/ended_at/duration_seconds, optional todo_id/bezug, category-Enum (focus/meeting/break/admin/learning/other), description, day_entry_id-Verknüpfung. Partial-Unique-Index erzwingt max. einen aktiven Timer pro User. - tRPC time-Router: now, start (stoppt aktiven automatisch), stop, listToday (Liste + Tagessumme), update, upsertManual (retroaktiv), delete, teamToday (personenübergreifend mit byCategory + aktivem Timer pro User). - TopNav: persistente TimerPill links neben Streak. Quick-Picker mit heutigen ToDos, Kategorie-Auswahl und Freitext-Start. Live-Sekundenzähler. - /heute: TimelineSection mit Edit/Delete pro Eintrag, ToDo-Bindung nachträglich änderbar, Block-nachtragen-Dialog. Pro ToDo-Zeile ▶-Start- und 🕐-Nachtrag-Button. - /puls: TeamTimeSection mit aktiver Timer-Anzeige + Tagessumme + Kategorie-Breakdown pro User (refresh alle 30s, Live-Tick jede Sekunde). Visual - Space Grotesk als Hausschrift (selbst-gehostet, latin + latin-ext) - Keycap-Button-Stil (Gradient + Druckeffekt) für primary/secondary/destructive - Neue Helper-Module: format-duration, time-categories Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
196 lines
5.0 KiB
CSS
196 lines
5.0 KiB
CSS
@import 'tailwindcss';
|
|
|
|
/* ------ Hausschrift: Space Grotesk (lokal gehostet, wie tool-ctrl.de) ------- */
|
|
|
|
@font-face {
|
|
font-family: 'Space Grotesk';
|
|
font-style: normal;
|
|
font-weight: 300 700;
|
|
font-display: swap;
|
|
src: url(/fonts/space-grotesk-latin.woff2) format('woff2');
|
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
|
|
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
|
|
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
}
|
|
@font-face {
|
|
font-family: 'Space Grotesk';
|
|
font-style: normal;
|
|
font-weight: 300 700;
|
|
font-display: swap;
|
|
src: url(/fonts/space-grotesk-latin-ext.woff2) format('woff2');
|
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
|
|
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
|
|
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
|
|
U+A720-A7FF;
|
|
}
|
|
|
|
/* ------ Brand Tokens (UX-Spec § Visual Design Foundation) ------- */
|
|
|
|
@theme {
|
|
/* Neutrals */
|
|
--color-bg: #ffffff;
|
|
--color-surface: #fafafa;
|
|
--color-surface-elevated: #ffffff;
|
|
--color-border: #e5e5e5;
|
|
--color-border-strong: #d4d4d4;
|
|
--color-ink: #0a0a0a;
|
|
--color-ink-muted: #525252;
|
|
--color-ink-faint: #a3a3a3;
|
|
--color-brand: #0a0a0a;
|
|
--color-brand-fg: #ffffff;
|
|
|
|
/* Ampel */
|
|
--color-ampel-green-fg: #15803d;
|
|
--color-ampel-green-bg: #dcfce7;
|
|
--color-ampel-amber-fg: #a16207;
|
|
--color-ampel-amber-bg: #fef3c7;
|
|
--color-ampel-red-fg: #b91c1c;
|
|
--color-ampel-red-bg: #fee2e2;
|
|
|
|
/* Trend */
|
|
--color-trend-up: #15803d;
|
|
--color-trend-flat: #525252;
|
|
--color-trend-down: #b91c1c;
|
|
|
|
/* Typografie */
|
|
--font-sans: 'Space Grotesk', 'Helvetica Neue', Arial, sans-serif;
|
|
--font-mono: 'JetBrains Mono', 'SF Mono', Menlo, monospace;
|
|
|
|
/* Radii */
|
|
--radius-sm: 6px;
|
|
--radius-md: 10px;
|
|
--radius-lg: 16px;
|
|
--radius-xl: 24px;
|
|
|
|
/* Shadows */
|
|
--shadow-sm: 0 1px 2px rgba(10, 10, 10, 0.04);
|
|
--shadow-md: 0 4px 12px rgba(10, 10, 10, 0.06);
|
|
--shadow-lg: 0 12px 32px rgba(10, 10, 10, 0.1);
|
|
}
|
|
|
|
/* ------ Base styles ------- */
|
|
|
|
html {
|
|
font-family: var(--font-sans);
|
|
-webkit-font-smoothing: antialiased;
|
|
text-rendering: optimizeLegibility;
|
|
}
|
|
|
|
body {
|
|
background: var(--color-bg);
|
|
color: var(--color-ink);
|
|
margin: 0;
|
|
}
|
|
|
|
*:focus-visible {
|
|
outline: 2px solid var(--color-ink);
|
|
outline-offset: 2px;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
animation-duration: 0ms !important;
|
|
transition-duration: 0ms !important;
|
|
}
|
|
}
|
|
|
|
/* Reusable utility classes (NFR-9 — ≤ 3 Klicks Workflow). */
|
|
|
|
.skip-link {
|
|
position: absolute;
|
|
top: -40px;
|
|
left: 0;
|
|
background: var(--color-ink);
|
|
color: var(--color-brand-fg);
|
|
padding: 8px 16px;
|
|
z-index: 100;
|
|
text-decoration: none;
|
|
}
|
|
.skip-link:focus {
|
|
top: 0;
|
|
}
|
|
|
|
/* ------ Keycap-Buttons (ToolCTRL-Website-Stil) ------- */
|
|
|
|
.btn-keycap {
|
|
position: relative;
|
|
border-width: 1.5px;
|
|
border-style: solid;
|
|
border-radius: 6px;
|
|
transition:
|
|
transform 0.08s ease,
|
|
box-shadow 0.08s ease,
|
|
background 0.15s ease,
|
|
color 0.15s ease;
|
|
}
|
|
.btn-keycap:active:not(:disabled) {
|
|
transform: translateY(5px);
|
|
}
|
|
.btn-keycap:disabled {
|
|
transform: none;
|
|
box-shadow: none;
|
|
}
|
|
|
|
.btn-keycap-solid {
|
|
background: linear-gradient(180deg, #3a3a3a 0%, #1a1a1a 55%, #0e0e0e 100%);
|
|
color: #ffffff;
|
|
border-color: #000000;
|
|
box-shadow:
|
|
0 5px 0 0 #000000,
|
|
0 10px 12px -5px rgba(0, 0, 0, 0.5),
|
|
inset 0 1.5px 0 0 rgba(255, 255, 255, 0.2),
|
|
inset 0 -6px 9px -10px rgba(0, 0, 0, 0.9);
|
|
}
|
|
.btn-keycap-solid:hover:not(:disabled) {
|
|
background: linear-gradient(180deg, #454545 0%, #232323 55%, #131313 100%);
|
|
}
|
|
.btn-keycap-solid:active:not(:disabled) {
|
|
box-shadow:
|
|
0 0 0 0 #000000,
|
|
0 3px 5px -2px rgba(0, 0, 0, 0.5),
|
|
inset 0 1.5px 0 0 rgba(255, 255, 255, 0.14),
|
|
inset 0 -5px 8px -10px rgba(0, 0, 0, 0.85);
|
|
}
|
|
|
|
.btn-keycap-ghost {
|
|
background: linear-gradient(180deg, #ffffff 0%, #f1f1ef 60%, #e5e5e2 100%);
|
|
color: var(--color-ink);
|
|
border-color: #bebebe;
|
|
box-shadow:
|
|
0 5px 0 0 #b0b0b0,
|
|
0 10px 12px -6px rgba(0, 0, 0, 0.25),
|
|
inset 0 1.5px 0 0 rgba(255, 255, 255, 0.95),
|
|
inset 0 -5px 8px -10px rgba(0, 0, 0, 0.3);
|
|
}
|
|
.btn-keycap-ghost:hover:not(:disabled) {
|
|
background: linear-gradient(180deg, #ffffff 0%, #ececea 60%, #dcdcd9 100%);
|
|
}
|
|
.btn-keycap-ghost:active:not(:disabled) {
|
|
box-shadow:
|
|
0 0 0 0 #b0b0b0,
|
|
0 3px 5px -2px rgba(0, 0, 0, 0.22),
|
|
inset 0 1.5px 0 0 rgba(255, 255, 255, 0.9),
|
|
inset 0 -4px 7px -10px rgba(0, 0, 0, 0.28);
|
|
}
|
|
|
|
.btn-keycap-destructive {
|
|
background: linear-gradient(180deg, #d54040 0%, #b91c1c 55%, #9a1414 100%);
|
|
color: #ffffff;
|
|
border-color: #8a1313;
|
|
box-shadow:
|
|
0 5px 0 0 #7a0f0f,
|
|
0 10px 12px -5px rgba(0, 0, 0, 0.4),
|
|
inset 0 1.5px 0 0 rgba(255, 255, 255, 0.18);
|
|
}
|
|
.btn-keycap-destructive:hover:not(:disabled) {
|
|
background: linear-gradient(180deg, #e04848 0%, #c92020 55%, #aa1717 100%);
|
|
}
|
|
.btn-keycap-destructive:active:not(:disabled) {
|
|
box-shadow:
|
|
0 0 0 0 #7a0f0f,
|
|
0 3px 5px -2px rgba(0, 0, 0, 0.4);
|
|
}
|