@tailwind base; @tailwind components; @tailwind utilities; /* ══════════════════════════════════════════════════════════════ PolyWeather — Unified Design Token System ══════════════════════════════════════════════════════════════ */ @layer base { :root { /* ── Background Scale ── */ --color-bg-base: #0B1220; --color-bg-raised: #111A2E; --color-bg-overlay: #16213A; --color-bg-card: rgba(17, 26, 46, 0.88); --color-bg-input: rgba(22, 33, 58, 0.72); /* ── Text Scale ── */ --color-text-primary: #E6EDF3; --color-text-secondary: #9FB2C7; --color-text-muted: #6B7A90; --color-text-disabled: #6B7A90; /* ── Accent Colors (Fintech 3-Color) ── */ --color-accent-primary: #4DA3FF; --color-accent-secondary: #4DA3FF; --color-accent-tertiary: #93C5FD; /* ── Signal / Semantic Colors ── */ --color-signal-success: #22C55E; --color-signal-warning: #F59E0B; --color-signal-danger: #EF4444; --color-signal-info: #4DA3FF; /* ── Risk Colors (aliased from signal) ── */ --color-risk-high: var(--color-signal-danger); --color-risk-medium: var(--color-signal-warning); --color-risk-low: var(--color-signal-success); /* ── Border ── */ --color-border-default: rgba(159, 178, 199, 0.16); --color-border-hover: rgba(77, 163, 255, 0.38); --color-border-subtle: rgba(159, 178, 199, 0.08); /* ── Shadow / Elevation ── */ --shadow-elevation-1: 0 1px 3px rgba(0, 0, 0, 0.3); --shadow-elevation-2: 0 8px 24px rgba(0, 0, 0, 0.45); --shadow-elevation-3: 0 20px 60px rgba(0, 0, 0, 0.6); --shadow-glow-accent: 0 0 20px rgba(77, 163, 255, 0.24); --shadow-glow-secondary: 0 0 20px rgba(111, 183, 255, 0.22); /* ── Typography ── */ --font-data: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-display: "Geist", "Inter", -apple-system, sans-serif; --font-mono: "JetBrains Mono", "Fira Code", "SF Mono", monospace; /* ── Spacing (4px grid) ── */ --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 20px; --space-6: 24px; --space-8: 32px; --space-10: 40px; --space-12: 48px; /* ── Border Radius ── */ --radius-sm: 6px; --radius-md: 10px; --radius-lg: 14px; --radius-xl: 20px; --radius-full: 9999px; /* ── Glass / Blur ── */ --glass-blur-1: blur(10px); --glass-blur-2: blur(16px); --glass-blur-3: blur(24px); --glass-opacity-1: 0.72; --glass-opacity-2: 0.85; --glass-opacity-3: 0.92; /* ── Layout ── */ --header-height: 52px; --sidebar-width: 260px; --panel-width: 560px; /* ── Motion ── */ --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1); --transition-base: 250ms cubic-bezier(0.4, 0, 0.2, 1); --transition-slow: 400ms cubic-bezier(0.16, 1, 0.3, 1); /* ── Legacy Compatibility (shadcn/ui HSL tokens) ── */ --background: 223 53% 4%; --foreground: 210 40% 98%; --card: 223 46% 8%; --card-foreground: 210 40% 98%; --primary: 159 100% 44%; --primary-foreground: 222 47% 8%; --secondary: 224 30% 14%; --secondary-foreground: 210 40% 98%; --accent: 217 30% 18%; --accent-foreground: 210 40% 98%; --border: 221 38% 22%; } * { @apply border-border; } body { font-family: var(--font-data); background: radial-gradient( circle at 10% -10%, rgba(0, 224, 164, 0.1), transparent 40% ), radial-gradient( circle at 90% 0%, rgba(123, 97, 255, 0.08), transparent 36% ), radial-gradient( circle at 80% 100%, rgba(0, 224, 164, 0.06), transparent 48% ), var(--color-bg-base); color: var(--color-text-primary); } } /* ══════════════════════════════════════════════════════════════ Map Components (Leaflet overrides + map markers) ══════════════════════════════════════════════════════════════ */ @layer components { .leaflet-container { width: 100%; height: 100%; font-family: inherit; } .leaflet-control-zoom a { background: rgba(8, 12, 20, 0.85) !important; border-color: var(--color-border-default) !important; color: var(--color-text-primary) !important; } .leaflet-control-zoom a:hover { background: rgba(13, 19, 33, 0.95) !important; border-color: var(--color-border-hover) !important; } /* ── Map Pill (temperature labels on map) ── */ .map-pill { min-width: 52px; border-radius: var(--radius-full); border: 1px solid rgba(255, 255, 255, 0.2); padding: 5px 10px; color: var(--color-text-primary); font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1; letter-spacing: 0.04em; text-transform: uppercase; backdrop-filter: var(--glass-blur-1); box-shadow: 0 2px 14px rgba(2, 6, 23, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.2); } .map-pill.high { background: linear-gradient(135deg, var(--color-signal-danger), #b91c1c); } .map-pill.medium { background: linear-gradient(135deg, var(--color-signal-warning), #b45309); } .map-pill.low { background: linear-gradient(135deg, #22C55E, #047857); } .map-pill.active { transform: translateY(-2px) scale(1.05); box-shadow: 0 8px 24px rgba(0, 224, 164, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.35); } /* ── Glass utility ── */ .glass { background: linear-gradient( 180deg, rgba(13, 19, 33, 0.88) 0%, rgba(8, 12, 20, 0.75) 100% ); backdrop-filter: var(--glass-blur-1); } /* ── Fade-up entrance ── */ .fade-up { animation: fadeUp 400ms var(--transition-slow); } } @layer utilities { @keyframes fadeUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } } /* ══════════════════════════════════════════════════════════════ Map Marker Components (nearby stations, city bubbles) ══════════════════════════════════════════════════════════════ */ @layer components { .nearby-marker { display: flex; align-items: center; gap: var(--space-2); background: rgba(13, 19, 33, 0.9); color: var(--color-text-secondary); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--space-1) var(--space-3); font-size: 11px; font-weight: 600; box-shadow: var(--shadow-elevation-2); backdrop-filter: var(--glass-blur-1); white-space: nowrap; } .nearby-name { color: var(--color-text-secondary); } .nearby-temp { color: #fff; font-weight: 800; font-variant-numeric: tabular-nums; } .nearby-unit { color: var(--color-text-muted); font-size: 9px; } .wind-info { display: flex; align-items: center; gap: var(--space-1); margin-left: var(--space-1); padding-left: var(--space-2); border-left: 1px solid var(--color-border-subtle); color: var(--color-accent-primary); font-size: 10px; opacity: 0.9; } .wind-arrow { display: inline-block; transform-origin: center; } /* ── City Marker (bubble on map) ── */ .city-marker { position: relative; display: flex; flex-direction: column; align-items: center; cursor: pointer; } .marker-bubble { position: relative; min-width: 46px; padding: 5px 10px; border-radius: var(--radius-md); font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums; text-align: center; color: white; border: 1px solid transparent; box-shadow: var(--shadow-elevation-2); } .marker-bubble::after { content: ""; position: absolute; bottom: -6px; left: 50%; transform: translateX(-50%); width: 0; height: 0; border-left: 6px solid transparent; border-right: 6px solid transparent; border-top: 6px solid transparent; } .marker-bubble.risk-high { background: linear-gradient(135deg, #dc2626, var(--color-signal-danger)); border-color: rgba(239, 68, 68, 0.5); } .marker-bubble.risk-high::after { border-top-color: var(--color-signal-danger); } .marker-bubble.risk-medium { background: linear-gradient(135deg, #d97706, var(--color-signal-warning)); border-color: rgba(245, 158, 11, 0.5); } .marker-bubble.risk-medium::after { border-top-color: var(--color-signal-warning); } .marker-bubble.risk-low { background: linear-gradient(135deg, #059669, #22C55E); border-color: rgba(16, 185, 129, 0.5); } .marker-bubble.risk-low::after { border-top-color: #22C55E; } .marker-name { margin-top: var(--space-2); font-size: 10px; font-weight: 700; color: rgba(255, 255, 255, 0.88); text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8); } .city-marker.selected .marker-bubble { animation: markerGlow 2s ease-in-out infinite; } /* ── Scrollbar ── */ .custom-scrollbar::-webkit-scrollbar { width: 6px; } .custom-scrollbar::-webkit-scrollbar-thumb { background: rgba(123, 97, 255, 0.2); border-radius: var(--radius-full); } .custom-scrollbar::-webkit-scrollbar-thumb:hover { background: rgba(123, 97, 255, 0.35); } } @keyframes markerGlow { 0%, 100% { box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4); } 50% { box-shadow: 0 10px 26px rgba(0, 224, 164, 0.3); } }