:root { --bg-primary: #ffffff; --bg-secondary: #f8f9fa; --text-primary: #1a1a1a; --text-secondary: #6c757d; --border-color: #dee2e6; --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.12); --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1); --accent: #0066ff; --accent-hover: #0052cc; } body.dark-mode { --bg-primary: #1a1a1a; --bg-secondary: #2d2d2d; --text-primary: #ffffff; --text-secondary: #a0a0a0; --border-color: #3d3d3d; --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3); --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4); --accent: #4a9eff; --accent-hover: #6bb0ff; } * { margin: 0; padding: 0; box-sizing: border-box; } html, body { height: 100%; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background: var(--bg-secondary); color: var(--text-primary); transition: background-color 0.3s ease, color 0.3s ease; } #map { position: fixed; top: 60px; left: 0; right: 0; bottom: 0; z-index: 0; } /* Top Bar */ #topbar { position: fixed; top: 0; left: 0; right: 0; height: 60px; background: var(--bg-primary); border-bottom: 1px solid var(--border-color); display: flex; align-items: center; justify-content: space-between; padding: 0 20px; z-index: 1001; box-shadow: var(--shadow-sm); transition: all 0.3s ease; } .topbar-left { display: flex; align-items: center; gap: 32px; } /* Logo */ .logo { display: flex; align-items: center; gap: 10px; user-select: none; } .logo-icon { font-size: 28px; line-height: 1; } .logo-text { font-size: 20px; font-weight: 700; color: var(--text-primary); letter-spacing: -0.5px; } /* Stats */ .stats { display: flex; align-items: center; gap: 20px; } .stat { display: flex; flex-direction: column; gap: 2px; } .stat-number { font-size: 18px; font-weight: 700; color: var(--accent); line-height: 1; } .stat-label { font-size: 11px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 500; } .stat-divider { width: 1px; height: 30px; background: var(--border-color); } /* Toggle Button */ .toggle-btn { width: 40px; height: 40px; border-radius: 10px; border: none; background: var(--bg-secondary); color: var(--text-primary); cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.2s ease; font-size: 20px; } .toggle-btn:hover { background: var(--accent); transform: scale(1.05); } .toggle-btn:active { transform: scale(0.95); } .toggle-icon { transition: transform 0.3s ease; } body.dark-mode .toggle-icon { transform: rotate(180deg); } /* Leaflet Marker */ .vehicle-marker { filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3)); cursor: pointer; transition: filter 0.2s ease; } .vehicle-marker:hover { filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.5)) brightness(1.1); } /* Line Labels */ .line-label { padding: 3px 8px; border-radius: 4px; font-weight: 700; font-size: 11px; display: inline-block; color: white; margin-top: 3px; user-select: none; letter-spacing: 0.3px; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); } /* Popups */ .leaflet-popup-content-wrapper { background: var(--bg-primary); color: var(--text-primary); border-radius: 12px; box-shadow: var(--shadow-md); border: 1px solid var(--border-color); padding: 0; overflow: hidden; min-width: 280px; } .leaflet-popup-content { margin: 0; font-size: 14px; line-height: 1.5; } .leaflet-popup-tip { background: var(--bg-primary); border: 1px solid var(--border-color); border-right: none; border-bottom: none; } .popup-header { background: var(--bg-secondary); padding: 15px; border-bottom: 1px solid var(--border-color); } .popup-title { font-size: 16px; font-weight: 700; color: var(--accent); display: flex; align-items: center; gap: 8px; } .popup-body { padding: 15px; } .info-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid var(--border-color); } .info-row:last-child { border-bottom: none; } .info-label { color: var(--text-secondary); font-size: 13px; } .info-value { font-weight: 600; font-size: 13px; } /* Station Table */ .departure-table { width: 100%; border-collapse: collapse; font-size: 13px; } .departure-table th { text-align: left; padding: 12px; background: var(--bg-secondary); color: var(--text-secondary); font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; border-bottom: 2px solid var(--border-color); } .departure-table td { padding: 12px; border-bottom: 1px solid var(--border-color); } .departure-table tr:last-child td { border-bottom: none; } .departure-table tr:hover { background: var(--bg-secondary); } .line-cell { font-weight: 700; white-space: nowrap; } .direction-cell { max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .time-cell { font-weight: 600; white-space: nowrap; } .delay { color: #dc3545; font-weight: 700; margin-left: 4px; } /* Station Markers */ .station-marker { cursor: pointer; } .station-marker-icon { display: flex; align-items: center; justify-content: center; position: relative; } .station-marker-icon::before { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 30px; height: 30px; border: 3px solid var(--accent); border-radius: 50%; animation: pulse-ring 2s ease-out infinite; } .station-marker-icon::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 30px; height: 30px; border: 2px solid var(--accent); border-radius: 50%; animation: pulse-ring 2s ease-out infinite 1s; } @keyframes pulse-ring { 0% { width: 30px; height: 30px; opacity: 1; } 100% { width: 60px; height: 60px; opacity: 0; } } .station-marker:hover .station-marker-icon { animation: station-bounce 0.5s ease; } @keyframes station-bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } } body.dark-mode .station-marker-icon::before, body.dark-mode .station-marker-icon::after { border-color: var(--accent); } /* Location Marker */ .location-marker-icon { display: flex; align-items: center; justify-content: center; position: relative; } .location-marker-icon::before { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 20px; height: 20px; border: 3px solid #27E7F5; border-radius: 50%; animation: location-pulse 2s ease-out infinite; } .location-marker-icon::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 20px; height: 20px; border: 2px solid #27E7F5; border-radius: 50%; animation: location-pulse 2s ease-out infinite 1s; } @keyframes location-pulse { 0% { width: 20px; height: 20px; opacity: 1; } 100% { width: 50px; height: 50px; opacity: 0; } } /* Responsive */ @media (max-width: 768px) { #topbar { padding: 0 15px; } .topbar-left { gap: 16px; } .logo-text { font-size: 18px; } .stats { gap: 12px; } .stat-number { font-size: 16px; } .stat-label { font-size: 10px; } #map { top: 60px; } .leaflet-popup-content-wrapper { min-width: 260px; } } @media (max-width: 480px) { .logo-text { display: none; } .stat-label { display: none; } .stat-divider { display: none; } .stats { gap: 16px; } } /* Smooth Transitions */ .leaflet-popup-content-wrapper, .toggle-btn, .leaflet-marker-icon { transition: all 0.3s ease; } /* Loading State */ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } } .loading { animation: pulse 1.5s ease-in-out infinite; }