@tailwind base; @tailwind components; @tailwind utilities; @layer base { body { @apply bg-gray-50 text-gray-900 antialiased; } /* Smooth scrollbar */ ::-webkit-scrollbar { @apply w-1.5 h-1.5; } ::-webkit-scrollbar-track { @apply bg-transparent; } ::-webkit-scrollbar-thumb { @apply bg-gray-300 rounded-full hover:bg-gray-400; } } @layer components { /* ─── Buttons ──────────────────────────────────────────── */ .btn-primary { @apply inline-flex items-center justify-center gap-2 bg-primary-600 text-white px-4 py-2.5 rounded-xl font-semibold text-sm hover:bg-primary-700 active:scale-[0.98] focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 transition-all duration-150 disabled:opacity-50 disabled:cursor-not-allowed shadow-sm hover:shadow-md; } .btn-secondary { @apply inline-flex items-center justify-center gap-2 bg-white text-gray-700 px-4 py-2.5 rounded-xl font-semibold text-sm border border-gray-300 hover:bg-gray-50 active:scale-[0.98] focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 transition-all duration-150 shadow-sm; } .btn-danger { @apply inline-flex items-center justify-center gap-2 bg-red-600 text-white px-4 py-2.5 rounded-xl font-semibold text-sm hover:bg-red-700 active:scale-[0.98] focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 transition-all duration-150 shadow-sm hover:shadow-md disabled:opacity-50 disabled:cursor-not-allowed; } .btn-ghost { @apply inline-flex items-center justify-center gap-2 text-gray-600 px-3 py-2 rounded-xl font-medium text-sm hover:bg-gray-100 active:scale-[0.98] focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 transition-all duration-150; } .btn-icon { @apply inline-flex items-center justify-center w-9 h-9 rounded-xl text-gray-500 hover:bg-gray-100 hover:text-gray-700 active:scale-[0.95] transition-all duration-150; } /* ─── Inputs ──────────────────────────────────────────── */ .input-field { @apply w-full px-3.5 py-2.5 border border-gray-300 rounded-xl shadow-sm text-sm placeholder-gray-400 bg-white focus:outline-none focus:ring-2 focus:ring-primary-500/20 focus:border-primary-500 transition-all duration-150; } /* Compact, design-consistent select for inline rows (e.g. version pickers). */ .select-compact { @apply rounded-lg border border-gray-300 bg-white px-2.5 py-1.5 text-sm shadow-sm text-gray-800 cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary-500/20 focus:border-primary-500 transition-all duration-150; } /* ─── Cards ──────────────────────────────────────────── */ .card { @apply bg-white rounded-2xl shadow-sm border border-gray-200/80 p-6 transition-shadow duration-200; } .card-hover { @apply card hover:shadow-md hover:border-gray-300; } /* ─── Badges ──────────────────────────────────────────── */ .badge { @apply inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-semibold; } .badge-green { @apply badge bg-emerald-100 text-emerald-700; } .badge-red { @apply badge bg-red-100 text-red-700; } .badge-blue { @apply badge bg-blue-100 text-blue-700; } .badge-yellow { @apply badge bg-amber-100 text-amber-700; } .badge-gray { @apply badge bg-gray-100 text-gray-600; } .badge-purple { @apply badge bg-purple-100 text-purple-700; } /* ─── Stat card ──────────────────────────────────────── */ .stat-card { @apply bg-white rounded-2xl border border-gray-200/80 p-5 shadow-sm flex flex-col gap-1; } .stat-value { @apply text-3xl font-bold tracking-tight; } .stat-label { @apply text-sm font-medium text-gray-500; } /* ─── Table ──────────────────────────────────────────── */ .table-wrapper { @apply overflow-hidden rounded-2xl border border-gray-200/80 bg-white shadow-sm; } /* ─── Loading skeleton ──────────────────────────────── */ .skeleton { @apply animate-pulse bg-gray-200 rounded-xl; } /* ─── Page header ──────────────────────────────────── */ .page-header { @apply flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4; } .page-title { @apply text-2xl font-bold text-gray-900 tracking-tight; } .page-subtitle { @apply text-sm text-gray-500 mt-0.5; } } /* ─── Animations ─────────────────────────────────────── */ @keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } @keyframes slideUp { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } } .animate-fade-in { animation: fadeIn 0.3s ease-out; } .animate-slide-up { animation: slideUp 0.4s ease-out; } /* ─── Modal animations ───────────────────────────────── */ @keyframes modalBackdropIn { from { opacity: 0; } to { opacity: 1; } } @keyframes modalEnter { from { opacity: 0; transform: scale(0.95) translateY(8px); } to { opacity: 1; transform: scale(1) translateY(0); } } .animate-modal-backdrop { animation: modalBackdropIn 0.15s ease-out; } .animate-modal-enter { animation: modalEnter 0.2s ease-out; } /* ─── Lenis smooth scroll (only active on the landing page) ─── */ html.lenis, html.lenis body { height: auto; } .lenis.lenis-smooth { scroll-behavior: auto !important; } .lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; } .lenis.lenis-stopped { overflow: hidden; } .lenis.lenis-smooth iframe { pointer-events: none; } /* ─── Landing-only helpers ───────────────────────────── */ @keyframes abrbanFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } } @keyframes abrbanScrollHint { 0% { opacity: 0; transform: translateY(-6px); } 50% { opacity: 1; } 100% { opacity: 0; transform: translateY(8px); } } @keyframes abrbanShimmer { to { background-position: 200% center; } } .abrban-float { animation: abrbanFloat 6s ease-in-out infinite; } .abrban-scroll-hint { animation: abrbanScrollHint 1.8s ease-in-out infinite; } .abrban-shimmer { background: linear-gradient(100deg, #93c5fd 0%, #ffffff 25%, #2563eb 50%, #ffffff 75%, #93c5fd 100%); background-size: 200% auto; -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; animation: abrbanShimmer 6s linear infinite; filter: drop-shadow(0 2px 12px rgba(2, 6, 23, 0.55)); } /* Strong legibility over the ever-changing sky (bright clouds <-> dark storm). */ .abrban-ink { text-shadow: 0 1px 2px rgba(2, 6, 23, 0.5), 0 6px 30px rgba(2, 6, 23, 0.45); } /* Frosted dark-glass panel so text stays crisp on any weather stage. */ .abrban-panel { background: rgba(15, 23, 42, 0.46); backdrop-filter: blur(18px) saturate(125%); -webkit-backdrop-filter: blur(18px) saturate(125%); border: 1px solid rgba(255, 255, 255, 0.12); box-shadow: 0 30px 80px -30px rgba(2, 6, 23, 0.78), inset 0 1px 0 rgba(255, 255, 255, 0.08); } @media (prefers-reduced-motion: reduce) { .abrban-float, .abrban-scroll-hint, .abrban-shimmer { animation: none; } } /* Mobile: keep form controls at a 16px minimum so iOS Safari doesn't auto-zoom (and shift the page contents up) when a field/select is focused. */ @media (max-width: 640px) { input:not([type='checkbox']):not([type='radio']):not([type='range']), select, textarea { font-size: 16px !important; } }