PageSourceSearch

https://virtualcaravans.web.app/

html virtualcaravans.web.app collected 2026-10-03 12:39:19 UTC 27,682 bytes, 497 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="UTF-8">
5  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6  <title>Dispersed Camp Finder | Find Legal Off-Grid Camping</title>
7  <meta name="description" content="Find legal dispersed campsites on BLM and USFS public lands within a 2-hour drive of any US destination. Dynamic driving time routing and coordinate exports.">
8  
9  <!-- Tailwind CSS CDN -->
10  
10<script src="https://cdn.tailwindcss.com"></script>
10
11  
11<script>
12    tailwind.config = {
13      darkMode: 'class',
14      theme: {
15        extend: {
16          colors: {
17            primary: {
18              50: '#f4f7f4',
19              100: '#e5ebe5',
20              200: '#cbdad0',
21              300: '#a2beae',
22              400: '#759b85',
23              500: '#567f69',
24              600: '#426652',
25              700: '#365243',
26              800: '#2c4238',
27              900: '#26372f',
28              950: '#15201b',
29            },
30            accent: {
31              50: '#fffbf0',
32              100: '#fef3d6',
33              200: '#fde4ac',
34              300: '#fcd077',
35              400: '#fbb745',
36              500: '#f9991e',
37              600: '#df7912',
38              700: '#b95910',
39              800: '#934311',
40              900: '#773711',
41              950: '#431c05',
42            }
43          },
44          fontFamily: {
45            sans: ['Inter', 'sans-serif'],
46          }
47        }
48      }
49    }
50  </script>
50
51
52  <!-- Google Fonts -->
53  <link rel="preconnect" href="https://fonts.googleapis.com">
54  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
55  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
56
57  <!-- FontAwesome for Premium Icons -->
58  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
59
60  <!-- Leaflet CSS -->
61  <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" />
62
63  <!-- Custom Stylesheet -->
64  <link rel="stylesheet" href="style.css">
65</head>
66<body class="bg-primary-950 text-slate-100 font-sans min-h-screen flex flex-col antialiased selection:bg-accent-500 selection:text-primary-950">
67
68  <!-- Global Error Handler to display runtime library crashes visually -->
69  
69<script>
70    window.addEventListener('error', function(e) {
71      const banner = document.createElement('div');
72      banner.className = 'bg-red-600 text-white text-center py-3 px-4 font-bold text-sm sticky top-0 z-[5000] flex items-center justify-center gap-2 shadow-lg';
73      banner.innerHTML = `<i class="fa-solid fa-circle-exclamation"></i> <span>Runtime Error: ${e.message} (${e.filename.split('/').pop()}:${e.lineno})</span>`;
74      document.body.insertBefore(banner, document.body.firstChild);
75    });
76  </script>
76
77
78  <!-- Header -->
79  <header class="border-b border-cyan-950/80 bg-[#060913]/90 backdrop-blur-md sticky top-0 z-[1000] px-4 py-3 sm:px-6">
80    <div class="max-w-7xl mx-auto flex flex-col sm:flex-row items-center justify-between gap-4">
81      <div class="flex items-center gap-3">
82        <div class="h-10 w-10 rounded-xl bg-gradient-to-tr from-cyan-500 to-teal-400 flex items-center justify-center shadow-lg shadow-cyan-500/20">
83          <i class="fa-solid fa-compass text-slate-950 text-xl animate-spin-slow"></i>
84        </div>
85        <div>
86          <h1 id="main-title" class="text-xl font-bold tracking-tight bg-gradient-to-r from-white to-cyan-200 bg-clip-text text-transparent flex items-center gap-2">
87            Nomad High Temps <span id="title-badge" class="text-xs px-2 py-0.5 rounded-full bg-cyan-500/10 text-cyan-400 font-medium border border-cyan-500/20">Feels-like matching</span>
88          </h1>
89          <p id="main-subtitle" class="text-xs text-slate-400">Find your perfect temperature within driving range</p>
90        </div>
91      </div>
92
93      <!-- Tabs Switcher -->
94      <div class="flex bg-slate-950/60 p-1 rounded-xl border border-slate-800/80 select-none">
95        <button 
96          id="tab-campsites" 
97          class="px-4 py-1.5 rounded-lg text-xs font-semibold transition-all duration-200 flex items-center gap-1.5 text-slate-400 hover:text-cyan-400"
98        >
99          <i class="fa-solid fa-tent"></i> Campsite Search
100        </button>
101        <button 
102          id="tab-weather" 
103          class="px-4 py-1.5 rounded-lg text-xs font-semibold transition-all duration-200 flex items-center gap-1.5 bg-cyan-500 text-slate-950 shadow-sm"
104        >
105          <i class="fa-solid fa-sun"></i> Ideal Temp Search
106        </button>
107      </div>
108    </div>
109  </header>
110
111  <!-- Main Content Layout -->
112  <main id="main-content" class="flex-1 max-w-7xl w-full mx-auto px-4 py-6 sm:px-6 flex flex-col gap-6 hidden">
113    <!-- Campsites Tab Content -->
114    <div id="campsites-content" class="flex flex-col gap-6">
115
116    <!-- Search & Control Panel -->
117    <section class="bg-primary-900/40 border border-primary-800/80 rounded-2xl p-4 sm:p-6 backdrop-blur-sm relative overflow-hidden">
118      <!-- Glow effect -->
119      <div class="absolute -top-24 -left-24 w-48 h-48 bg-primary-500/10 rounded-full blur-3xl pointer-events-none"></div>
120      <div class="absolute -bottom-24 -right-24 w-48 h-48 bg-accent-500/10 rounded-full blur-3xl pointer-events-none"></div>
121
122      <div class="relative z-10 flex flex-col lg:flex-row gap-4 items-end">
123        <!-- Destination Input -->
124        <div class="flex-1 w-full relative">
125          <label for="destination-input" class="block text-xs font-semibold text-primary-300 uppercase tracking-wider mb-2">
126            Destination Location (US)
127          </label>
128          <div class="relative flex items-center">
129            <span class="absolute left-4 text-primary-400 pointer-events-none">
130              <i class="fa-solid fa-location-dot"></i>
131            </span>
132            <input 
133              type="text" 
134              id="destination-input" 
135              placeholder="e.g. Moab, UT or Denver, CO" 
136              class="w-full pl-11 pr-20 py-3.5 bg-primary-950/60 border border-primary-800 rounded-xl text-slate-100 placeholder-primary-500 focus:outline-none focus:ring-2 focus:ring-accent-500/50 focus:border-accent-500 transition-all text-sm"
137              autocomplete="off"
138            >
139            <!-- Clear search button -->
140            <button id="clear-search" class="absolute right-14 text-primary-500 hover:text-slate-100 hidden">
141              <i class="fa-solid fa-circle-xmark"></i>
142            </button>
143            <!-- Compact Icon-Only Search Button inside input -->
144            <button 
145              id="search-btn" 
146              class="absolute right-1.5 top-1.5 bottom-1.5 w-10 bg-gradient-to-r from-accent-500 to-accent-600 hover:from-accent-600 hover:to-accent-700 text-primary-950 font-bold rounded-lg transition-all duration-200 active:scale-95 flex items-center justify-center text-sm select-none shadow-md shadow-accent-500/10"
147              title="Search Location"
148            >
149              <i class="fa-solid fa-magnifying-glass"></i>
150            </button>
151            <!-- Suggestions Dropdown -->
152            <div id="suggestions-box" class="absolute left-0 right-0 top-full mt-2 bg-primary-950 border border-primary-800 rounded-xl shadow-2xl overflow-hidden z-[2000] hidden">
153              <ul id="suggestions-list" class="divide-y divide-primary-900/60 max-h-60 overflow-y-auto"></ul>
154            </div>
155          </div>
156        </div>
157
158        <!-- Distance Filter -->
159        <div class="w-full lg:w-48">
160          <label for="distance-limit" class="block text-xs font-semibold text-primary-300 uppercase tracking-wider mb-2">
161            Max Distance
162          </label>
163          <div class="relative">
164            <span class="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none text-primary-400">
165              <i class="fa-solid fa-road"></i>
166            </span>
167            <select 
168              id="distance-limit" 
169              class="w-full pl-11 pr-4 py-3.5 bg-primary-950/60 border border-primary-800 rounded-xl text-slate-100 focus:outline-none focus:ring-2 focus:ring-accent-500/50 focus:border-accent-500 transition-all text-sm appearance-none cursor-pointer"
170            >
171              <option value="25">25 Miles</option>
172              <option value="50">50 Miles</option>
173              <option value="75" selected>75 Miles</option>
174              <option value="100">100 Miles</option>
175            </select>
176            <span class="absolute inset-y-0 right-0 pr-4 flex items-center pointer-events-none text-primary-500">
177              <i class="fa-solid fa-chevron-down text-xs"></i>
178            </span>
179          </div>
180        </div>
181
182        <!-- Layer Toggles -->
183        <div class="w-full lg:w-auto flex flex-col gap-1.5">
184          <div class="flex flex-wrap gap-3">
185            <button 
186              id="show-legend" 
187              class="flex-1 lg:flex-initial flex items-center justify-center gap-1.5 px-4 py-3.5 bg-primary-800/40 border border-emerald-500/30 text-emerald-400 hover:bg-emerald-500/10 rounded-xl transition-all text-xs font-semibold uppercase tracking-wider shadow-sm select-none"
188              title="Show Boundaries Legend"
189            >
190              <i class="fa-solid fa-circle-info"></i>
191              Map Legend
192            </button>
193            <button 
194              id="toggle-mvum" 
195              class="flex-1 lg:flex-initial flex items-center justify-center gap-2 px-4 py-3.5 bg-primary-800/40 border border-emerald-500/30 text-emerald-400 hover:bg-emerald-500/10 rounded-xl transition-all text-xs font-semibold uppercase tracking-wider shadow-sm select-none"
196              title="Note: You must zoom in close on the map to see these roads!"
197            >
198              <i class="fa-solid fa-road"></i>
199              Show National Forest Roads
200            </button>
201          </div>
202          <span class="text-[9px] text-emerald-400/80 font-medium block text-center lg:text-right px-1">
203            * Zoom in close on map to view forest roads
204          </span>
205        </div>
206      </div>
207    </section>
208
209    <!-- Map & Side Details Grid -->
210    <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
211      <!-- Leaflet Map Container -->
212      <section class="lg:col-span-2 bg-primary-900/40 border border-primary-800 rounded-2xl overflow-hidden min-h-[500px] h-[550px] relative flex flex-col">
213        <!-- Map Overlay Actions -->
214        <div class="absolute top-3 right-3 z-[1000] flex flex-col gap-2">
215          <!-- Custom Zoom buttons / Controls -->
216        </div>
217
218        <div id="map" class="w-full flex-1"></div>
219
220        <!-- Map Loading Spinner overlay -->
221        <div id="map-loader" class="absolute inset-0 bg-primary-950/80 z-[2000] flex flex-col items-center justify-center gap-4 transition-all duration-300 opacity-0 pointer-events-none">
222          <div class="relative flex items-center justify-center">
223            <div class="h-16 w-16 rounded-full border-4 border-primary-800 border-t-accent-500 animate-spin"></div>
224            <i class="fa-solid fa-tent text-accent-500 absolute text-lg animate-pulse"></i>
225          </div>
226          <div class="text-center">
227            <p id="loader-text" class="text-sm font-semibold text-slate-200">Searching camp coordinates...</p>
228            <p id="loader-subtext" class="text-xs text-primary-400 mt-1">This may take up to 10 seconds</p>
229          </div>
230        </div>
231      </section>
232
233      <!-- Camping Guidelines & Resources Panel -->
234      <section class="bg-primary-900/40 border border-primary-800 rounded-2xl p-5 flex flex-col h-[550px]">
235        <!-- Search official websites dropdown (moved to top) -->
236        <div class="pb-4 border-b border-primary-800 text-left mb-4">
237          <label for="local-boundaries-select" class="text-[10px] font-bold text-primary-300 uppercase tracking-wider mb-2 flex items-center gap-1.5">
238            <i class="fa-solid fa-circle-nodes text-accent-500"></i> Official Agency Sites
239          </label>
240          <div class="relative">
241            <span class="absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none text-primary-400">
242              <i class="fa-solid fa-arrow-up-right-from-square text-[10px]"></i>
243            </span>
244            <select 
245              id="local-boundaries-select" 
246              class="w-full pl-9 pr-8 py-2.5 bg-primary-950/60 border border-primary-800 rounded-xl text-slate-200 focus:outline-none focus:ring-2 focus:ring-accent-500/50 focus:border-accent-500 transition-all text-[10px] appearance-none cursor-pointer"
247            >
248              <option value="" disabled selected>Find Official Websites</option>
249            </select>
250            <span class="absolute inset-y-0 right-0 pr-3.5 flex items-center pointer-events-none text-primary-500">
251              <i class="fa-solid fa-chevron-down text-[10px]"></i>
252            </span>
253          </div>
254        </div>
255
256        <h2 class="text-xs font-semibold text-primary-300 uppercase tracking-wider mb-3 flex items-center justify-between">
257          <span>Camping Guidelines & Resources</span>
258          <i class="fa-solid fa-circle-info text-primary-500"></i>
259        </h2>
260
261        <!-- OSM Verification Warning -->
262        <div class="mb-3.5 p-3 bg-red-950/40 border border-red-500/20 rounded-xl flex gap-2.5 text-left">
263          <i class="fa-solid fa-triangle-exclamation text-red-400 mt-0.5 flex-shrink-0"></i>
264          <div>
265            <h4 class="text-[10px] font-bold text-red-400 uppercase tracking-wider mb-0.5">OSM Verification Warning</h4>
266            <p class="text-[10px] text-slate-300 leading-normal">
267              OpenStreetMap (OSM) sites are crowdsourced, unverified, and may not be legal. You should check official agency websites to confirm campsite legality and regulations.
268            </p>
269          </div>
270        </div>
271
272        <!-- Info Box: BLM Dispersed Guidance -->
273        <div class="mb-3.5 p-3.5 bg-accent-950/30 border border-accent-500/20 rounded-xl flex gap-3 text-left">
274          <i class="fa-solid fa-circle-question text-accent-400 mt-0.5 flex-shrink-0"></i>
275          <div>
276            <h4 class="text-[10px] font-bold text-accent-400 uppercase tracking-wider mb-0.5">BLM Dispersed Guidance</h4>
277            <p class="text-[10px] text-slate-300 leading-normal">
278              Yellow shaded areas indicate Bureau of Land Management (BLM) land, which is generally open to free dispersed camping.
279            </p>
280          </div>
281        </div>
282
283        <!-- Info Box: USFS Camping Guidance -->
284        <div class="p-3.5 bg-primary-950/80 border border-primary-800 rounded-xl flex gap-3 text-left">
285          <i class="fa-solid fa-tree text-primary-400 mt-0.5 flex-shrink-0"></i>
286          <div>
287            <h4 class="text-[10px] font-bold text-primary-300 uppercase tracking-wider mb-0.5">National Forest Camping Info</h4>
288            <p class="text-[10px] text-slate-300 leading-normal">
289              Green shaded areas indicate National Forest land. Dispersed camping is often allowed along forest roads and one should check the official site for details. The roads where camping is allowed are often shown on official MVUM maps with dots on one or both sides of the road.
290            </p>
291          </div>
292        </div>
293      </section>
294    </div>
295
296    <!-- Table of coordinates & results -->
297    <section class="bg-primary-900/40 border border-primary-800 rounded-2xl p-5 sm:p-6 backdrop-blur-sm">
298      <div class="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 mb-6">
299        <div>
300          <h2 class="text-lg font-bold text-slate-100 flex items-center gap-2">
301            <i class="fa-solid fa-list text-accent-500"></i>
302            Nearby Campsite Coordinates
303          </h2>
304          <p class="text-xs text-primary-400 mt-0.5">List of verified locations within the selected distance of destination.</p>
305        </div>
306
307        <!-- Export Buttons -->
308        <div class="flex items-center gap-2.5 w-full sm:w-auto">
309          <button 
310            id="export-gpx" 
311            class="flex-1 sm:flex-none px-4 py-2.5 bg-primary-800/80 hover:bg-primary-750 text-slate-200 rounded-xl text-xs font-bold border border-primary-700/60 flex items-center justify-center gap-2 uppercase tracking-wider transition-all disabled:opacity-50 disabled:cursor-not-allowed"
312            disabled
313          >
314            <i class="fa-solid fa-file-code"></i>
315            GPX
316          </button>
317          <button 
318            id="export-csv" 
319            class="flex-1 sm:flex-none px-4 py-2.5 bg-primary-800/80 hover:bg-primary-750 text-slate-200 rounded-xl text-xs font-bold border border-primary-700/60 flex items-center justify-center gap-2 uppercase tracking-wider transition-all disabled:opacity-50 disabled:cursor-not-allowed"
320            disabled
321          >
322            <i class="fa-solid fa-file-csv"></i>
323            CSV
324          </button>
325        </div>
326      </div>
327
328      <!-- Table wrapper -->
329      <div class="overflow-x-auto border border-primary-800/80 rounded-xl bg-primary-950/40">
330        <table class="w-full text-left border-collapse">
331          <thead>
332            <tr class="bg-primary-950 border-b border-primary-800 text-primary-300 font-semibold text-xs uppercase tracking-wider">
333              <th id="th-name" class="py-3.5 px-4 font-semibold cursor-pointer hover:text-accent-400 select-none transition-colors">Campsite Name <i class="fa-solid fa-sort text-[10px] opacity-40 ml-1"></i></th>
334              <th id="th-source" class="py-3.5 px-4 font-semibold cursor-pointer hover:text-accent-400 select-none transition-colors">Source Type <i class="fa-solid fa-sort text-[10px] opacity-40 ml-1"></i></th>
335              <th id="th-lat" class="py-3.5 px-4 font-semibold cursor-pointer hover:text-accent-400 select-none transition-colors">Latitude <i class="fa-solid fa-sort text-[10px] opacity-40 ml-1"></i></th>
336              <th id="th-lon" class="py-3.5 px-4 font-semibold cursor-pointer hover:text-accent-400 select-none transition-colors">Longitude <i class="fa-solid fa-sort text-[10px] opacity-40 ml-1"></i></th>
337              <th id="th-elevation" class="py-3.5 px-4 font-semibold text-right cursor-pointer hover:text-accent-400 select-none transition-colors">Elevation <i class="fa-solid fa-sort text-[10px] opacity-40 ml-1"></i></th>
338              <th id="th-distance" class="py-3.5 px-4 font-semibold text-right cursor-pointer hover:text-accent-400 select-none transition-colors">Distance <i class="fa-solid fa-sort text-[10px] opacity-40 ml-1"></i></th>
339              <th id="th-time" class="py-3.5 px-4 font-semibold text-right cursor-pointer hover:text-accent-400 select-none transition-colors">Driving Time <i class="fa-solid fa-sort text-[10px] opacity-40 ml-1"></i></th>
340              <th class="py-3.5 px-4 font-semibold text-center select-none">Action</th>
341            </tr>
342          </thead>
343          <tbody id="campsite-table-body" class="divide-y divide-primary-900/60 text-sm">
344            <tr id="table-empty-state">
345              <td colspan="8" class="py-12 text-center text-primary-400">
346                <i class="fa-solid fa-magnifying-glass-location text-3xl mb-3 block text-primary-600"></i>
347                Enter a destination to calculate campsite coordinates.
348              </td>
349            </tr>
350          </tbody>
351        </table>
352      </div>
353    </div>
354  </main>
355
356  <!-- Weather Tab Content (Iframe) - Full screen viewport width/height under header -->
357  <div id="weather-content" class="w-full h-[calc(100vh-76px)] flex flex-col">
358    <iframe data-src="./weather/index.html" class="w-full h-full border-none block" id="weather-iframe"></iframe>
359  </div>
360
361  <!-- Footer -->
362  <footer id="main-footer" class="border-t border-primary-900 bg-primary-950/60 px-4 py-6 sm:px-6 mt-12 text-center text-xs text-primary-500 hidden">
363    <div class="max-w-7xl mx-auto flex flex-col sm:flex-row items-center justify-between gap-4">
364      <p>&copy; 2026 DispersedCampFinder. Public domain government data and open crowdsourced map files.</p>
365      <div class="flex items-center gap-4">
366        <a href="https://www.blm.gov" target="_blank" class="hover:text-primary-300 transition-colors">BLM Lands</a>
367        <a href="https://www.fs.usda.gov" target="_blank" class="hover:text-primary-300 transition-colors">USDA Forest Service</a>
368        <a href="https://www.openstreetmap.org" target="_blank" class="hover:text-primary-300 transition-colors">OpenStreetMap</a>
369      </div>
370    </div>
371  </footer>
372
373  <!-- Public Boundaries Legend Modal -->
374  <div id="legend-modal" class="fixed inset-0 z-[6000] flex items-center justify-center p-4 bg-primary-950/80 backdrop-blur-sm opacity-0 pointer-events-none transition-opacity duration-300">
375    <div class="relative w-full max-w-md bg-primary-900/95 border border-primary-800 rounded-2xl p-6 shadow-2xl">
376      <!-- Close Button -->
377      <button id="close-legend" class="absolute top-4 right-4 text-primary-400 hover:text-slate-100 transition-colors text-lg">
378        <i class="fa-solid fa-xmark"></i>
379      </button>
380      
381      <h3 class="text-base font-bold text-slate-100 mb-4 flex items-center gap-2">
382        <i class="fa-solid fa-map text-accent-500"></i>
383        Public Boundaries Legend
384      </h3>
385      <p class="text-xs text-primary-300 mb-3">
386        Federal land agency ownership color codes displayed on the map boundaries layer:
387      </p>
388      
389      <!-- Warning Box -->
390      <div class="mb-4 p-3 bg-accent-950/40 border border-accent-500/20 rounded-xl flex gap-2.5 text-left">
391        <i class="fa-solid fa-triangle-exclamation text-accent-400 mt-0.5 flex-shrink-0 text-xs"></i>
392        <p class="text-[10px] text-slate-350 leading-relaxed">
393          <strong class="text-accent-400 font-bold uppercase tracking-wide block mb-0.5">Availability Warning</strong>
394          Boundary shading only indicates general land jurisdiction. You must check with official agency websites or local offices to verify actual camping availability, local closures, and fire restrictions.
395        </p>
396      </div>
397      
398      <!-- Legend Items -->
399      <div class="space-y-4">
400        <div class="flex items-start gap-3">
401          <div class="w-6 h-6 rounded-md bg-[#ffffaa] border border-slate-500/30 flex-shrink-0 mt-0.5"></div>
402          <div class="text-xs">
403            <span class="font-bold text-slate-200 block">Bureau of Land Management (BLM)</span>
404            <span class="text-[10px] text-primary-450">Generally open to free dispersed camping for up to 14 days.</span>
405          </div>
406        </div>
407        <div class="flex items-start gap-3">
408          <div class="w-6 h-6 rounded-md bg-[#d1ffc4] border border-slate-500/30 flex-shrink-0 mt-0.5"></div>
409          <div class="text-xs">
410            <span class="font-bold text-slate-200 block">U.S. Forest Service (USFS)</span>
411            <span class="text-[10px] text-primary-455">Generally open to free dispersed camping; check MVUM for corridor details.</span>
412          </div>
413        </div>
414        <div class="flex items-start gap-3">
415          <div class="w-6 h-6 rounded-md bg-[#e3c2ff] border border-slate-500/30 flex-shrink-0 mt-0.5"></div>
416          <div class="text-xs">
417            <span class="font-bold text-slate-200 block">National Park Service (NPS)</span>
418            <span class="text-[10px] text-primary-450">Usually regulated; permits and designated sites usually required.</span>
419          </div>
420        </div>
421        <div class="flex items-start gap-3">
422          <div class="w-6 h-6 rounded-md bg-[#b5d6ff] border border-slate-500/30 flex-shrink-0 mt-0.5"></div>
423          <div class="text-xs">
424            <span class="font-bold text-slate-200 block">State Lands (Parks / Trust Lands)</span>
425            <span class="text-[10px] text-primary-450">Access rules vary; state trust land often requires a permit or fees.</span>
426          </div>
427        </div>
428        <div class="flex items-start gap-3">
429          <div class="w-6 h-6 rounded-md bg-[#ffddb5] border border-slate-500/30 flex-shrink-0 mt-0.5"></div>
430          <div class="text-xs">
431            <span class="font-bold text-slate-200 block">Tribal Lands (Reservation Boundaries)</span>
432            <span class="text-[10px] text-primary-450">Private Sovereign Land; check with tribal authority for rules.</span>
433          </div>
434        </div>
435        <div class="flex items-start gap-3">
436          <div class="w-6 h-6 rounded-md bg-[#ffc4c4] border border-slate-500/30 flex-shrink-0 mt-0.5"></div>
437          <div class="text-xs">
438            <span class="font-bold text-slate-200 block">Department of Defense (DOD) / Military</span>
439            <span class="text-[10px] text-primary-450">Restricted areas; usually closed to public camping.</span>
440          </div>
441        </div>
442        <div class="flex items-start gap-3">
443          <div class="w-6 h-6 rounded-md bg-[#c2fbfb] border border-slate-500/30 flex-shrink-0 mt-0.5"></div>
444          <div class="text-xs">
445            <span class="font-bold text-slate-200 block">Fish & Wildlife Service (USFWS)</span>
446            <span class="text-[10px] text-primary-450">Refuges and conservation areas; local rules apply.</span>
447          </div>
448        </div>
449      </div>
450      
451      <div class="mt-5 pt-3.5 border-t border-primary-800 text-[10px] text-primary-400 text-center">
452        Always cross-reference with local rules before setting up camp.
453      </div>
454    </div>
455  </div>
456
457  <!-- Discord Login Screen Overlay -->
458  <div id="login-overlay" class="fixed inset-0 z-[9999] flex items-center justify-center bg-primary-950/90 backdrop-blur-md transition-opacity duration-300 hidden">
459    <div class="w-full max-w-md bg-primary-900 border border-primary-800 rounded-2xl p-8 shadow-2xl text-center relative overflow-hidden">
460      <!-- Glow effect -->
461      <div class="absolute -top-24 -left-24 w-48 h-48 bg-accent-500/10 rounded-full blur-3xl pointer-events-none"></div>
462      <div class="absolute -bottom-24 -right-24 w-48 h-48 bg-primary-500/10 rounded-full blur-3xl pointer-events-none"></div>
463
464      <div class="h-16 w-16 mx-auto rounded-2xl bg-gradient-to-tr from-primary-500 to-accent-400 flex items-center justify-center shadow-lg shadow-primary-500/20 mb-6">
465        <i class="fa-solid fa-compass text-primary-950 text-3xl animate-spin-slow"></i>
466      </div>
467      
468      <h2 class="text-2xl font-bold text-slate-100 tracking-tight mb-6">Virtual Caravans Member-Only App</h2>
469      
470      <div class="border-t border-primary-800/80 my-4"></div>
471      
472      <p class="text-xs text-slate-350 leading-relaxed mb-6">
473        This application is restricted to verified members of our Discord community.
474      </p>
475      
476      <button 
477        id="login-btn" 
478        class="w-full py-3.5 bg-[#5865F2] hover:bg-[#4752C4] text-white font-bold rounded-xl transition-all duration-200 shadow-lg active:scale-95 flex items-center justify-center gap-2.5 text-sm"
479      >
480        <i class="fa-brands fa-discord text-lg"></i>
481        <span>Login with Discord</span>
482      </button>
483      
484      <div id="login-error-msg" class="mt-4 text-xs font-semibold text-red-400 bg-red-950/40 border border-red-900/40 rounded-lg py-2.5 px-4 hidden"></div>
485    </div>
486  </div>
487
488  <!-- Leaflet Javascript -->
489  
489<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
489
490  
491  <!-- Esri Leaflet for ArcGIS REST boundaries and layers -->
492  
492<script src="https://unpkg.com/[email protected]/dist/esri-leaflet.js"></script>
492
493  
494  <!-- Custom Application Script -->
495  
495<script src="app.js"></script>
495
496</body>
497</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.