Files
gooseek/backend/webui/src/app/globals.css
home a0e3748dde feat: auth service + security audit fixes + cleanup legacy services
Major changes:
- Add auth-svc: JWT auth, register/login/refresh, password reset
- Add auth UI: modals, pages (/login, /register, /forgot-password)
- Add usage tracking (usage_metrics table, daily limits)
- Add tiered rate limiting (free/pro/business)
- Add LLM usage limits per tier

Security fixes:
- All repos now require userID for Update/Delete operations
- JWT middleware in chat-svc, llm-svc, agent-svc, discover-svc
- ErrNotFound/ErrForbidden errors for proper access control

Cleanup:
- Remove legacy TypeScript services/ directory
- Remove computer-svc (to be reimplemented)
- Remove old deploy/docker configs

New files:
- backend/cmd/auth-svc/main.go
- backend/internal/auth/{types,repository}.go
- backend/internal/usage/{types,repository}.go
- backend/pkg/middleware/{llm_limits,ratelimit_tiered}.go
- backend/webui/src/components/auth/*
- backend/webui/src/app/(auth)/*

Made-with: Cursor
2026-02-28 01:33:49 +03:00

860 lines
18 KiB
CSS

@tailwind base;
@tailwind components;
@tailwind utilities;
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap');
:root {
/* Cursor IDE 2026 Dark Theme */
/* Base backgrounds - very dark with slight blue tint */
--bg-base: 240 6% 4%;
--bg-elevated: 240 6% 8%;
--bg-surface: 240 5% 11%;
--bg-overlay: 240 5% 14%;
--bg-muted: 240 4% 18%;
/* Text colors - zinc-based for readability */
--text-primary: 240 5% 92%;
--text-secondary: 240 4% 68%;
--text-muted: 240 4% 48%;
--text-faint: 240 3% 38%;
/* Accent colors - indigo/purple like Cursor */
--accent: 239 84% 67%;
--accent-hover: 239 84% 74%;
--accent-muted: 239 60% 55%;
--accent-subtle: 239 40% 25%;
/* Secondary accent - cyan for variety */
--accent-secondary: 187 85% 55%;
--accent-secondary-muted: 187 60% 40%;
/* Semantic colors */
--success: 142 71% 45%;
--success-muted: 142 50% 35%;
--warning: 38 92% 50%;
--warning-muted: 38 70% 40%;
--error: 0 72% 51%;
--error-muted: 0 60% 40%;
/* Border colors */
--border: 240 4% 16%;
--border-hover: 240 4% 22%;
--border-focus: 239 60% 50%;
/* Legacy mappings for compatibility */
--background: var(--bg-base);
--foreground: var(--text-primary);
--card: var(--bg-elevated);
--card-foreground: var(--text-primary);
--popover: var(--bg-surface);
--popover-foreground: var(--text-primary);
--primary: var(--accent);
--primary-foreground: 0 0% 100%;
--secondary: var(--bg-surface);
--secondary-foreground: var(--text-secondary);
--muted: var(--bg-muted);
--muted-foreground: var(--text-muted);
--accent-color: var(--accent);
--accent-foreground: 0 0% 100%;
--destructive: var(--error);
--destructive-foreground: 0 0% 100%;
--input: var(--bg-surface);
--ring: var(--accent);
--radius: 0.75rem;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
color-scheme: dark;
}
body {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
background: hsl(var(--bg-base));
color: hsl(var(--text-primary));
min-height: 100vh;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
letter-spacing: -0.01em;
}
/* Gradient backgrounds */
.bg-gradient-main {
background: linear-gradient(
180deg,
hsl(240 6% 4%) 0%,
hsl(240 6% 5%) 50%,
hsl(240 5% 6%) 100%
);
}
.bg-gradient-elevated {
background: linear-gradient(
180deg,
hsl(240 6% 9% / 0.9) 0%,
hsl(240 6% 7% / 0.8) 100%
);
}
.bg-gradient-card {
background: linear-gradient(
180deg,
hsl(240 5% 11% / 0.6) 0%,
hsl(240 5% 9% / 0.4) 100%
);
}
/* Accent gradient for special elements */
.bg-gradient-accent {
background: linear-gradient(
135deg,
hsl(239 84% 67%) 0%,
hsl(260 84% 67%) 50%,
hsl(239 84% 67%) 100%
);
}
/* Text gradient */
.text-gradient {
background: linear-gradient(
135deg,
hsl(239 84% 74%) 0%,
hsl(260 90% 75%) 50%,
hsl(187 85% 65%) 100%
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Gradient border button */
.btn-gradient {
position: relative;
background: transparent;
border: none;
border-radius: 0.75rem;
padding: 0.625rem 1rem;
font-size: 0.875rem;
font-weight: 500;
color: hsl(239 84% 74%);
transition: all 0.15s ease;
z-index: 1;
}
.btn-gradient::before {
content: '';
position: absolute;
inset: 0;
border-radius: 0.75rem;
padding: 1.5px;
background: linear-gradient(
135deg,
hsl(239 84% 74%) 0%,
hsl(260 90% 75%) 50%,
hsl(187 85% 65%) 100%
);
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
}
.btn-gradient:hover {
background: linear-gradient(
135deg,
hsl(239 84% 74% / 0.1) 0%,
hsl(260 90% 75% / 0.1) 50%,
hsl(187 85% 65% / 0.1) 100%
);
}
.btn-gradient:active {
transform: scale(0.98);
}
/* Gradient border - larger version */
.btn-gradient-lg {
position: relative;
background: transparent;
border: none;
border-radius: 0.75rem;
padding: 0.75rem 1.25rem;
font-size: 0.875rem;
font-weight: 500;
color: hsl(239 84% 74%);
transition: all 0.15s ease;
z-index: 1;
}
.btn-gradient-lg::before {
content: '';
position: absolute;
inset: 0;
border-radius: 0.75rem;
padding: 2px;
background: linear-gradient(
135deg,
hsl(239 84% 74%) 0%,
hsl(260 90% 75%) 50%,
hsl(187 85% 65%) 100%
);
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
}
.btn-gradient-lg:hover {
background: linear-gradient(
135deg,
hsl(239 84% 74% / 0.1) 0%,
hsl(260 90% 75% / 0.1) 50%,
hsl(187 85% 65% / 0.1) 100%
);
}
/* Gradient text for buttons */
.btn-gradient-text {
background: linear-gradient(
135deg,
hsl(239 84% 74%) 0%,
hsl(260 90% 75%) 50%,
hsl(187 85% 65%) 100%
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Gradient active state for selectable items */
.active-gradient {
position: relative;
background: linear-gradient(
135deg,
hsl(239 84% 74% / 0.1) 0%,
hsl(260 90% 75% / 0.08) 50%,
hsl(187 85% 65% / 0.06) 100%
);
}
.active-gradient::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
padding: 1px;
background: linear-gradient(
135deg,
hsl(239 84% 74% / 0.4) 0%,
hsl(260 90% 75% / 0.3) 50%,
hsl(187 85% 65% / 0.2) 100%
);
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
}
/* Gradient border for cards on hover */
.hover-gradient:hover {
position: relative;
}
.hover-gradient:hover::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
padding: 1px;
background: linear-gradient(
135deg,
hsl(239 84% 74% / 0.3) 0%,
hsl(260 90% 75% / 0.2) 50%,
hsl(187 85% 65% / 0.15) 100%
);
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
}
/* Gradient icon wrapper */
.icon-gradient {
display: inline-flex;
align-items: center;
justify-content: center;
background: linear-gradient(
135deg,
hsl(239 84% 74% / 0.15) 0%,
hsl(260 90% 75% / 0.1) 50%,
hsl(187 85% 65% / 0.08) 100%
);
position: relative;
}
.icon-gradient::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
padding: 1px;
background: linear-gradient(
135deg,
hsl(239 84% 74% / 0.25) 0%,
hsl(260 90% 75% / 0.2) 50%,
hsl(187 85% 65% / 0.15) 100%
);
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
}
/* Gradient focus state for inputs */
.input-gradient:focus {
outline: none;
border-color: transparent;
box-shadow: 0 0 0 1px hsl(239 84% 74% / 0.4),
0 0 0 3px hsl(239 84% 74% / 0.1);
}
/* Gradient loader */
.loader-gradient {
color: hsl(239 84% 74%);
filter: drop-shadow(0 0 8px hsl(239 84% 74% / 0.3));
}
/* Progress bar gradient */
.progress-gradient {
background: linear-gradient(
90deg,
hsl(239 84% 74%) 0%,
hsl(260 90% 75%) 50%,
hsl(187 85% 65%) 100%
);
}
/* Stat card gradient */
.stat-gradient {
background: linear-gradient(
135deg,
hsl(239 84% 74% / 0.08) 0%,
hsl(260 90% 75% / 0.05) 100%
);
border: 1px solid;
border-image: linear-gradient(
135deg,
hsl(239 84% 74% / 0.25) 0%,
hsl(187 85% 65% / 0.15) 100%
) 1;
}
/* Gradient glow effect */
.glow-gradient {
box-shadow: 0 0 20px hsl(239 84% 74% / 0.15),
0 0 40px hsl(260 90% 75% / 0.1),
0 0 60px hsl(187 85% 65% / 0.05);
}
/* Border left gradient indicator */
.border-l-gradient {
position: relative;
}
.border-l-gradient::after {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 2px;
height: 60%;
background: linear-gradient(
180deg,
hsl(239 84% 74%) 0%,
hsl(260 90% 75%) 50%,
hsl(187 85% 65%) 100%
);
border-radius: 1px;
}
/* Modern thin scrollbars */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: hsl(240 4% 20%);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: hsl(240 4% 28%);
}
/* Hide scrollbar utility */
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
::selection {
background: hsl(239 84% 67% / 0.3);
}
/* Code font */
.font-mono {
font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', Consolas, monospace;
}
@layer base {
* {
@apply border-border;
}
}
@layer components {
/* Glass morphism card */
.glass-card {
@apply bg-surface/60 backdrop-blur-xl border border-border rounded-2xl;
}
/* Surface card with hover */
.surface-card {
@apply bg-elevated/40 backdrop-blur-sm border border-border/50 rounded-xl;
@apply transition-all duration-200;
}
.surface-card:hover {
@apply border-border-hover bg-elevated/60;
}
/* Input styles */
.input-cursor {
@apply bg-surface/50 border border-border rounded-xl px-4 py-3;
@apply text-primary placeholder:text-muted;
@apply focus:outline-none focus:border-accent/50 focus:ring-1 focus:ring-accent/20;
@apply transition-all duration-200;
}
/* Primary button - gradient accent */
.btn-primary {
@apply bg-accent/10 text-accent-foreground border border-accent/30;
@apply rounded-xl px-4 py-2.5 text-sm font-medium;
@apply hover:bg-accent/20 hover:border-accent/50;
@apply active:bg-accent/25;
@apply transition-all duration-150;
}
.btn-primary-solid {
@apply bg-accent text-white border-none;
@apply rounded-xl px-4 py-2.5 text-sm font-medium;
@apply hover:bg-accent-hover;
@apply active:scale-[0.98];
@apply transition-all duration-150;
}
/* Secondary button */
.btn-secondary {
@apply bg-surface/50 text-secondary border border-border;
@apply rounded-xl px-4 py-2.5 text-sm font-medium;
@apply hover:bg-muted/50 hover:text-primary hover:border-border-hover;
@apply transition-all duration-150;
}
/* Ghost button */
.btn-ghost {
@apply text-secondary hover:text-primary;
@apply hover:bg-surface/50 rounded-xl px-3 py-2;
@apply transition-all duration-150;
}
/* Icon button */
.btn-icon {
@apply w-9 h-9 flex items-center justify-center rounded-xl;
@apply text-muted hover:text-secondary hover:bg-surface/50;
@apply transition-all duration-150;
}
.btn-icon-active {
@apply bg-accent/15 text-accent;
}
/* Navigation item */
.nav-item {
@apply flex items-center gap-3 px-3 py-2.5 rounded-xl;
@apply text-secondary hover:text-primary;
@apply hover:bg-surface/40 transition-all duration-150;
}
.nav-item-active {
@apply bg-accent/10 text-primary;
@apply border-l-2 border-accent;
}
/* Card styles */
.card {
@apply bg-elevated/40 backdrop-blur-sm;
@apply border border-border/50 rounded-2xl;
@apply transition-all duration-200;
}
.card:hover {
@apply border-border bg-elevated/60;
}
.card-interactive {
@apply cursor-pointer;
}
.card-interactive:hover {
@apply border-accent/30 shadow-lg shadow-accent/5;
}
/* Section headers */
.section-header {
@apply text-xs font-semibold uppercase tracking-wider text-muted;
}
/* Badges */
.badge {
@apply inline-flex items-center px-2 py-0.5 rounded-lg text-xs font-medium;
@apply bg-surface text-secondary border border-border/50;
}
.badge-accent {
@apply bg-accent/15 text-accent border-accent/30;
}
.badge-success {
@apply bg-success/15 text-success border-success/30;
}
.badge-warning {
@apply bg-warning/15 text-warning border-warning/30;
}
.badge-error {
@apply bg-error/15 text-error border-error/30;
}
/* Divider */
.divider {
@apply border-t border-border/50;
}
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
/* Glow effects */
.glow-accent {
box-shadow: 0 0 20px hsl(239 84% 67% / 0.15),
0 0 40px hsl(239 84% 67% / 0.1);
}
.glow-accent-strong {
box-shadow: 0 0 30px hsl(239 84% 67% / 0.25),
0 0 60px hsl(239 84% 67% / 0.15);
}
.glow-subtle {
box-shadow: 0 4px 20px hsl(240 6% 4% / 0.5);
}
/* Focus ring */
.focus-ring {
@apply focus:outline-none focus:ring-2 focus:ring-accent/50 focus:ring-offset-2 focus:ring-offset-base;
}
/* Animation delays */
.animate-delay-75 { animation-delay: 75ms; }
.animate-delay-100 { animation-delay: 100ms; }
.animate-delay-150 { animation-delay: 150ms; }
.animate-delay-200 { animation-delay: 200ms; }
.animate-delay-300 { animation-delay: 300ms; }
.animate-delay-400 { animation-delay: 400ms; }
.animate-delay-500 { animation-delay: 500ms; }
}
/* Smooth animations */
@keyframes fade-in {
0% { opacity: 0; transform: translateY(4px); }
100% { opacity: 1; transform: translateY(0); }
}
@keyframes fade-in-up {
0% { opacity: 0; transform: translateY(12px); }
100% { opacity: 1; transform: translateY(0); }
}
@keyframes slide-in-right {
0% { opacity: 0; transform: translateX(-12px); }
100% { opacity: 1; transform: translateX(0); }
}
@keyframes slide-in-left {
0% { opacity: 0; transform: translateX(12px); }
100% { opacity: 1; transform: translateX(0); }
}
@keyframes scale-in {
0% { opacity: 0; transform: scale(0.95); }
100% { opacity: 1; transform: scale(1); }
}
@keyframes pulse-soft {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
@keyframes glow-pulse {
0%, 100% {
box-shadow: 0 0 20px hsl(239 84% 67% / 0.15);
}
50% {
box-shadow: 0 0 30px hsl(239 84% 67% / 0.25);
}
}
.animate-fade-in {
animation: fade-in 0.2s ease-out forwards;
}
.animate-fade-in-up {
animation: fade-in-up 0.3s ease-out forwards;
}
.animate-slide-in-right {
animation: slide-in-right 0.25s ease-out forwards;
}
.animate-slide-in-left {
animation: slide-in-left 0.25s ease-out forwards;
}
.animate-scale-in {
animation: scale-in 0.2s ease-out forwards;
}
.animate-pulse-soft {
animation: pulse-soft 2s ease-in-out infinite;
}
.animate-shimmer {
background: linear-gradient(
90deg,
hsl(240 5% 11%) 0%,
hsl(240 5% 16%) 50%,
hsl(240 5% 11%) 100%
);
background-size: 200% 100%;
animation: shimmer 1.5s linear infinite;
}
.animate-glow-pulse {
animation: glow-pulse 2s ease-in-out infinite;
}
/* =====================
Computer UI Styles
===================== */
/* Action step container */
.action-step {
@apply relative;
}
.action-step::before {
content: '';
position: absolute;
left: 1.25rem;
top: 2.75rem;
bottom: 0;
width: 2px;
background: linear-gradient(
to bottom,
hsl(var(--border)) 0%,
transparent 100%
);
}
/* Strikethrough animation for completed tasks */
@keyframes strikethrough {
from {
width: 0;
}
to {
width: 100%;
}
}
.task-completed {
position: relative;
}
.task-completed::after {
content: '';
position: absolute;
left: 0;
top: 50%;
height: 1px;
background: hsl(var(--text-muted));
animation: strikethrough 0.3s ease-out forwards;
}
/* Typing indicator */
@keyframes typing-dot {
0%, 20% { opacity: 0; }
50% { opacity: 1; }
100% { opacity: 0; }
}
.typing-indicator span {
animation: typing-dot 1.4s infinite;
}
.typing-indicator span:nth-child(2) {
animation-delay: 0.2s;
}
.typing-indicator span:nth-child(3) {
animation-delay: 0.4s;
}
/* Code highlight colors */
.code-keyword { color: #c792ea; }
.code-string { color: #c3e88d; }
.code-comment { color: #546e7a; font-style: italic; }
.code-function { color: #82aaff; }
.code-number { color: #f78c6c; }
.code-operator { color: #89ddff; }
/* Thinking block pulse */
@keyframes thinking-pulse {
0%, 100% {
background: hsl(239 84% 67% / 0.05);
}
50% {
background: hsl(239 84% 67% / 0.12);
}
}
.thinking-active {
animation: thinking-pulse 2s ease-in-out infinite;
}
/* Status indicator pulse */
@keyframes status-pulse {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.1);
opacity: 0.8;
}
}
.status-active {
animation: status-pulse 1.5s ease-in-out infinite;
}
/* File card hover effect */
.file-card-hover {
transition: all 0.2s ease;
}
.file-card-hover:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px -5px rgba(0, 0, 0, 0.3);
}
/* Collapsible animation */
.collapsible-content {
overflow: hidden;
transition: max-height 0.3s ease-out, opacity 0.2s ease-out;
}
/* Progress bar shimmer */
@keyframes progress-shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
.progress-shimmer {
background: linear-gradient(
90deg,
hsl(239 84% 67%) 0%,
hsl(260 90% 75%) 25%,
hsl(187 85% 65%) 50%,
hsl(260 90% 75%) 75%,
hsl(239 84% 67%) 100%
);
background-size: 200% 100%;
animation: progress-shimmer 2s linear infinite;
}
/* Event timeline line */
.timeline-line {
position: relative;
}
.timeline-line::before {
content: '';
position: absolute;
left: 0.5rem;
top: 1.5rem;
bottom: 0;
width: 1px;
background: linear-gradient(
to bottom,
hsl(var(--border)) 0%,
transparent 100%
);
}
/* Artifact card glow on hover */
.artifact-glow:hover {
box-shadow:
0 0 20px hsl(142 71% 45% / 0.15),
0 4px 12px rgba(0, 0, 0, 0.2);
}