From 83cd028bcc0ddcc165c2c9fc669da880b1e113dc Mon Sep 17 00:00:00 2001 From: Justin Oros Date: Mon, 25 May 2026 16:05:20 -0700 Subject: [PATCH] squash bug, upload screenshot, update readme. --- README.md | 2 +- index.html | 1028 +++++++----------------------------------------- screenshot.png | Bin 0 -> 1188687 bytes server.py | 6 +- 4 files changed, 150 insertions(+), 886 deletions(-) create mode 100644 screenshot.png diff --git a/README.md b/README.md index 93c8865..a02f2bc 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ PoGo Mover is a macOS web app that lets you control your Pokémon GO character's It works by using Apple's **DVT (Developer Tools) location simulation** API via `pymobiledevice3` — the same mechanism Xcode uses to simulate locations during app development. No jailbreak required. -![PoGo Mover Screenshot](https://i.imgur.com/placeholder.png) +![PoGo Mover Screenshot](screenshot.png) --- diff --git a/index.html b/index.html index 7492162..93f9c81 100644 --- a/index.html +++ b/index.html @@ -22,737 +22,105 @@ --green: #4caf50; --orange: #ff9800; } - * { box-sizing: border-box; margin: 0; padding: 0; } - - body { - background: var(--darker); - color: var(--text); - font-family: 'Nunito', sans-serif; - height: 100vh; - display: flex; - flex-direction: column; - overflow: hidden; - } - - header { - background: var(--red); - padding: 0 20px; - height: 56px; - display: flex; - align-items: center; - justify-content: space-between; - border-bottom: 4px solid #8b0000; - flex-shrink: 0; - position: relative; - z-index: 1000; - } - - .logo { - font-family: 'Press Start 2P', monospace; - font-size: 14px; - color: var(--yellow); - text-shadow: 2px 2px 0 #8b6000, -1px -1px 0 #8b6000; - letter-spacing: 1px; - } - - .logo span { - color: white; - } - - .status-pill { - display: flex; - align-items: center; - gap: 8px; - background: rgba(0,0,0,0.3); - padding: 6px 14px; - border-radius: 20px; - font-size: 12px; - font-weight: 700; - } - - .status-dot { - width: 10px; - height: 10px; - border-radius: 50%; - background: #555; - animation: none; - } - - .status-dot.connected { - background: var(--green); - animation: pulse 1.5s infinite; - } - - .status-dot.error { - background: var(--red); - } - - @keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.4; } - } - - .main { - display: flex; - flex: 1; - overflow: hidden; - } - - #map { - flex: 1; - cursor: crosshair; - } - - .sidebar { - width: 280px; - background: var(--panel); - border-left: 3px solid var(--border); - display: flex; - flex-direction: column; - overflow-y: auto; - flex-shrink: 0; - } - - .section { - padding: 16px; - border-bottom: 2px solid var(--border); - } - - .section-title { - font-family: 'Press Start 2P', monospace; - font-size: 8px; - color: var(--yellow); - margin-bottom: 12px; - letter-spacing: 1px; - } - - .dpad-container { - display: flex; - justify-content: center; - margin: 8px 0; - } - - .dpad { - display: grid; - grid-template-columns: 52px 52px 52px; - grid-template-rows: 52px 52px 52px; - gap: 4px; - } - - .dpad-btn { - background: var(--dark); - border: 2px solid var(--border); - border-radius: 8px; - color: var(--text); - font-size: 18px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.1s; - user-select: none; - -webkit-user-select: none; - } - - .dpad-btn:hover { - background: var(--border); - border-color: var(--blue); - } - - .dpad-btn:active, .dpad-btn.pressed { - background: var(--blue); - border-color: var(--yellow); - transform: scale(0.93); - box-shadow: 0 0 10px rgba(61,125,202,0.5); - } - - .dpad-center { - background: var(--darker); - border-radius: 50%; - border: 2px solid var(--border); - font-size: 10px; - font-family: 'Press Start 2P', monospace; - color: var(--muted); - display: flex; - align-items: center; - justify-content: center; - cursor: default; - } - - .key-hint { - text-align: center; - font-size: 10px; - color: var(--muted); - margin-top: 6px; - } - - .key-hint kbd { - background: var(--dark); - border: 1px solid var(--border); - border-radius: 4px; - padding: 1px 5px; - font-family: monospace; - font-size: 10px; - color: var(--yellow); - } - - .speed-section { } - - .speed-label { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 10px; - font-weight: 700; - } - - .speed-badge { - background: var(--blue); - padding: 3px 10px; - border-radius: 12px; - font-size: 12px; - font-weight: 800; - } - - .speed-presets { - display: flex; - gap: 6px; - margin-bottom: 10px; - } - - .preset-btn { - flex: 1; - background: var(--dark); - border: 2px solid var(--border); - border-radius: 8px; - color: var(--text); - font-family: 'Nunito', sans-serif; - font-size: 11px; - font-weight: 700; - padding: 6px 4px; - cursor: pointer; - transition: all 0.15s; - display: flex; - flex-direction: column; - align-items: center; - gap: 2px; - } - - .preset-btn:hover, .preset-btn.active { - border-color: var(--yellow); - background: var(--border); - } - - .preset-btn.active { - background: var(--blue); - } - + body { background: var(--darker); color: var(--text); font-family: 'Nunito', sans-serif; height: 100vh; display: flex; flex-direction: column; overflow: hidden; } + header { background: var(--red); padding: 0 20px; height: 56px; display: flex; align-items: center; justify-content: space-between; border-bottom: 4px solid #8b0000; flex-shrink: 0; position: relative; z-index: 1000; } + .logo { font-family: 'Press Start 2P', monospace; font-size: 14px; color: var(--yellow); text-shadow: 2px 2px 0 #8b6000, -1px -1px 0 #8b6000; letter-spacing: 1px; } + .logo span { color: white; } + .status-pill { display: flex; align-items: center; gap: 8px; background: rgba(0,0,0,0.3); padding: 6px 14px; border-radius: 20px; font-size: 12px; font-weight: 700; } + .status-dot { width: 10px; height: 10px; border-radius: 50%; background: #555; } + .status-dot.connected { background: var(--green); animation: pulse 1.5s infinite; } + .status-dot.error { background: var(--red); } + @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } + .main { display: flex; flex: 1; overflow: hidden; } + #map { flex: 1; cursor: crosshair; } + .sidebar { width: 280px; background: var(--panel); border-left: 3px solid var(--border); display: flex; flex-direction: column; overflow-y: auto; flex-shrink: 0; } + .section { padding: 16px; border-bottom: 2px solid var(--border); } + .section-title { font-family: 'Press Start 2P', monospace; font-size: 8px; color: var(--yellow); margin-bottom: 12px; letter-spacing: 1px; } + .dpad-container { display: flex; justify-content: center; margin: 8px 0; } + .dpad { display: grid; grid-template-columns: 52px 52px 52px; grid-template-rows: 52px 52px 52px; gap: 4px; } + .dpad-btn { background: var(--dark); border: 2px solid var(--border); border-radius: 8px; color: var(--text); font-size: 18px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.1s; user-select: none; -webkit-user-select: none; } + .dpad-btn:hover { background: var(--border); border-color: var(--blue); } + .dpad-btn:active, .dpad-btn.pressed { background: var(--blue); border-color: var(--yellow); transform: scale(0.93); box-shadow: 0 0 10px rgba(61,125,202,0.5); } + .dpad-center { background: var(--darker); border-radius: 50%; border: 2px solid var(--border); font-size: 10px; font-family: 'Press Start 2P', monospace; color: var(--muted); display: flex; align-items: center; justify-content: center; cursor: default; } + .key-hint { text-align: center; font-size: 10px; color: var(--muted); margin-top: 6px; } + .key-hint kbd { background: var(--dark); border: 1px solid var(--border); border-radius: 4px; padding: 1px 5px; font-family: monospace; font-size: 10px; color: var(--yellow); } + .speed-label { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; font-weight: 700; } + .speed-badge { background: var(--blue); padding: 3px 10px; border-radius: 12px; font-size: 12px; font-weight: 800; } + .speed-presets { display: flex; gap: 6px; margin-bottom: 10px; } + .preset-btn { flex: 1; background: var(--dark); border: 2px solid var(--border); border-radius: 8px; color: var(--text); font-family: 'Nunito', sans-serif; font-size: 11px; font-weight: 700; padding: 6px 4px; cursor: pointer; transition: all 0.15s; display: flex; flex-direction: column; align-items: center; gap: 2px; } + .preset-btn:hover, .preset-btn.active { border-color: var(--yellow); background: var(--border); } + .preset-btn.active { background: var(--blue); } .preset-icon { font-size: 14px; } - - input[type=range] { - width: 100%; - accent-color: var(--yellow); - cursor: pointer; - } - - .coords-display { - background: var(--darker); - border: 2px solid var(--border); - border-radius: 8px; - padding: 10px 12px; - font-family: monospace; - font-size: 12px; - line-height: 1.8; - } - - .coords-display .label { - color: var(--muted); - font-size: 10px; - } - - .coords-display .value { - color: var(--yellow); - font-weight: bold; - } - - .click-tip { - background: rgba(61,125,202,0.15); - border: 1px solid rgba(61,125,202,0.4); - border-radius: 8px; - padding: 10px; - font-size: 11px; - color: var(--muted); - line-height: 1.6; - margin-top: 8px; - } - - .click-tip strong { - color: var(--text); - } - - .server-warning { - background: rgba(227,53,13,0.15); - border: 2px solid rgba(227,53,13,0.5); - border-radius: 8px; - padding: 12px; - font-size: 11px; - line-height: 1.7; - margin: 16px; - } - - .server-warning strong { - color: var(--yellow); - display: block; - margin-bottom: 4px; - font-size: 10px; - font-family: 'Press Start 2P', monospace; - } - - .move-queue-indicator { - display: flex; - align-items: center; - gap: 8px; - margin-top: 8px; - font-size: 11px; - color: var(--muted); - } - - .moving-dot { - width: 8px; - height: 8px; - border-radius: 50%; - background: var(--green); - display: none; - } - - .moving-dot.active { - display: block; - animation: pulse 0.5s infinite; - } - - .character-marker { - width: 36px; - height: 36px; - background: var(--blue); - border: 3px solid var(--yellow); - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 18px; - box-shadow: 0 0 0 3px rgba(61,125,202,0.3), 0 4px 12px rgba(0,0,0,0.5); - animation: float 2s ease-in-out infinite; - } - - @keyframes float { - 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(-4px); } - } - - .destination-marker { - width: 20px; - height: 20px; - background: var(--yellow); - border: 2px solid var(--red); - border-radius: 50%; - box-shadow: 0 0 8px rgba(255,203,5,0.6); - } - - .locate-btn { - width: 44px; - height: 44px; - background: var(--panel); - border: 2px solid var(--border); - border-radius: 10px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - box-shadow: 0 2px 8px rgba(0,0,0,0.4); - transition: all 0.2s; - position: relative; - } - - .locate-btn:hover { - background: var(--border); - border-color: var(--blue); - box-shadow: 0 0 12px rgba(61,125,202,0.4); - } - - .locate-btn:active { - transform: scale(0.93); - } - - .locate-btn.locating svg { - animation: locateSpin 1s linear infinite; - } - - .locate-btn.located svg #arrow { - fill: var(--blue); - filter: drop-shadow(0 0 4px rgba(61,125,202,0.8)); - } - - @keyframes locateSpin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } - } - - .locate-toast { - position: absolute; - bottom: 60px; - left: 0; - background: var(--panel); - border: 1px solid var(--border); - border-radius: 8px; - padding: 6px 10px; - font-size: 11px; - white-space: nowrap; - color: var(--text); - pointer-events: none; - opacity: 0; - transform: translateY(4px); - transition: opacity 0.2s, transform 0.2s; - box-shadow: 0 2px 8px rgba(0,0,0,0.4); - } - - .locate-toast.visible { - opacity: 1; - transform: translateY(0); - } - - .leaflet-control-layers { - background: var(--panel) !important; - border: 2px solid var(--border) !important; - border-radius: 10px !important; - box-shadow: 0 2px 10px rgba(0,0,0,0.5) !important; - padding: 2px 4px !important; - margin-bottom: 8px !important; - } - - .leaflet-control-layers-list { - display: flex !important; - gap: 4px !important; - } - - .leaflet-control-layers label { - display: flex !important; - align-items: center !important; - gap: 5px !important; - padding: 5px 8px !important; - border-radius: 7px !important; - cursor: pointer !important; - font-family: 'Nunito', sans-serif !important; - font-size: 12px !important; - font-weight: 700 !important; - color: var(--muted) !important; - transition: all 0.15s !important; - white-space: nowrap !important; - } - - .leaflet-control-layers label:has(input:checked) { - background: var(--blue) !important; - color: white !important; - } - - .leaflet-control-layers label:hover { - color: var(--text) !important; - background: var(--border) !important; - } - - .leaflet-control-layers input[type=radio] { - display: none !important; - } - - .leaflet-control-layers-toggle { - display: none !important; - } - - .leaflet-control-layers-separator { - display: none !important; - } - - .teleport-btn { - width: 100%; - margin-top: 10px; - padding: 10px; - background: linear-gradient(135deg, #1a0030, #2d0050); - border: 2px solid #7b2fff; - border-radius: 10px; - color: #d4aaff; - font-family: 'Press Start 2P', monospace; - font-size: 8px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - transition: all 0.2s; - letter-spacing: 1px; - } - - .teleport-btn:hover { - background: linear-gradient(135deg, #2d0050, #4a00a0); - border-color: #bf80ff; - color: #fff; - box-shadow: 0 0 16px rgba(123,47,255,0.5); - } - - .teleport-btn.active { - background: linear-gradient(135deg, #4a00a0, #7b2fff); - border-color: #ffcb05; - color: #ffcb05; - box-shadow: 0 0 20px rgba(123,47,255,0.7); - } - + input[type=range] { width: 100%; accent-color: var(--yellow); cursor: pointer; } + .coords-display { background: var(--darker); border: 2px solid var(--border); border-radius: 8px; padding: 10px 12px; font-family: monospace; font-size: 12px; line-height: 1.8; } + .coords-display .label { color: var(--muted); font-size: 10px; } + .coords-display .value { color: var(--yellow); font-weight: bold; } + .click-tip { background: rgba(61,125,202,0.15); border: 1px solid rgba(61,125,202,0.4); border-radius: 8px; padding: 10px; font-size: 11px; color: var(--muted); line-height: 1.6; margin-top: 8px; } + .click-tip strong { color: var(--text); } + .server-warning { background: rgba(227,53,13,0.15); border: 2px solid rgba(227,53,13,0.5); border-radius: 8px; padding: 12px; font-size: 11px; line-height: 1.7; margin: 16px; } + .server-warning strong { color: var(--yellow); display: block; margin-bottom: 4px; font-size: 10px; font-family: 'Press Start 2P', monospace; } + .move-queue-indicator { display: flex; align-items: center; gap: 8px; margin-top: 8px; font-size: 11px; color: var(--muted); } + .moving-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); display: none; } + .moving-dot.active { display: block; animation: pulse 0.5s infinite; } + .character-marker { width: 36px; height: 36px; background: var(--blue); border: 3px solid var(--yellow); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 18px; box-shadow: 0 0 0 3px rgba(61,125,202,0.3), 0 4px 12px rgba(0,0,0,0.5); animation: float 2s ease-in-out infinite; } + @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } } + .destination-marker { width: 20px; height: 20px; background: var(--yellow); border: 2px solid var(--red); border-radius: 50%; box-shadow: 0 0 8px rgba(255,203,5,0.6); } + .teleport-btn { width: 100%; margin-top: 10px; padding: 10px; background: linear-gradient(135deg, #1a0030, #2d0050); border: 2px solid #7b2fff; border-radius: 10px; color: #d4aaff; font-family: 'Press Start 2P', monospace; font-size: 8px; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 8px; transition: all 0.2s; letter-spacing: 1px; } + .teleport-btn:hover { background: linear-gradient(135deg, #2d0050, #4a00a0); border-color: #bf80ff; color: #fff; box-shadow: 0 0 16px rgba(123,47,255,0.5); } + .teleport-btn.active { background: linear-gradient(135deg, #4a00a0, #7b2fff); border-color: #ffcb05; color: #ffcb05; box-shadow: 0 0 20px rgba(123,47,255,0.7); } .teleport-btn .t-icon { font-size: 16px; } - - .modal-overlay { - display: none; - position: fixed; - inset: 0; - background: rgba(0,0,0,0.75); - z-index: 9999; - align-items: center; - justify-content: center; - backdrop-filter: blur(4px); - } - - .modal-overlay.visible { - display: flex; - } - - .modal { - background: var(--panel); - border: 3px solid #7b2fff; - border-radius: 16px; - padding: 28px 28px 24px; - max-width: 420px; - width: 90%; - box-shadow: 0 0 40px rgba(123,47,255,0.4), 0 20px 60px rgba(0,0,0,0.6); - animation: modalIn 0.25s cubic-bezier(0.34, 1.56, 0.64, 1); - } - - @keyframes modalIn { - from { opacity: 0; transform: scale(0.85) translateY(20px); } - to { opacity: 1; transform: scale(1) translateY(0); } - } - - .modal-header { - display: flex; - align-items: center; - gap: 12px; - margin-bottom: 16px; - } - - .modal-icon { - font-size: 32px; - line-height: 1; - } - - .modal-title { - font-family: 'Press Start 2P', monospace; - font-size: 11px; - color: #bf80ff; - line-height: 1.6; - } - - .modal-body { - font-size: 13px; - line-height: 1.8; - color: var(--text); - margin-bottom: 20px; - } - - .modal-body .warning-box { - background: rgba(227,53,13,0.12); - border: 2px solid rgba(227,53,13,0.5); - border-radius: 10px; - padding: 12px 14px; - margin-bottom: 14px; - font-weight: 700; - color: #ffb3a7; - } - - .modal-body .warning-box .warn-title { - font-family: 'Press Start 2P', monospace; - font-size: 8px; - color: var(--red); - margin-bottom: 8px; - display: block; - } - - .modal-body .cooldown-box { - background: rgba(123,47,255,0.1); - border: 1px solid rgba(123,47,255,0.4); - border-radius: 10px; - padding: 12px 14px; - font-size: 12px; - color: #d4aaff; - } - - .modal-body .cooldown-box strong { - color: #ffcb05; - } - - .modal-dest { - font-family: monospace; - font-size: 11px; - color: var(--muted); - background: var(--darker); - border-radius: 6px; - padding: 6px 10px; - margin-bottom: 16px; - } - - .modal-actions { - display: flex; - gap: 10px; - } - - .modal-btn { - flex: 1; - padding: 12px; - border-radius: 10px; - border: 2px solid transparent; - font-family: 'Nunito', sans-serif; - font-size: 14px; - font-weight: 800; - cursor: pointer; - transition: all 0.15s; - } - - .modal-btn-cancel { - background: var(--dark); - border-color: var(--border); - color: var(--muted); - } - - .modal-btn-cancel:hover { - border-color: var(--muted); - color: var(--text); - } - - .modal-btn-confirm { - background: linear-gradient(135deg, #4a00a0, #7b2fff); - border-color: #bf80ff; - color: white; - } - - .modal-btn-confirm:hover { - background: linear-gradient(135deg, #6200d0, #9b4fff); - box-shadow: 0 0 16px rgba(123,47,255,0.5); - } - - .cooldown-overlay { - display: none; - position: fixed; - inset: 0; - background: rgba(0,0,0,0.85); - z-index: 9998; - align-items: center; - justify-content: center; - flex-direction: column; - gap: 20px; - backdrop-filter: blur(6px); - } - - .cooldown-overlay.visible { - display: flex; - } - - .cooldown-title { - font-family: 'Press Start 2P', monospace; - font-size: 13px; - color: #bf80ff; - text-align: center; - line-height: 1.8; - } - - .cooldown-ring { - position: relative; - width: 140px; - height: 140px; - } - - .cooldown-ring svg { - transform: rotate(-90deg); - } - - .cooldown-ring-track { - fill: none; - stroke: rgba(123,47,255,0.2); - stroke-width: 8; - } - - .cooldown-ring-progress { - fill: none; - stroke: #7b2fff; - stroke-width: 8; - stroke-linecap: round; - transition: stroke-dashoffset 1s linear; - } - - .cooldown-time { - position: absolute; - inset: 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-family: 'Press Start 2P', monospace; - font-size: 22px; - color: #ffcb05; - line-height: 1; - } - - .cooldown-time .cd-unit { - font-size: 8px; - color: var(--muted); - margin-top: 4px; - } - - .cooldown-msg { - font-size: 13px; - color: var(--muted); - text-align: center; - max-width: 300px; - line-height: 1.7; - } - - .cooldown-skip { - background: transparent; - border: 2px solid var(--border); - border-radius: 8px; - color: var(--muted); - font-family: 'Nunito', sans-serif; - font-size: 12px; - padding: 8px 20px; - cursor: pointer; - transition: all 0.15s; - margin-top: 8px; - } - - .cooldown-skip:hover { - border-color: var(--muted); - color: var(--text); - } - - footer { - background: var(--darker); - border-top: 2px solid var(--border); - padding: 6px 20px; - font-size: 10px; - color: var(--muted); - display: flex; - justify-content: space-between; - align-items: center; - flex-shrink: 0; - } + .modal-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.75); z-index: 9999; align-items: center; justify-content: center; backdrop-filter: blur(4px); } + .modal-overlay.visible { display: flex; } + .modal { background: var(--panel); border: 3px solid #7b2fff; border-radius: 16px; padding: 28px 28px 24px; max-width: 420px; width: 90%; box-shadow: 0 0 40px rgba(123,47,255,0.4), 0 20px 60px rgba(0,0,0,0.6); animation: modalIn 0.25s cubic-bezier(0.34, 1.56, 0.64, 1); } + @keyframes modalIn { from { opacity: 0; transform: scale(0.85) translateY(20px); } to { opacity: 1; transform: scale(1) translateY(0); } } + .modal-header { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; } + .modal-icon { font-size: 32px; line-height: 1; } + .modal-title { font-family: 'Press Start 2P', monospace; font-size: 11px; color: #bf80ff; line-height: 1.6; } + .modal-body { font-size: 13px; line-height: 1.8; color: var(--text); margin-bottom: 20px; } + .modal-body .warning-box { background: rgba(227,53,13,0.12); border: 2px solid rgba(227,53,13,0.5); border-radius: 10px; padding: 12px 14px; margin-bottom: 14px; font-weight: 700; color: #ffb3a7; } + .modal-body .warning-box .warn-title { font-family: 'Press Start 2P', monospace; font-size: 8px; color: var(--red); margin-bottom: 8px; display: block; } + .modal-body .cooldown-box { background: rgba(123,47,255,0.1); border: 1px solid rgba(123,47,255,0.4); border-radius: 10px; padding: 12px 14px; font-size: 12px; color: #d4aaff; } + .modal-body .cooldown-box strong { color: #ffcb05; } + .modal-dest { font-family: monospace; font-size: 11px; color: var(--muted); background: var(--darker); border-radius: 6px; padding: 6px 10px; margin-bottom: 16px; } + .modal-actions { display: flex; gap: 10px; } + .modal-btn { flex: 1; padding: 12px; border-radius: 10px; border: 2px solid transparent; font-family: 'Nunito', sans-serif; font-size: 14px; font-weight: 800; cursor: pointer; transition: all 0.15s; } + .modal-btn-cancel { background: var(--dark); border-color: var(--border); color: var(--muted); } + .modal-btn-cancel:hover { border-color: var(--muted); color: var(--text); } + .modal-btn-confirm { background: linear-gradient(135deg, #4a00a0, #7b2fff); border-color: #bf80ff; color: white; } + .modal-btn-confirm:hover { background: linear-gradient(135deg, #6200d0, #9b4fff); box-shadow: 0 0 16px rgba(123,47,255,0.5); } + .cooldown-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.85); z-index: 9998; align-items: center; justify-content: center; flex-direction: column; gap: 20px; backdrop-filter: blur(6px); } + .cooldown-overlay.visible { display: flex; } + .cooldown-title { font-family: 'Press Start 2P', monospace; font-size: 13px; color: #bf80ff; text-align: center; line-height: 1.8; } + .cooldown-ring { position: relative; width: 140px; height: 140px; } + .cooldown-ring svg { transform: rotate(-90deg); } + .cooldown-ring-track { fill: none; stroke: rgba(123,47,255,0.2); stroke-width: 8; } + .cooldown-ring-progress { fill: none; stroke: #7b2fff; stroke-width: 8; stroke-linecap: round; transition: stroke-dashoffset 1s linear; } + .cooldown-time { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; font-family: 'Press Start 2P', monospace; font-size: 22px; color: #ffcb05; line-height: 1; } + .cooldown-time .cd-unit { font-size: 8px; color: var(--muted); margin-top: 4px; } + .cooldown-msg { font-size: 13px; color: var(--muted); text-align: center; max-width: 300px; line-height: 1.7; } + .cooldown-skip { background: transparent; border: 2px solid var(--border); border-radius: 8px; color: var(--muted); font-family: 'Nunito', sans-serif; font-size: 12px; padding: 8px 20px; cursor: pointer; transition: all 0.15s; margin-top: 8px; } + .cooldown-skip:hover { border-color: var(--muted); color: var(--text); } + .locate-btn { width: 44px; height: 44px; background: var(--panel); border: 2px solid var(--border); border-radius: 10px; cursor: pointer; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 8px rgba(0,0,0,0.4); transition: all 0.2s; position: relative; } + .locate-btn:hover { background: var(--border); border-color: var(--blue); box-shadow: 0 0 12px rgba(61,125,202,0.4); } + .locate-btn:active { transform: scale(0.93); } + .locate-btn.locating svg { animation: locateSpin 1s linear infinite; } + .locate-btn.located svg #arrow { fill: var(--blue); filter: drop-shadow(0 0 4px rgba(61,125,202,0.8)); } + @keyframes locateSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } + .locate-toast { position: absolute; bottom: 60px; left: 0; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 6px 10px; font-size: 11px; white-space: nowrap; color: var(--text); pointer-events: none; opacity: 0; transform: translateY(4px); transition: opacity 0.2s, transform 0.2s; box-shadow: 0 2px 8px rgba(0,0,0,0.4); } + .locate-toast.visible { opacity: 1; transform: translateY(0); } + .leaflet-control-layers { background: var(--panel) !important; border: 2px solid var(--border) !important; border-radius: 10px !important; box-shadow: 0 2px 10px rgba(0,0,0,0.5) !important; padding: 2px 4px !important; margin-bottom: 8px !important; } + .leaflet-control-layers-list { display: flex !important; gap: 4px !important; } + .leaflet-control-layers label { display: flex !important; align-items: center !important; gap: 5px !important; padding: 5px 8px !important; border-radius: 7px !important; cursor: pointer !important; font-family: 'Nunito', sans-serif !important; font-size: 12px !important; font-weight: 700 !important; color: var(--muted) !important; transition: all 0.15s !important; white-space: nowrap !important; } + .leaflet-control-layers label:has(input:checked) { background: var(--blue) !important; color: white !important; } + .leaflet-control-layers label:hover { color: var(--text) !important; background: var(--border) !important; } + .leaflet-control-layers input[type=radio] { display: none !important; } + .leaflet-control-layers-toggle { display: none !important; } + .leaflet-control-layers-separator { display: none !important; } + footer { background: var(--darker); border-top: 2px solid var(--border); padding: 6px 20px; font-size: 10px; color: var(--muted); display: flex; justify-content: space-between; align-items: center; flex-shrink: 0; } -
@@ -760,12 +128,9 @@ Connecting...
-
- - -
+
Speed
- - - - + + + +
- +
Speed
1.4 m/s
-
Position
@@ -828,15 +179,12 @@ Click the map to add waypoints. The player moves through them in order. Click multiple times to build a route.
- -
-