Oliver-ai-bot_2.0/frontend/app/globals.css
Vadym Samoilenko aa23c309d4 feat: file attachments, model badge, Russian RAG fix, trust score calibration
- Add POST /chat/attachment endpoint with markitdown extraction for docs/images
- Add GET /chat?attachment_id= query param to inject attachment into assistant context
- Update model names: gpt-5.2, claude-sonnet-4-6, gemini-3.1-pro-preview
- Fix Google API event loop blocking (wrap in asyncio.to_thread)
- Add Russian query translation step in RAG retriever (with 10s timeout fallback)
- Fix corrective RAG grader treating empty Gemini response as irrelevant
- Add safety fallback: if corrective RAG empties results, use originals
- Recalibrate trust score: answer_groundedness 50% weight (was retrieval-heavy)
- Deduplicate sources by filename in citations
- Add llm_model/llm_provider to SSE done event and message store
- Show model badge (Cpu icon) at bottom of each assistant response
- Fix enum migration bug in 002, 005, 006 (remove create_type=False)
- Add migrations 010 (role varchar), 011 (enum varchar), 012 (app_settings)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 17:31:00 +00:00

263 lines
6.2 KiB
CSS

@tailwind base;
@tailwind components;
@tailwind utilities;
@layer utilities {
.text-balance {
text-wrap: balance;
}
}
@layer base {
:root {
--background: 36 18% 97%;
--foreground: 0 0% 10%;
--card: 0 0% 100%;
--card-foreground: 0 0% 10%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 10%;
--primary: 48 100% 44%;
--primary-foreground: 0 0% 8%;
--secondary: 36 12% 94%;
--secondary-foreground: 0 0% 10%;
--muted: 36 10% 94%;
--muted-foreground: 0 0% 36%;
--accent: 22 100% 50%;
--accent-foreground: 0 0% 10%;
--destructive: 0 84% 60%;
--destructive-foreground: 0 0% 100%;
--border: 36 10% 86%;
--input: 36 10% 86%;
--ring: 48 100% 44%;
--chart-1: 48 100% 44%;
--chart-2: 22 100% 50%;
--chart-3: 284 100% 68%;
--chart-4: 174 96% 66%;
--chart-5: 196 95% 36%;
--radius: 0.625rem;
/* OLIVER brand tokens */
--brand-gold: 48 100% 44%;
--brand-orange: 22 100% 50%;
--brand-black: 0 0% 10%;
--brand-rag: 48 100% 44%;
--brand-assistant: 22 100% 50%;
--brand-gradient-from: 48 100% 44%;
--brand-gradient-to: 22 100% 50%;
--sidebar-width: 300px;
}
.dark {
--background: 220 13% 8%;
--foreground: 0 0% 95%;
--card: 220 13% 11%;
--card-foreground: 0 0% 95%;
--popover: 220 13% 11%;
--popover-foreground: 0 0% 95%;
--primary: 48 100% 51%;
--primary-foreground: 0 0% 10%;
--secondary: 220 13% 16%;
--secondary-foreground: 0 0% 95%;
--muted: 220 13% 16%;
--muted-foreground: 0 0% 55%;
--accent: 22 100% 50%;
--accent-foreground: 0 0% 100%;
--destructive: 0 63% 31%;
--destructive-foreground: 0 0% 100%;
--border: 220 13% 18%;
--input: 220 13% 18%;
--ring: 48 100% 51%;
--chart-1: 48 100% 51%;
--chart-2: 22 100% 50%;
--chart-3: 284 100% 68%;
--chart-4: 174 96% 66%;
--chart-5: 196 95% 36%;
--brand-rag: 48 100% 51%;
--brand-assistant: 22 100% 50%;
--brand-gradient-from: 48 100% 51%;
--brand-gradient-to: 22 100% 50%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground antialiased font-sans;
font-feature-settings: "rlig" 1, "calt" 1;
}
}
/* Scrollbar styling */
@layer utilities {
.scrollbar-thin::-webkit-scrollbar {
width: 5px;
}
.scrollbar-thin::-webkit-scrollbar-track {
background: transparent;
}
.scrollbar-thin::-webkit-scrollbar-thumb {
background-color: hsl(var(--border));
border-radius: 3px;
}
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
background-color: hsl(var(--muted-foreground));
}
}
/* Typing indicator animation */
@keyframes typing-dot {
0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
30% { opacity: 1; transform: translateY(-3px); }
}
.typing-dot {
animation: typing-dot 1.4s infinite ease-in-out;
}
.typing-dot:nth-child(2) { animation-delay: 0.2s; }
.typing-dot:nth-child(3) { animation-delay: 0.4s; }
/* Gradient text */
.text-gradient {
background: linear-gradient(135deg, hsl(var(--brand-gradient-from)), hsl(var(--brand-gradient-to)));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Smooth page transitions */
.page-transition {
animation: fadeIn 0.2s ease-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(4px); }
to { opacity: 1; transform: translateY(0); }
}
/* Glass morphism utility */
.glass {
background: hsla(var(--card), 0.7);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
/* Pulse glow for active items */
@keyframes pulse-glow {
0%, 100% { box-shadow: 0 0 0 0 hsla(var(--brand-gold), 0.4); }
50% { box-shadow: 0 0 12px 2px hsla(var(--brand-gold), 0.15); }
}
.glow-pulse {
animation: pulse-glow 2s ease-in-out infinite;
}
/* Smooth hover lift */
.hover-lift {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.hover-lift:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px hsla(0, 0%, 0%, 0.08);
}
/* Context menu animations */
@keyframes scale-in {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
.animate-scale-in {
animation: scale-in 0.12s ease-out;
}
/* Copy button flash */
@keyframes copy-flash {
0% { background-color: hsla(var(--brand-gold), 0.2); }
100% { background-color: transparent; }
}
.copy-flash {
animation: copy-flash 0.6s ease-out;
}
/* Shimmer skeleton loading */
@keyframes shimmer {
0% { background-position: -200% center; }
100% { background-position: 200% center; }
}
.shimmer-skeleton {
background: linear-gradient(
90deg,
hsl(var(--muted)) 25%,
hsl(var(--muted-foreground) / 0.15) 50%,
hsl(var(--muted)) 75%
);
background-size: 200% 100%;
animation: shimmer 1.6s ease-in-out infinite;
}
/* Stagger fade-in for lists */
@keyframes stagger-fade-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
.stagger-in {
opacity: 0;
animation: stagger-fade-in 0.3s ease-out forwards;
animation-delay: calc(var(--stagger-index, 0) * 60ms);
}
/* Animated gradient background */
@keyframes gradient-shift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* Enhanced glassmorphism */
.glass-strong {
background: hsla(var(--card), 0.85);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
}
/* Ambient gold glow */
.brand-glow {
box-shadow: 0 0 20px 4px hsla(var(--brand-gold), 0.12),
0 0 40px 8px hsla(var(--brand-orange), 0.06);
}
/* Gold glow on hover */
.hover-glow {
transition: box-shadow 0.2s ease, border-color 0.2s ease;
}
.hover-glow:hover {
box-shadow: 0 0 16px 2px hsla(var(--brand-gold), 0.15),
0 4px 12px hsla(0, 0%, 0%, 0.08);
}
/* Nexus logo materialise — blur + scale + fade, delayed so globe loads first */
@keyframes nexus-materialise {
0% {
opacity: 0;
transform: scale(0.91) translateY(12px);
filter: blur(16px);
}
60% {
filter: blur(2px);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
filter: blur(0px);
}
}
.nexus-materialise {
animation: nexus-materialise 2.2s cubic-bezier(0.16, 1, 0.3, 1) 0.8s both;
}