@tailwind base; @tailwind components; @tailwind utilities; :root { --foreground-rgb: 0, 0, 0; --background-rgb: 249, 250, 251; --primary: 234, 88, 12; --primary-light: 249, 115, 22; --success: 34, 197, 94; --warning: 234, 179, 8; --danger: 239, 68, 68; --info: 6, 182, 212; --nav-height: 4rem; } html, body { max-width: 100vw; overflow-x: hidden; height: 100%; -webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } body { color: rgb(var(--foreground-rgb)); background: rgb(var(--background-rgb)); font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; overscroll-behavior-y: none; -webkit-user-select: none; user-select: none; /* Smooth page transitions */ scroll-behavior: smooth; } /* Mobile viewport height fix (100vh is wrong on mobile) */ @supports (-webkit-touch-callout: none) { .h-screen { height: -webkit-fill-available; } .min-h-screen { min-height: -webkit-fill-available; } } /* Safe area insets for notched phones */ .safe-top { padding-top: env(safe-area-inset-top); } .safe-bottom { padding-bottom: env(safe-area-inset-bottom); } /* Content must account for bottom nav */ .pb-nav { padding-bottom: calc(var(--nav-height) + env(safe-area-inset-bottom, 0px) + 1rem); } /* Hide scrollbar but keep scroll functionality */ .no-scrollbar::-webkit-scrollbar { display: none; } .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; } /* Touch action optimization */ .touch-manipulation { touch-action: manipulation; } /* Prevent text selection on interactive elements */ button, a, nav { -webkit-user-select: none; user-select: none; } /* Allow text selection in content areas */ .selectable { -webkit-user-select: text; user-select: text; } /* Leaflet container fix */ .leaflet-container { width: 100%; height: 100%; z-index: 1; font-family: inherit; } /* ======================================== Animations ======================================== */ @keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } @keyframes slideUp { from { transform: translateY(100%); opacity: 0; } to { transform: translateY(0); opacity: 1; } } @keyframes slideDown { from { transform: translateY(-100%); opacity: 0; } to { transform: translateY(0); opacity: 1; } } @keyframes scaleIn { from { transform: scale(0.95); opacity: 0; } to { transform: scale(1); opacity: 1; } } @keyframes shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } } .animate-fade-in { animation: fadeIn 0.3s ease-out forwards; } .animate-slide-up { animation: slideUp 0.35s cubic-bezier(0.32, 0.72, 0, 1) forwards; } .animate-slide-down { animation: slideDown 0.3s ease-out forwards; } .animate-scale-in { animation: scaleIn 0.2s ease-out forwards; } /* Stagger animation delay helper */ .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; } /* ======================================== Card Styles ======================================== */ .card-shadow { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 3px rgba(0, 0, 0, 0.1); } .card-shadow-md { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1); } .card-shadow-lg { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1); } /* Pressed/active state for cards */ .card-press { transition: transform 0.15s ease, box-shadow 0.15s ease; } .card-press:active { transform: scale(0.985); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.08); } /* ======================================== Status Badges ======================================== */ .status-pending { @apply bg-gray-100 text-gray-700 border-gray-300; } .status-assigned { @apply bg-blue-100 text-blue-700 border-blue-300; } .status-collected { @apply bg-green-100 text-green-700 border-green-300; } .status-problem { @apply bg-red-100 text-red-700 border-red-300; } /* ======================================== Loading Skeleton ======================================== */ .skeleton { background: linear-gradient(90deg, #f0f0f0 25%, #e8e8e8 50%, #f0f0f0 75%); background-size: 200% 100%; animation: shimmer 1.5s infinite; } /* ======================================== Modal Overlay ======================================== */ .modal-overlay { backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); } /* ======================================== Input Focus Rings ======================================== */ input:focus, textarea:focus, select:focus { outline: none; box-shadow: 0 0 0 2px rgba(234, 88, 12, 0.3); } /* ======================================== Bottom Sheet (iOS-style modal) ======================================== */ .bottom-sheet { border-radius: 1rem 1rem 0 0; box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.15); } @media (min-width: 640px) { .bottom-sheet { border-radius: 1rem; } } /* ======================================== Custom scrollbar (for when needed) ======================================== */ .custom-scrollbar::-webkit-scrollbar { width: 4px; } .custom-scrollbar::-webkit-scrollbar-track { background: transparent; } .custom-scrollbar::-webkit-scrollbar-thumb { background: rgba(0, 0, 0, 0.15); border-radius: 2px; } .custom-scrollbar::-webkit-scrollbar-thumb:hover { background: rgba(0, 0, 0, 0.25); } /* ======================================== Pull-to-refresh visual feedback ======================================== */ .pull-indicator { transition: transform 0.2s ease-out; } /* ======================================== Haptic-like press feedback ======================================== */ .press-feedback { transition: transform 0.1s ease, opacity 0.1s ease; } .press-feedback:active { transform: scale(0.96); opacity: 0.9; } .press-feedback-sm { transition: transform 0.1s ease, opacity 0.1s ease; } .press-feedback-sm:active { transform: scale(0.98); opacity: 0.9; }