OptiQ / frontend /src /index.css
AhmedSamir1598's picture
Add frontend source files and fix Dockerfile npm install fallback
15225f7
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
html {
scroll-behavior: smooth;
}
body {
@apply bg-dark-50 text-dark-800 font-sans antialiased;
}
}
@layer components {
.btn {
@apply inline-flex items-center justify-center px-6 py-3 rounded-lg font-semibold transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2;
}
.btn-primary {
@apply bg-gradient-to-r from-primary-500 to-primary-600 text-white hover:from-primary-600 hover:to-primary-700 focus:ring-primary-500 shadow-lg shadow-primary-500/25 hover:shadow-xl hover:shadow-primary-500/30;
}
.btn-secondary {
@apply bg-dark-800 text-white hover:bg-dark-700 focus:ring-dark-500;
}
.btn-accent {
@apply bg-gradient-to-r from-accent-500 to-accent-600 text-white hover:from-accent-600 hover:to-accent-700 focus:ring-accent-500 shadow-lg shadow-accent-500/25;
}
.btn-outline {
@apply border-2 border-primary-500 text-primary-600 hover:bg-primary-50 focus:ring-primary-500;
}
.card {
@apply bg-white rounded-xl shadow-lg border border-dark-100 p-6;
}
.card-hover {
@apply card hover:shadow-xl hover:border-primary-200 transition-all duration-300 hover:-translate-y-1;
}
.stat-card {
@apply bg-white rounded-xl p-6 border border-dark-100 shadow-md;
}
.gradient-text {
@apply bg-gradient-to-r from-primary-500 to-accent-500 bg-clip-text text-transparent;
}
.section-padding {
@apply py-16 md:py-24 px-4 md:px-8;
}
.input {
@apply w-full px-4 py-3 rounded-lg border border-dark-200 focus:border-primary-500 focus:ring-2 focus:ring-primary-500/20 outline-none transition-all duration-200;
}
.label {
@apply block text-sm font-medium text-dark-600 mb-2;
}
.page-transition {
@apply animate-page-in;
}
.hover-lift {
@apply transition-transform duration-200 hover:-translate-y-0.5;
}
.glow-ring {
@apply shadow-[0_0_0_0_rgba(14,165,233,0.0)] transition-shadow duration-300 hover:shadow-[0_0_0_6px_rgba(14,165,233,0.12)];
}
.stagger-1 { animation-delay: 60ms; }
.stagger-2 { animation-delay: 120ms; }
.stagger-3 { animation-delay: 180ms; }
.stagger-4 { animation-delay: 240ms; }
.stagger-5 { animation-delay: 300ms; }
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
@apply bg-dark-100;
}
::-webkit-scrollbar-thumb {
@apply bg-dark-300 rounded-full hover:bg-dark-400;
}
/* React Flow customizations */
.react-flow__node {
@apply shadow-lg;
}
.react-flow__edge-path {
stroke-width: 2;
}
/* Animations */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes pageIn {
from { opacity: 0; transform: translateY(16px) scale(0.99); filter: blur(4px); }
to { opacity: 1; transform: translateY(0) scale(1); filter: blur(0); }
}
@keyframes floatSlow {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
@keyframes shimmer {
0% { background-position: 0% 50%; }
100% { background-position: 100% 50%; }
}
@keyframes pulse-glow {
0%, 100% { box-shadow: 0 0 5px rgba(14, 165, 233, 0.5); }
50% { box-shadow: 0 0 20px rgba(14, 165, 233, 0.8); }
}
.animate-fade-in {
animation: fadeIn 0.5s ease-out forwards;
}
.animate-page-in {
animation: pageIn 520ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
.animate-float-slow {
animation: floatSlow 6s ease-in-out infinite;
}
.animate-shimmer {
background-size: 200% 200%;
animation: shimmer 5s ease-in-out infinite;
}
.animate-pulse-glow {
animation: pulse-glow 2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
.animate-fade-in,
.animate-page-in,
.animate-float-slow,
.animate-shimmer,
.animate-pulse-glow {
animation: none !important;
}
}