Files
everythingbutwork/apps/web/src/styles/globals.css
T
dejanandClaude Opus 4.7 95beb99cd4
ci / quality (push) Has been cancelled
ci / build (push) Has been cancelled
Zeiterfassung + Visual-Polish (Keycap-Buttons, Space Grotesk)
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>
2026-06-02 17:27:40 +02:00

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);
}