379 lines
17 KiB
HTML
379 lines
17 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Radio Mobile Coverage – BYU-Idaho Amateur Radio Society</title>
|
||
<link rel="stylesheet" href="/style.css" />
|
||
<script src="/script.js" defer></script>
|
||
<style>
|
||
/* OpenLayers & Map Overrides */
|
||
.ol-map-container {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 650px;
|
||
border-radius: var(--border-radius);
|
||
overflow: hidden;
|
||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||
margin-top: 1rem;
|
||
}
|
||
|
||
.ol-popup {
|
||
display: none;
|
||
position: absolute;
|
||
background-color: var(--bg-color);
|
||
color: var(--text-color);
|
||
padding: 15px;
|
||
border: 1px solid #cccccc;
|
||
bottom: 12px;
|
||
left: -50px;
|
||
border-radius: var(--border-radius);
|
||
}
|
||
|
||
.ol-popup:after, .ol-popup:before {
|
||
top: 100%;
|
||
border: solid transparent;
|
||
content: " ";
|
||
height: 0;
|
||
width: 0;
|
||
position: absolute;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.ol-popup:after {
|
||
border-top-color: var(--bg-color);
|
||
border-width: 10px;
|
||
left: 48px;
|
||
margin-left: -10px;
|
||
}
|
||
|
||
.ol-popup:before {
|
||
border-top-color: #cccccc;
|
||
border-width: 11px;
|
||
left: 48px;
|
||
margin-left: -11px;
|
||
}
|
||
|
||
.ol-popup-content {
|
||
min-width: 170px;
|
||
max-height: 200px;
|
||
overflow-x: auto;
|
||
}
|
||
|
||
.ol-popup-closer {
|
||
position: absolute;
|
||
top: 2px;
|
||
right: 2px;
|
||
font-size: 120%;
|
||
padding: 0 4px;
|
||
color: gray;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.ol-popup-closer:after {
|
||
content: "✕";
|
||
}
|
||
|
||
.ol-mouse-position { top: 8px; right: 8px; position: absolute; }
|
||
.ol-scale-line { background: rgba(0,60,136,.3); border-radius: 4px; bottom: 8px; left: 8px; padding: 2px; position: absolute; }
|
||
.ol-scale-line-inner { border: 1px solid #eee; border-top: none; color: #eee; font-size: 10px; text-align: center; margin: 1px; padding: 0 2px; }
|
||
.ol-control { position: absolute; background-color: rgba(255,255,255,.4); border-radius: 4px; padding: 2px; }
|
||
.ol-control:hover { background-color: rgba(255,255,255,.6); }
|
||
.ol-zoom { top: .5em; left: .5em; }
|
||
.ol-control button { display: block; margin: 1px; padding: 0; color: #fff; font-size: 1.14em; font-weight: 700; text-align: center; height: 1.375em; width: 1.375em; background-color: rgba(0,60,136,.5); border: none; border-radius: 2px; cursor: pointer; }
|
||
.ol-zoomslider { position: absolute; top: 4.5em; left: .5em; background: rgba(255,255,255,.4); width: 24px; height: 200px; }
|
||
.ol-zoomslider-thumb { position: absolute; background: rgba(0,60,136,.5); border-radius: 2px; cursor: pointer; height: 10px; width: 22px; margin: 3px; }
|
||
</style>
|
||
|
||
<script type="text/javascript">
|
||
var map, layers = [], mapkey, mapgrey;
|
||
var infowindow, ie, marker, rmap1, rmap2, rmap3, rmap4, mlat, mlon, job;
|
||
var ti, link, cover, txt, txtm, icon = 0;
|
||
var no = 'N', so = 'S', es = 'E', ws = 'W';
|
||
|
||
function initialize(lat, lon, zoom, j, mode) {
|
||
job = j;
|
||
createmapstyles();
|
||
switch (job) {
|
||
case 0:
|
||
map = initmap('map_canvas', 'test', 'ladeg', 'lodeg', 'ladms', 'lodms', mode);
|
||
setlltags(lat, lon, 'ladeg', 'lodeg', 'ladms', 'lodms');
|
||
icon = 3;
|
||
marker = addmarker(map, icon, lat, lon);
|
||
break;
|
||
case 1:
|
||
icon = 4;
|
||
map = initmap('map_canvas', 'test', null, null, null, null, mode);
|
||
mlat = lat; mlon = lon;
|
||
do_overlays();
|
||
break;
|
||
case 2:
|
||
icon = 4;
|
||
marker = new Array(); link = new Array(); link2 = new Array(); cover = new Array(); txt = new Array(); txtm = new Array();
|
||
map = initmap('map_canvas', 'test', null, null, null, null, mode);
|
||
init(true);
|
||
multi();
|
||
break;
|
||
}
|
||
setmap(map, lat, lon, zoom);
|
||
}
|
||
|
||
function multi() {
|
||
var i;
|
||
var s = document.getElementById('sc');
|
||
if (s) {
|
||
for (i = 1; i < s.length; ++i) cover[i - 1].setVisible(s.options[i].selected);
|
||
}
|
||
s = document.getElementById('sl');
|
||
if (s) {
|
||
for (i = 1; i < s.length; ++i) link[i - 1].setVisible(s.options[i].selected);
|
||
}
|
||
s = document.getElementById('sm');
|
||
if (s) {
|
||
for (i = 1; i < s.length; ++i) marker[i - 1].setVisible(s.options[i].selected);
|
||
}
|
||
}
|
||
|
||
function switchtiles(ind) {
|
||
selectmaptiles(map, ind);
|
||
}
|
||
|
||
function findZoom() {
|
||
if (document.form1) {
|
||
document.form1.m_lat.value = getmarkerlat(marker);
|
||
document.form1.m_lon.value = getmarkerlon(marker);
|
||
document.form1.m_zoom.value = getmapzoom(map);
|
||
}
|
||
}
|
||
|
||
function centerit() {
|
||
setmap(map, getmarkerlat(marker), getmarkerlon(marker), getmapzoom(map));
|
||
}
|
||
|
||
function centercursor() {
|
||
var lat = getmaplat(map);
|
||
var lon = getmaplon(map);
|
||
setlltags(lat, lon, 'ladeg', 'lodeg', 'ladms', 'lodms');
|
||
setmarker(marker, lat, lon);
|
||
}
|
||
|
||
function initmap(mapdiv, session, latag, lotag, ladms, lodms, src) {
|
||
var inter;
|
||
if (latag && lotag && ladms && lodms) {
|
||
initdrag(latag, lotag, ladms, lodms);
|
||
inter = ol.interaction.defaults().extend([new app.Drag()]);
|
||
}
|
||
if (!src) src = 0;
|
||
|
||
var map = new ol.Map({
|
||
interactions: inter,
|
||
layers: layers,
|
||
target: mapdiv
|
||
});
|
||
selectmaptiles(map, src);
|
||
map.addControl(new ol.control.ZoomSlider());
|
||
return map;
|
||
}
|
||
|
||
function createmapstyles() {
|
||
layers[0] = new ol.layer.Tile({
|
||
visible: false,
|
||
source: new ol.source.OSM({ url: 'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png', maxZoom: 19 })
|
||
});
|
||
layers[1] = new ol.layer.Tile({
|
||
visible: false,
|
||
source: new ol.source.XYZ({
|
||
tileUrlFunction: function (tileCoord) {
|
||
var z = tileCoord[0], x = tileCoord[1], y = tileCoord[2];
|
||
return 'https://r0.ortho.tiles.virtualearth.net/tiles/r' + quadkey(x, y, z) + '.png?g=1';
|
||
}, maxZoom: 19
|
||
})
|
||
});
|
||
layers[2] = new ol.layer.Tile({
|
||
visible: false,
|
||
source: new ol.source.XYZ({
|
||
tileUrlFunction: function (tileCoord) {
|
||
var z = tileCoord[0], x = tileCoord[1], y = tileCoord[2];
|
||
return 'https://a0.ortho.tiles.virtualearth.net/tiles/a' + quadkey(x, y, z) + '.jpeg?g=1';
|
||
}, maxZoom: 19
|
||
})
|
||
});
|
||
layers[3] = new ol.layer.Tile({
|
||
visible: false,
|
||
source: new ol.source.XYZ({ url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/{z}/{y}/{x}', maxZoom: 16 })
|
||
});
|
||
layers[4] = new ol.layer.Tile({
|
||
visible: false,
|
||
source: new ol.source.XYZ({ url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}', maxZoom: 16 })
|
||
});
|
||
layers[5] = new ol.layer.Tile({
|
||
visible: false,
|
||
source: new ol.source.XYZ({ url: 'https://tile.opentopomap.org/{z}/{x}/{y}.png', maxZoom: 17 })
|
||
});
|
||
layers[6] = new ol.layer.Tile({
|
||
visible: false,
|
||
source: new ol.source.XYZ({ url: 'https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png', maxZoom: 19 })
|
||
});
|
||
layers[7] = new ol.layer.Tile({
|
||
visible: false,
|
||
source: new ol.source.XYZ({ url: 'https://mt.google.com/vt/lyrs=r&x={x}&y={y}&z={z}', maxZoom: 19 })
|
||
});
|
||
layers[8] = new ol.layer.Tile({
|
||
visible: false,
|
||
source: new ol.source.XYZ({ url: 'https://mt.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', maxZoom: 19 })
|
||
});
|
||
}
|
||
|
||
var quadkey = function (x, y, z) {
|
||
var quadKey = [];
|
||
for (var i = z; i > 0; i--) {
|
||
var digit = '0';
|
||
var mask = 1 << (i - 1);
|
||
if ((x & mask) != 0) digit++;
|
||
if ((y & mask) != 0) { digit++; digit++; }
|
||
quadKey.push(digit);
|
||
}
|
||
return quadKey.join('');
|
||
};
|
||
|
||
function selectmaptiles(map, src) {
|
||
for (var i = 0, ii = layers.length; i < ii; ++i) layers[i].setVisible(i == src);
|
||
}
|
||
|
||
function getmaplat(map) {
|
||
var c = ol.proj.transform(map.getView().getCenter(), 'EPSG:3857', 'EPSG:4326');
|
||
return c[1];
|
||
}
|
||
|
||
function getmaplon(map) {
|
||
var c = ol.proj.transform(map.getView().getCenter(), 'EPSG:3857', 'EPSG:4326');
|
||
return c[0];
|
||
}
|
||
|
||
function getmapzoom(map) {
|
||
return map.getView().getZoom();
|
||
}
|
||
|
||
function setmap(map, lat, lon, z) {
|
||
map.setView(new ol.View({
|
||
center: ol.proj.transform([lon, lat], 'EPSG:4326', 'EPSG:3857'),
|
||
zoom: z, minZoom: 2, maxZoom: 19
|
||
}));
|
||
}
|
||
|
||
function addimage(map, src, lamin, lomin, lamax, lomax) {
|
||
var c1 = ol.proj.transform([lomin, lamin], 'EPSG:4326', 'EPSG:3857');
|
||
var c2 = ol.proj.transform([lomax, lamax], 'EPSG:4326', 'EPSG:3857');
|
||
var cx = ol.proj.transform([(lomin + lomax) / 2, (lamin + lamax) / 2], 'EPSG:4326', 'EPSG:3857');
|
||
var dx = (c2[0] - c1[0]) / 2;
|
||
var dy = (c2[1] - c1[1]) / 2;
|
||
|
||
c1[0] = cx[0] - dx;
|
||
c2[0] = cx[0] + dx;
|
||
c1[1] = cx[1] - dy;
|
||
c2[1] = cx[1] + dy;
|
||
|
||
var ov = new ol.layer.Image({
|
||
source: new ol.source.ImageStatic({
|
||
url: src,
|
||
imageExtent: [c1[0], c1[1], c2[0], c2[1]]
|
||
})
|
||
});
|
||
map.addLayer(ov);
|
||
return ov;
|
||
}
|
||
|
||
function addmarker(map, iconindex, lat, lon, label, html) {
|
||
var iconFeature = new ol.Feature({
|
||
geometry: new ol.geom.Point(ol.proj.transform([lon, lat], 'EPSG:4326', 'EPSG:3857'))
|
||
});
|
||
|
||
var iconStyle = new ol.style.Style({
|
||
image: new ol.style.Icon({
|
||
anchor: [0.5, 1.0],
|
||
anchorXUnits: 'fraction',
|
||
anchorYUnits: 'fraction',
|
||
opacity: 0.9,
|
||
src: ico[iconindex]
|
||
}),
|
||
text: new ol.style.Text({
|
||
font: '12px helvetica,sans-serif',
|
||
text: label,
|
||
fill: new ol.style.Fill({ color: '#000' }),
|
||
stroke: new ol.style.Stroke({ color: '#fff', width: 2 })
|
||
})
|
||
});
|
||
|
||
iconFeature.setStyle(iconStyle);
|
||
iconFeature.setId(html);
|
||
var vectorSource = new ol.source.Vector({ features: [iconFeature] });
|
||
var vectorLayer = new ol.layer.Vector({ source: vectorSource });
|
||
map.addLayer(vectorLayer);
|
||
return vectorLayer;
|
||
}
|
||
|
||
function setlltags(lat, lon, latag, lotag, ladms, lodms) {
|
||
var a;
|
||
var t = ol.coordinate.toStringHDMS([lon, lat]).split(" ");
|
||
if (latag && document.getElementById(latag)) document.getElementById(latag).innerHTML = lat.toFixed(8);
|
||
while (lon < -180) lon += 360; while (lon > 180) lon -= 360;
|
||
if (lotag && document.getElementById(lotag)) document.getElementById(lotag).innerHTML = lon.toFixed(8);
|
||
a = (lat < 0) ? so : no;
|
||
if (ladms && document.getElementById(ladms)) document.getElementById(ladms).innerHTML = t[0] + " " + t[1] + " " + t[2] + " " + a;
|
||
a = (lon < 0) ? ws : es;
|
||
if (lodms && document.getElementById(lodms)) document.getElementById(lodms).innerHTML = t[4] + " " + t[5] + " " + t[6] + " " + a;
|
||
}
|
||
|
||
var ico = [
|
||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAuCAMAAAB6WzuLAAADAFBMVEUAbv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0AbPoAZvAAYOYAWtsAVNMAUc0ATsgATcYATMUATMQAS8QAS8MAS8MAS8MAS8MAS8MAS8MATMMBUcEBVb8BV70BWLoBVa0BT6ABR5IBQooCQIcCPoUDO38GNnIING0NLmsRK2wYMnIjPnsoQn0tRoEySYM1TIU7UYhBW5BIZZhUbp1ZdKBhfKZpha1uirBzjrB2kK9+lLCImLOMmrSPm7WQnLaTn7eYpLmdq7yiscGquMSxv8m4xM69yNPDzdfH0dzK09/N1uHP1+TU2ujY3enb3urg4evj4uzm5O3o5u3q6O7t6+7w7vDy8PH08/P29vX4+Pb6+vj7+/j8/Pn+/vn+/vn///n///j///j///f///j///v///z///7////////////////9///8///+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+9nfC1AAABAHRSTlP///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfaoGpAAAAAlwSFlzAAAOwwAADsMBx2+oZAAAAUBJREFUOI2NlD2OwyAQhbmFj0OZZoqIwtooQkuxoXASaWlIE1nu3WyTE83FYsB2MAx4X4f0aebNHwx3xeJHf9PfSqrOFpChOwngTgCtsgSiBefNKi7UI0GMhGYrLvQG6QRvMoGKkJvIgQ/jECsOJNKAXhBFZAkSfUDuqdPIswrIuRgkhGFoy0FCGDaWnTi1LsqpUM6cySJ70T1ZBFdkz5qVyYxGZnYQ9S/ksY8MO3bvU9FtHeknpN66L9e6qhm4+DHWMoEfI3aVZZBhGSo1gZm37qdk2AfxSHGS8LtegC64UdEdnUlC2PjUqDA8PjX6To5DjIzPY+71mvwMl+zs5Zggf2kqYbL/JTlsN78USaqSSCCogEqz/Q4/dkAjjZhlVkvTcmStPE6TIPM8Qb/KiLezTZMhKPlB9nWk19JgHSH0BsTENRFLsv6lAAAAAElFTkSuQmCC",
|
||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAuCAMAAAB6WzuLAAADAFBMVEUReP4ReP4ReP4QeP4Pd/4Ndv4LdP4Jc/4Gcf4DcP4CcP4Bb/4Ab/4Ab/4Ab/4Abv4Abv4Abv4Abv4Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0Abv0AavYAY+sAXOAAWNgAVNEAUcwAT8kATscATcUATMQATMQAS8MAS8MAS8MAS8MAS8MAS8MAS8MAS8MAS8MATMMATMMATMIATcIAUMABVb4BWLwBW7oBXrcCXrICWqsBU6ABSpQBQ4sBQokBQYgCQIcCP4UEPIIFOH0JMnMLLW0NL28PMnIUNnUZOnghQHwnRYAqSIIuS4QyToc2U4o+W5BEYpZKaZpPbp5WdKJceqZng6xvi7BwjbByjrB3kbGBl7KGmbKKmrOMm7ONm7OOm7SPnLWQnbWRnraVormZp7ydrL+hssOnuciqvcuwwc+3x9S/zdrF09/J1uLL1+PN2eTR2+bV3ejZ3+nd4evg4+vj5Ozl5u3l5+3m6e/k6/Dh7vLZ8PTP9Pe7+fu2+vy1+/21+/21+/21+/21+/21+/21+/23+/26+/2//P3H/P3b/f32/v3+//3///z///z///z///v///z///3///7///7////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////1DM8mAAABAHRSTlP/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAA//////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApx8BhgAAAAlwSFlzAAAOwwAADsMBx2+oZAAAAVxJREFUOI2F1L2KwzAMAGA/wC2d825+gI5atIUrNORM4Qqe0rvFlGRyZo/lIA/iV7n8R5adVFvgQ7YsKcK/DUE/7EN/qVJV9Q5pqwuCHAIgV3WCaJQyW0OiahgxBWRhSNQBqVBmUYAi5IEx2MxAajwnSQZ6ISpxyhRoJ/LLb0rurCZypUmEc46lEb6mST5cSIY0oqM3OTlGsnzIctnKGXOEBBsvXtubOBcTeHhhgYuASO2FeUMUI+IUkZsXDSFzSTxLG7QwIvDTF50fE9uToIkR+RyeroEDAvectjfkRaUdSwS6R5TQMtCZG4DlP3bfcIWOSkZBOhgTMugEa0kSRPbomCdZ01VITLumqpfcEW0o6G+9jP2/hn+EerX3RMfLHj0IT/V/YYg/944RVVfgE8YoYfCYJqRy0TxOzVL48WkzWyrdqIjL3E/Rrn/ib5MdExJfyXNpjYnVh/DFJxD+xZNmYMqLlMgAAAABJRU5ErkJggg=="
|
||
];
|
||
</script>
|
||
</head>
|
||
<body onload="if(typeof initialize === 'function') initialize(43.8231, -111.7924, 11, 1, 0);">
|
||
|
||
<!-- Announcement Banner -->
|
||
<div id="banner" class="banner-bg hidden">
|
||
<strong id="banner-title"></strong>: <span id="banner-content"></span>
|
||
</div>
|
||
|
||
<!-- Navigation Bar -->
|
||
<nav class="navbar accent-bg">
|
||
<div class="nav-container">
|
||
<a href="/" class="nav-brand">BYU-I Amateur Radio Society</a>
|
||
|
||
<!-- Mobile Hamburger Toggle -->
|
||
<button id="menu-toggle" class="icon-button mobile-only" aria-label="Toggle Navigation Menu">
|
||
<svg id="icon-hamburger" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||
</svg>
|
||
<svg id="icon-close" class="icon hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||
</svg>
|
||
</button>
|
||
|
||
<!-- Desktop Links -->
|
||
<div id="desktop-links" class="nav-links desktop-only"></div>
|
||
|
||
<!-- Desktop Dark Mode Toggle -->
|
||
<button class="theme-toggle icon-button desktop-only" aria-label="Toggle Dark Mode">
|
||
<svg class="icon icon-sun hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m8.66-8.66h-1M4.34 12H3m15.36 6.36l-.71-.71M6.34 6.34l-.71-.71m12.02 0l-.71.71M6.34 17.66l-.71.71M12 5a7 7 0 100 14 7 7 0 000-14z" />
|
||
</svg>
|
||
<svg class="icon icon-moon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12.79A9 9 0 1111.21 3a7 7 0 009.79 9.79z" />
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Mobile Dropdown Menu -->
|
||
<div id="mobile-menu" class="mobile-menu mobile-only hidden">
|
||
<div id="mobile-links"></div>
|
||
<button class="theme-toggle mobile-theme-btn" aria-label="Toggle Dark Mode">
|
||
<span class="theme-text">🌙 Dark Mode</span>
|
||
</button>
|
||
</div>
|
||
</nav>
|
||
|
||
<!-- Main Content -->
|
||
<main class="main- |