Files
ridebus-admin/frontend/src/index.css

626 lines
13 KiB
CSS

@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
body {
@apply bg-gray-50 text-gray-900;
-webkit-tap-highlight-color: transparent;
}
/* Prevent zoom on input focus on iOS */
input, select, textarea {
font-size: 16px !important;
}
@media (min-width: 640px) {
input, select, textarea {
font-size: inherit !important;
}
}
}
@layer components {
.btn-primary {
@apply bg-primary-600 text-white px-4 py-2.5 rounded-lg font-medium;
@apply transition-all duration-200 ease-out;
@apply hover:bg-primary-700 hover:shadow-md hover:-translate-y-0.5;
@apply active:scale-95 active:translate-y-0;
@apply text-sm sm:text-base;
}
.btn-secondary {
@apply bg-gray-200 text-gray-700 px-4 py-2.5 rounded-lg font-medium;
@apply transition-all duration-200 ease-out;
@apply hover:bg-gray-300 hover:shadow-sm hover:-translate-y-0.5;
@apply active:scale-95 active:translate-y-0;
@apply text-sm sm:text-base;
}
.btn-danger {
@apply bg-red-600 text-white px-4 py-2.5 rounded-lg font-medium;
@apply transition-all duration-200 ease-out;
@apply hover:bg-red-700 hover:shadow-md hover:-translate-y-0.5;
@apply active:scale-95 active:translate-y-0;
@apply text-sm sm:text-base;
}
.card {
@apply bg-white rounded-lg shadow-sm border border-gray-200 p-4 sm:p-6;
@apply transition-all duration-300 ease-out;
}
.card-hover {
@apply hover:shadow-lg hover:-translate-y-1 hover:border-gray-300;
}
.input {
@apply border border-gray-300 rounded-lg px-3 py-2.5 w-full;
@apply focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent;
@apply transition-all duration-200 ease-out;
@apply text-base sm:text-sm;
}
.label {
@apply block text-sm font-medium text-gray-700 mb-1;
}
/* Mobile-friendly touch targets */
.touch-target {
@apply min-h-[44px] min-w-[44px];
}
/* Page titles */
.page-title {
@apply text-2xl sm:text-3xl font-bold text-gray-900;
}
/* Modal styles with animations */
.modal-overlay {
@apply fixed inset-0 bg-black/50 flex items-end sm:items-center justify-center z-50;
animation: fadeIn 0.2s ease-out;
}
.modal-content {
@apply bg-white w-full sm:max-w-lg sm:mx-4 sm:rounded-lg rounded-t-2xl max-h-[90vh] overflow-hidden;
animation: slideUp 0.3s ease-out;
}
@media (min-width: 640px) {
.modal-content {
animation: scaleIn 0.2s ease-out;
}
}
/* Safe area for bottom navigation */
.safe-bottom {
padding-bottom: env(safe-area-inset-bottom, 0);
}
/* Animated list items */
.list-item-animated {
@apply transition-all duration-200 ease-out;
animation: fadeSlideIn 0.3s ease-out backwards;
}
/* Stagger animation delays */
.stagger-1 { animation-delay: 0.05s; }
.stagger-2 { animation-delay: 0.1s; }
.stagger-3 { animation-delay: 0.15s; }
.stagger-4 { animation-delay: 0.2s; }
.stagger-5 { animation-delay: 0.25s; }
.stagger-6 { animation-delay: 0.3s; }
/* Pulse animation for loading states */
.pulse-soft {
animation: pulseSoft 2s ease-in-out infinite;
}
/* Shimmer loading effect */
.shimmer {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
/* Icon animation */
.icon-bounce {
@apply transition-transform duration-200;
}
.icon-bounce:hover {
animation: iconBounce 0.4s ease-out;
}
/* Floating action button */
.fab {
@apply fixed bottom-20 right-4 lg:bottom-8 lg:right-8;
@apply w-14 h-14 rounded-full shadow-lg;
@apply flex items-center justify-center;
@apply bg-primary-600 text-white;
@apply transition-all duration-300 ease-out;
@apply hover:shadow-xl hover:scale-110;
@apply active:scale-95;
@apply disabled:opacity-50 disabled:cursor-not-allowed;
animation: fabIn 0.4s ease-out;
z-index: 40;
}
/* Secondary FAB */
.fab-secondary {
@apply fixed bottom-36 right-4 lg:bottom-24 lg:right-8;
@apply w-12 h-12 rounded-full shadow-md;
@apply flex items-center justify-center;
@apply bg-white text-gray-700 border border-gray-200;
@apply transition-all duration-300 ease-out;
@apply hover:shadow-lg hover:scale-105;
@apply active:scale-95;
animation: fabIn 0.4s ease-out 0.1s backwards;
z-index: 39;
}
/* Empty state */
.empty-state {
@apply text-center py-12 px-4;
}
.empty-state-icon {
@apply h-16 w-16 sm:h-20 sm:w-20 text-gray-300 mx-auto mb-4;
animation: fadeSlideIn 0.5s ease-out;
}
.empty-state-text {
@apply text-gray-500 text-sm sm:text-base mb-4;
animation: fadeSlideIn 0.5s ease-out 0.1s backwards;
}
/* Touch feedback for list items */
.list-item-touch {
@apply relative overflow-hidden;
-webkit-tap-highlight-color: transparent;
}
.list-item-touch::before {
content: '';
@apply absolute inset-0 bg-gray-900/5 opacity-0 transition-opacity duration-150;
pointer-events: none;
}
.list-item-touch:active::before {
@apply opacity-100;
}
/* Mobile card improvements */
@media (max-width: 640px) {
.card {
@apply rounded-xl;
}
.btn-primary, .btn-secondary, .btn-danger {
@apply py-3;
}
}
/* Pull to refresh indicator */
.pull-indicator {
@apply flex items-center justify-center py-4 text-gray-400;
animation: fadeIn 0.2s ease-out;
}
/* Swipeable item */
.swipe-item {
@apply relative;
touch-action: pan-y;
}
/* Bottom sheet handle */
.sheet-handle {
@apply w-10 h-1 bg-gray-300 rounded-full mx-auto mb-2;
}
/* iOS-style segment control */
.segment-control {
@apply flex rounded-lg bg-gray-100 p-1 relative;
}
.segment-item {
@apply flex-1 py-2 px-3 rounded-md text-sm font-medium transition-colors relative z-10;
@apply flex items-center justify-center;
}
.segment-item-active {
@apply text-gray-900;
}
.segment-item-inactive {
@apply text-gray-500;
}
.segment-indicator {
@apply absolute top-1 bottom-1 bg-white rounded-md shadow-sm transition-all duration-300 ease-out;
}
/* Status indicator */
.status-online {
@apply w-2 h-2 bg-green-500 rounded-full;
animation: pulseSoft 2s ease-in-out infinite;
}
.status-offline {
@apply w-2 h-2 bg-gray-400 rounded-full;
}
/* Quick action buttons */
.quick-action {
@apply flex flex-col items-center justify-center p-3 rounded-xl;
@apply bg-gray-50 hover:bg-gray-100 active:bg-gray-200;
@apply transition-all duration-200;
@apply min-w-[72px];
}
.quick-action-icon {
@apply w-10 h-10 rounded-full flex items-center justify-center mb-1;
@apply transition-transform duration-200;
}
.quick-action:active .quick-action-icon {
@apply scale-90;
}
.quick-action-label {
@apply text-xs text-gray-600 font-medium;
}
/* Badge animation */
.badge-pulse {
@apply relative;
}
.badge-pulse::after {
content: '';
@apply absolute inset-0 rounded-full bg-current opacity-40;
animation: badgePulse 1.5s ease-out infinite;
}
/* Skeleton loading */
.skeleton {
@apply bg-gray-200 rounded;
animation: skeleton 1.5s ease-in-out infinite;
}
/* Tooltip animation */
.tooltip {
animation: tooltipIn 0.15s ease-out;
}
/* Success checkmark animation */
.success-check {
animation: successCheck 0.4s ease-out;
}
/* Shake animation for errors */
.shake {
animation: shake 0.5s ease-out;
}
/* Slide transitions */
.slide-enter {
animation: slideIn 0.3s ease-out;
}
.slide-exit {
animation: slideOut 0.2s ease-in forwards;
}
/* Rotate animation for refresh icons */
.spin-once {
animation: spinOnce 0.5s ease-out;
}
/* Number counter animation */
.counter {
@apply tabular-nums;
transition: all 0.3s ease-out;
}
/* Progress bar */
.progress-bar {
@apply h-1 bg-primary-600 rounded-full;
animation: progressGrow 0.5s ease-out;
}
/* Ripple effect */
.ripple {
@apply relative overflow-hidden;
}
.ripple::after {
content: '';
@apply absolute inset-0 bg-white/30 rounded-full scale-0;
transition: transform 0.4s ease-out, opacity 0.4s ease-out;
}
.ripple:active::after {
@apply scale-150 opacity-0;
}
}
/* Keyframes */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(100%);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideDown {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(100%);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes fadeSlideIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideOut {
from {
opacity: 1;
transform: translateX(0);
}
to {
opacity: 0;
transform: translateX(20px);
}
}
@keyframes pulseSoft {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
@keyframes iconBounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-3px); }
}
@keyframes fabIn {
from {
opacity: 0;
transform: scale(0) rotate(-180deg);
}
to {
opacity: 1;
transform: scale(1) rotate(0);
}
}
@keyframes badgePulse {
0% {
transform: scale(1);
opacity: 0.4;
}
100% {
transform: scale(2);
opacity: 0;
}
}
@keyframes skeleton {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
@keyframes tooltipIn {
from {
opacity: 0;
transform: translateY(5px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes successCheck {
0% {
transform: scale(0);
}
50% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
20% { transform: translateX(-8px); }
40% { transform: translateX(8px); }
60% { transform: translateX(-4px); }
80% { transform: translateX(4px); }
}
@keyframes spinOnce {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes progressGrow {
from { width: 0; }
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-5px); }
}
@keyframes wiggle {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(-5deg); }
75% { transform: rotate(5deg); }
}
/* Leaflet map container */
.leaflet-container {
height: 100%;
width: 100%;
border-radius: 0.5rem;
z-index: 1;
}
/* Fix leaflet controls on mobile */
.leaflet-control-zoom {
border: none !important;
box-shadow: 0 2px 6px rgba(0,0,0,0.15) !important;
}
.leaflet-control-zoom a {
width: 36px !important;
height: 36px !important;
line-height: 36px !important;
transition: background-color 0.2s ease;
}
/* Custom scrollbar for mobile */
@media (max-width: 640px) {
::-webkit-scrollbar {
width: 4px;
height: 4px;
}
::-webkit-scrollbar-thumb {
background: #d1d5db;
border-radius: 4px;
}
}
/* Hide scrollbar but keep functionality */
.hide-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
.hide-scrollbar::-webkit-scrollbar {
display: none;
}
/* Smooth scroll on iOS */
.smooth-scroll {
-webkit-overflow-scrolling: touch;
}
/* Pull to refresh indicator space */
@supports (padding-top: env(safe-area-inset-top)) {
.safe-top {
padding-top: env(safe-area-inset-top);
}
}
/* Page transition wrapper */
.page-transition {
animation: pageIn 0.3s ease-out;
}
@keyframes pageIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Blob animation for login page */
@keyframes blob {
0%, 100% {
transform: translate(0, 0) scale(1);
}
33% {
transform: translate(30px, -50px) scale(1.1);
}
66% {
transform: translate(-20px, 20px) scale(0.9);
}
}
.animate-blob {
animation: blob 7s infinite;
}
.animation-delay-2000 {
animation-delay: 2s;
}
.animation-delay-4000 {
animation-delay: 4s;
}
/* Shake animation for errors */
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); }
20%, 40%, 60%, 80% { transform: translateX(10px); }
}
/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}