feat(mobile): mobile-first driving layout, bottom-sheet dialogs, safe-area insets, and drawer controls

This commit is contained in:
2026-09-12 09:28:04 -07:00
parent f2a8660f10
commit fef8ab6417
3 changed files with 95 additions and 41 deletions
+79 -27
View File
@@ -203,6 +203,14 @@ body {
box-shadow: 0 0 12px rgba(6, 182, 212, 0.4);
}
.nav-text-mobile {
display: none;
}
.nav-text-desktop {
display: inline;
}
.nav-right {
display: flex;
align-items: center;
@@ -1865,9 +1873,22 @@ body {
/* Responsive Mobile Driving Mode (Calm, Uncluttered, Immersive Map) */
@media (max-width: 768px) {
html, body {
overscroll-behavior: none;
-webkit-overflow-scrolling: touch;
}
/* Full Bleed Radar Canvas on Mobile */
.radar-view-container {
height: calc(100dvh - 48px);
height: calc(100svh - 48px);
width: 100%;
}
/* Ultra-Compact Site Nav */
.site-nav {
padding: 6px 12px;
padding: max(6px, env(safe-area-inset-top)) max(10px, env(safe-area-inset-right)) 6px max(10px, env(safe-area-inset-left));
min-height: 48px;
}
.brand-text .brand-tagline,
.badge-live-pulse {
@@ -1883,6 +1904,12 @@ body {
padding: 5px 8px;
font-size: 0.72rem;
}
.nav-text-desktop {
display: none;
}
.nav-text-mobile {
display: inline;
}
.user-profile-pill {
padding: 4px 8px;
font-size: 0.72rem;
@@ -1891,13 +1918,13 @@ body {
/* Sleek Floating Top Driving Capsule */
.driver-hud {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
top: max(8px, env(safe-area-inset-top));
left: max(10px, env(safe-area-inset-left));
right: max(10px, env(safe-area-inset-right));
width: auto;
padding: 8px 12px;
border-radius: 16px;
background: rgba(10, 14, 23, 0.88);
background: rgba(10, 14, 23, 0.92);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.12);
@@ -2020,7 +2047,7 @@ body {
-webkit-backdrop-filter: blur(25px);
border-top: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 22px 22px 0 0;
padding: 16px 16px 36px;
padding: 16px 16px max(28px, env(safe-area-inset-bottom));
display: flex;
flex-direction: column;
gap: 8px;
@@ -2030,6 +2057,7 @@ body {
box-shadow: 0 -12px 35px rgba(0, 0, 0, 0.75);
max-height: 75vh;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.map-top-controls.open-drawer {
@@ -2094,8 +2122,8 @@ body {
/* Compact Floating Action Button on Mobile */
.driver-fab-container {
position: absolute;
bottom: 22px;
right: 14px;
bottom: max(18px, env(safe-area-inset-bottom));
right: max(14px, env(safe-area-inset-right));
z-index: 500;
margin: 0;
pointer-events: auto;
@@ -2124,12 +2152,16 @@ body {
/* Minimal Recenter Button on Mobile */
.btn-recenter-pill {
bottom: 22px;
left: 14px;
position: absolute;
bottom: max(18px, env(safe-area-inset-bottom));
left: max(14px, env(safe-area-inset-left));
right: auto;
transform: none;
padding: 10px 16px;
border-radius: 9999px;
font-size: 0.82rem;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
z-index: 500;
}
.map-legend {
@@ -2140,6 +2172,42 @@ body {
.leaflet-control-zoom {
display: none !important; /* Touch pinch-to-zoom is native */
}
/* Native Mobile Bottom Sheet for all Modals */
.agency-dialog,
.hardware-proof-dialog {
position: fixed !important;
bottom: 0 !important;
top: auto !important;
left: 0 !important;
right: 0 !important;
transform: none !important;
width: 100% !important;
max-width: 100% !important;
border-radius: 22px 22px 0 0 !important;
border-left: none !important;
border-right: none !important;
border-bottom: none !important;
max-height: 88dvh !important;
margin: 0 !important;
padding-bottom: max(20px, env(safe-area-inset-bottom)) !important;
box-shadow: 0 -12px 40px rgba(0, 0, 0, 0.85) !important;
animation: sheet-slide-up 0.28s cubic-bezier(0.16, 1, 0.3, 1) !important;
}
@keyframes sheet-slide-up {
from { transform: translateY(100%); }
to { transform: translateY(0); }
}
.modal-header {
padding: 18px 20px 14px;
border-radius: 22px 22px 0 0;
}
.modal-agency-name {
font-size: 1.25rem;
}
}
/* --- SLEEK RADAR DARK MODE FOR MAP TILES (Zero API Key, Zero Watermarks, 100% Free) --- */
@@ -2405,23 +2473,7 @@ body {
to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
/* 5. Mobile Adjustments for Driver FAB */
@media (max-width: 768px) {
.driver-fab-container {
bottom: 20px;
right: 15px;
}
.btn-driver-fab {
padding: 12px 18px;
font-size: 0.85rem;
}
.fab-icon-glow {
font-size: 1.3rem;
}
.btn-recenter-pill {
bottom: 85px;
}
}
/* ==========================================================================
PHOTO EVIDENCE & DEMOCRATIC VERIFICATION ENGINE
+10 -8
View File
@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>FlockRadar | Live ALPR Camera Awareness & National Transparency Directory</title>
<meta name="description" content="A Waze-style real-time ALPR radar navigation app alerting drivers to active Flock camera recorded zones with live proximity alerts, audio warnings, and a 1,439-portal public directory.">
<meta name="keywords" content="Flock Safety, ALPR, camera radar, waze for flock, live radar, license plate readers, police surveillance, camera alerts">
@@ -28,7 +28,7 @@
<meta name="apple-mobile-web-app-title" content="FlockRadar">
<!-- Main Stylesheet -->
<link rel="stylesheet" href="css/styles.css?v=8">
<link rel="stylesheet" href="css/styles.css?v=9">
</head>
<body>
@@ -56,11 +56,13 @@
<div class="nav-mode-switcher" role="tablist">
<button id="nav-map-btn" class="nav-mode-btn active" role="tab" aria-selected="true">
<span class="mode-icon">🗺️</span>
<span>Live Radar Map</span>
<span class="nav-text-desktop">Live Radar Map</span>
<span class="nav-text-mobile">Radar</span>
</button>
<button id="nav-dir-btn" class="nav-mode-btn" role="tab" aria-selected="false">
<span class="mode-icon">📋</span>
<span>National Directory (1,439)</span>
<span class="nav-text-desktop">National Directory (1,439)</span>
<span class="nav-text-mobile">Directory</span>
</button>
</div>
</div>
@@ -969,10 +971,10 @@
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<!-- Data & Application Logic with Cache Busting -->
<script src="data/portals.js?v=8"></script>
<script src="js/auth.js?v=8"></script>
<script src="js/radar.js?v=8"></script>
<script src="js/app.js?v=8"></script>
<script src="data/portals.js?v=9"></script>
<script src="js/auth.js?v=9"></script>
<script src="js/radar.js?v=9"></script>
<script src="js/app.js?v=9"></script>
<!-- Service Worker Instant Cache Invalidation -->
<script>
+6 -6
View File
@@ -1,13 +1,13 @@
// Service Worker for FlockRadar Offline Driving & Live Updates
const CACHE_NAME = 'flockradar-v8';
const CACHE_NAME = 'flockradar-v9';
const ASSETS_TO_CACHE = [
'./',
'./index.html',
'./css/styles.css?v=8',
'./js/app.js?v=8',
'./js/auth.js?v=8',
'./js/radar.js?v=8',
'./data/portals.js?v=8',
'./css/styles.css?v=9',
'./js/app.js?v=9',
'./js/auth.js?v=9',
'./js/radar.js?v=9',
'./data/portals.js?v=9',
'./manifest.json'
];