Greasy Fork

Greasy Fork is available in English.

World Guessr Cheat Panel [PATCHED] YOU WILL GET BANNED! ( I WILL TRY TO FIX IT )

Adds a draggable panel to World Guessr that reads coordinates already present on the page, shows a live map preview, and allows placing/removing a pin.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         World Guessr Cheat Panel [PATCHED] YOU WILL GET BANNED! ( I WILL TRY TO FIX IT )
// @namespace    http://greasyfork.icu/users/your-user-id
// @version      1.0.0
// @description  Adds a draggable panel to World Guessr that reads coordinates already present on the page, shows a live map preview, and allows placing/removing a pin.
// @author       RandomAccount
// @license      MIT (Chatgpt)
// @match        https://www.worldguessr.com/
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(() => {
  "use strict";

  let lastCoords = null;
  let isOpen = false;
  let isMinimized = false;
  let isDragging = false;
  let isResizing = false;
  let offsetX = 0;
  let offsetY = 0;
  let savedHeight = 720;
  let savedWidth = 420;
  let pinnedLatLng = null;
  let pinEnabled = false;
  let activeTab = "menu";

  document.querySelectorAll(".sgp-root, .sgp-style").forEach((el) => el.remove());

  const root = document.createElement("div");
  root.className = "sgp-root";
  document.body.appendChild(root);

  const style = document.createElement("style");
  style.className = "sgp-style";
  style.textContent = `
    .sgp-root * {
      box-sizing: border-box;
      font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    }

    .sgp-fab {
      position: fixed;
      bottom: 22px;
      left: 22px;
      z-index: 100001;
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 14px 18px;
      border: 1px solid rgba(255,255,255,0.15);
      border-radius: 18px;
      background: linear-gradient(135deg, rgba(17,24,39,0.96), rgba(31,41,55,0.96));
      color: #fff;
      font-size: 14px;
      font-weight: 700;
      letter-spacing: 0.2px;
      cursor: pointer;
      box-shadow: 0 18px 45px rgba(0,0,0,0.35);
      transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
    }

    .sgp-fab:hover {
      transform: translateY(-2px) scale(1.01);
      box-shadow: 0 22px 52px rgba(0,0,0,0.42);
    }

    .sgp-fab-icon {
      width: 28px;
      height: 28px;
      border-radius: 10px;
      display: grid;
      place-items: center;
      background: linear-gradient(135deg, #34d399, #10b981);
      color: #06281d;
      font-size: 15px;
      font-weight: 900;
      box-shadow: 0 0 18px rgba(16,185,129,0.4);
      flex-shrink: 0;
    }

    .sgp-overlay {
      position: fixed;
      inset: 0;
      z-index: 100000;
      background: rgba(2,6,23,0.12);
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.25s ease;
    }

    .sgp-overlay.open {
      opacity: 1;
      pointer-events: auto;
    }

    .sgp-panel {
      position: absolute;
      top: 26px;
      left: 26px;
      width: 420px;
      height: 720px;
      display: flex;
      flex-direction: column;
      border-radius: 28px;
      overflow: hidden;
      background: #f8fafc;
      border: 1px solid rgba(226,232,240,0.95);
      box-shadow:
        0 25px 70px rgba(15,23,42,0.25),
        0 8px 24px rgba(15,23,42,0.12);
      transform: translateX(-14px) scale(0.97);
      opacity: 0;
      transition: transform 0.28s ease, opacity 0.28s ease;
      user-select: none;
    }

    .sgp-overlay.open .sgp-panel {
      transform: translateX(0) scale(1);
      opacity: 1;
    }

    .sgp-header {
      height: 68px;
      min-height: 68px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 0 14px 0 16px;
      background: linear-gradient(135deg, #0f172a, #1e293b);
      color: white;
      border-bottom: 1px solid rgba(255,255,255,0.08);
      cursor: move;
    }

    .sgp-header-left {
      display: flex;
      align-items: center;
      gap: 12px;
      min-width: 0;
    }

    .sgp-logo {
      width: 40px;
      height: 40px;
      border-radius: 14px;
      display: grid;
      place-items: center;
      font-size: 18px;
      background: linear-gradient(135deg, #34d399, #10b981);
      color: #06281d;
      box-shadow: 0 0 22px rgba(52,211,153,0.35);
      flex-shrink: 0;
    }

    .sgp-title-group {
      min-width: 0;
    }

    .sgp-title {
      font-size: 15px;
      font-weight: 800;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      line-height: 1.1;
    }

    .sgp-subtitle {
      font-size: 11px;
      opacity: 0.72;
      margin-top: 4px;
      letter-spacing: 0.2px;
    }

    .sgp-actions {
      display: flex;
      align-items: center;
      gap: 8px;
      flex-shrink: 0;
    }

    .sgp-btn {
      width: 34px;
      height: 34px;
      border: none;
      border-radius: 12px;
      background: rgba(255,255,255,0.10);
      color: white;
      cursor: pointer;
      font-size: 15px;
      font-weight: 800;
      transition: all 0.18s ease;
    }

    .sgp-btn:hover {
      background: rgba(255,255,255,0.20);
      transform: scale(1.06);
    }

    .sgp-content {
      flex: 1;
      min-height: 0;
      display: flex;
      flex-direction: column;
      gap: 12px;
      padding: 14px;
      background: #f8fafc;
      overflow: hidden;
    }

    .sgp-tabs {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 10px;
      background: rgba(255,255,255,0.7);
      padding: 6px;
      border-radius: 18px;
      border: 1px solid rgba(226,232,240,0.95);
      box-shadow: 0 10px 24px rgba(15,23,42,0.05);
      flex-shrink: 0;
    }

    .sgp-tab-btn {
      border: none;
      border-radius: 14px;
      padding: 11px 12px;
      font-size: 12px;
      font-weight: 800;
      letter-spacing: 0.02em;
      cursor: pointer;
      background: transparent;
      color: #475569;
      transition: all 0.18s ease;
    }

    .sgp-tab-btn:hover {
      background: rgba(241,245,249,0.95);
      color: #0f172a;
    }

    .sgp-tab-btn.active {
      background: linear-gradient(135deg, #0f172a, #1e293b);
      color: white;
      box-shadow: 0 10px 20px rgba(15,23,42,0.18);
    }

    .sgp-pages {
      flex: 1;
      min-height: 0;
      position: relative;
      overflow: hidden;
    }

    .sgp-page {
      position: absolute;
      inset: 0;
      display: none;
      flex-direction: column;
      gap: 12px;
      overflow-y: auto;
      overflow-x: hidden;
      padding-right: 4px;
      min-height: 0;
    }

    .sgp-page.active {
      display: flex;
    }

    .sgp-page::-webkit-scrollbar {
      width: 8px;
    }

    .sgp-page::-webkit-scrollbar-thumb {
      background: rgba(148,163,184,0.4);
      border-radius: 999px;
    }

    .sgp-page::-webkit-scrollbar-track {
      background: transparent;
    }

    .sgp-menu-card,
    .sgp-map-card,
    .sgp-info-card,
    .sgp-credit-page-card {
      background: #ffffff;
      border: 1px solid rgba(226,232,240,0.95);
      border-radius: 22px;
      box-shadow: 0 10px 30px rgba(15,23,42,0.06);
    }

    .sgp-menu-card {
      padding: 14px;
      display: flex;
      flex-direction: column;
      gap: 14px;
      background: linear-gradient(180deg, rgba(255,255,255,0.98), rgba(248,250,252,0.98));
      flex-shrink: 0;
    }

    .sgp-menu-section {
      display: flex;
      flex-direction: column;
      gap: 10px;
    }

    .sgp-menu-section-title {
      font-size: 11px;
      font-weight: 800;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: #64748b;
      padding: 0 2px;
    }

    .sgp-menu-labels,
    .sgp-menu-buttons {
      display: grid;
      gap: 10px;
    }

    .sgp-menu-labels {
      grid-template-columns: repeat(3, 1fr);
    }

    .sgp-menu-buttons {
      grid-template-columns: repeat(2, 1fr);
    }

    .sgp-menu-label-static {
      position: relative;
      padding: 14px 10px 12px;
      border-radius: 18px;
      background: linear-gradient(180deg, #ffffff, #f8fafc);
      border: 1px solid rgba(226,232,240,0.95);
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 9px;
      text-align: center;
      cursor: default;
      box-shadow: 0 8px 22px rgba(15,23,42,0.05);
    }

    .sgp-menu-label-static::after {
      content: "";
      position: absolute;
      inset: 0;
      border-radius: 18px;
      pointer-events: none;
      box-shadow: inset 0 1px 0 rgba(255,255,255,0.75);
    }

    .sgp-menu-item {
      position: relative;
      padding: 14px 10px 12px;
      border-radius: 18px;
      background: linear-gradient(180deg, #ffffff, #f8fafc);
      border: 1px solid rgba(226,232,240,0.95);
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 9px;
      cursor: pointer;
      text-align: center;
      box-shadow: 0 10px 24px rgba(15,23,42,0.07);
      transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease, background 0.18s ease;
    }

    .sgp-menu-item:hover {
      transform: translateY(-2px);
      box-shadow: 0 14px 28px rgba(15,23,42,0.11);
      border-color: rgba(148,163,184,0.45);
      background: linear-gradient(180deg, #ffffff, #f1f5f9);
    }

    .sgp-menu-item:active {
      transform: translateY(0);
    }

    .sgp-pin-btn {
      background: linear-gradient(135deg, #ecfdf5, #d1fae5);
      border: 1px solid rgba(16,185,129,0.22);
      outline: none;
    }

    .sgp-pin-btn:hover {
      background: linear-gradient(135deg, #f0fdf4, #bbf7d0);
      border-color: rgba(16,185,129,0.32);
    }

    .sgp-remove-pin-btn {
      background: linear-gradient(135deg, #fff7ed, #ffedd5);
      border: 1px solid rgba(249,115,22,0.20);
      outline: none;
    }

    .sgp-remove-pin-btn:hover {
      background: linear-gradient(135deg, #fff7ed, #fed7aa);
      border-color: rgba(249,115,22,0.32);
    }

    .sgp-menu-icon {
      width: 42px;
      height: 42px;
      border-radius: 15px;
      display: grid;
      place-items: center;
      background: linear-gradient(135deg, rgba(16,185,129,0.16), rgba(59,130,246,0.14));
      font-size: 19px;
      box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 6px 14px rgba(15,23,42,0.06);
    }

    .sgp-pin-btn .sgp-menu-icon {
      background: linear-gradient(135deg, rgba(16,185,129,0.24), rgba(34,197,94,0.18));
    }

    .sgp-remove-pin-btn .sgp-menu-icon {
      background: linear-gradient(135deg, rgba(249,115,22,0.20), rgba(251,146,60,0.16));
    }

    .sgp-menu-label {
      font-size: 12px;
      font-weight: 800;
      color: #0f172a;
      line-height: 1.25;
    }

    .sgp-menu-label-static .sgp-menu-label {
      color: #334155;
    }

    .sgp-menu-hint {
      font-size: 10px;
      font-weight: 600;
      color: #94a3b8;
      line-height: 1.2;
    }

    .sgp-credit-page-card {
      position: relative;
      overflow: hidden;
      padding: 22px;
      min-height: 100%;
      background:
        radial-gradient(circle at top right, rgba(52,211,153,0.16), transparent 26%),
        radial-gradient(circle at bottom left, rgba(59,130,246,0.14), transparent 28%),
        linear-gradient(135deg, #ffffff, #f8fafc);
      flex-shrink: 0;
    }

    .sgp-credit-page-card::after {
      content: "";
      position: absolute;
      inset: 0;
      pointer-events: none;
      background: linear-gradient(
        120deg,
        rgba(255,255,255,0.22),
        transparent 35%,
        transparent 65%,
        rgba(255,255,255,0.10)
      );
    }

    .sgp-credit-page-inner {
      position: relative;
      z-index: 1;
      display: flex;
      flex-direction: column;
      gap: 18px;
    }

    .sgp-credit-hero {
      text-align: center;
      padding: 8px 6px 2px;
    }

    .sgp-credit-kicker {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      padding: 7px 12px;
      border-radius: 999px;
      font-size: 10px;
      font-weight: 800;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: #0f172a;
      background: rgba(255,255,255,0.8);
      border: 1px solid rgba(226,232,240,0.92);
      box-shadow: 0 8px 18px rgba(15,23,42,0.05);
    }

    .sgp-credit-hero-title {
      margin-top: 14px;
      font-size: 24px;
      font-weight: 900;
      letter-spacing: -0.03em;
      color: #0f172a;
    }

    .sgp-credit-hero-subtitle {
      margin-top: 8px;
      font-size: 13px;
      line-height: 1.6;
      color: #475569;
      max-width: 300px;
      margin-left: auto;
      margin-right: auto;
    }

    .sgp-credit-showcase {
      display: grid;
      grid-template-columns: 1fr;
      gap: 14px;
    }

    .sgp-credit-profile {
      display: flex;
      align-items: center;
      gap: 14px;
      padding: 16px;
      border-radius: 22px;
      background: rgba(255,255,255,0.82);
      border: 1px solid rgba(226,232,240,0.95);
      box-shadow: 0 14px 30px rgba(15,23,42,0.07);
      backdrop-filter: blur(8px);
    }

    .sgp-credit-profile-avatar {
      width: 56px;
      height: 56px;
      border-radius: 18px;
      display: grid;
      place-items: center;
      font-size: 26px;
      flex-shrink: 0;
      background: linear-gradient(135deg, rgba(16,185,129,0.18), rgba(59,130,246,0.16));
      box-shadow: inset 0 1px 0 rgba(255,255,255,0.75), 0 10px 18px rgba(15,23,42,0.08);
    }

    .sgp-credit-profile-content {
      min-width: 0;
    }

    .sgp-credit-profile-role {
      font-size: 11px;
      font-weight: 800;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: #64748b;
      margin-bottom: 5px;
    }

    .sgp-credit-profile-name {
      font-size: 18px;
      font-weight: 900;
      color: #0f172a;
      line-height: 1.2;
    }

    .sgp-credit-profile-desc {
      margin-top: 6px;
      font-size: 12px;
      line-height: 1.5;
      color: #475569;
    }

    .sgp-info-card {
      padding: 12px 14px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 12px;
      flex-shrink: 0;
    }

    .sgp-info-left {
      min-width: 0;
    }

    .sgp-badge {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 6px 10px;
      border-radius: 999px;
      background: rgba(15,23,42,0.92);
      color: white;
      font-size: 11px;
      font-weight: 700;
      margin-bottom: 8px;
    }

    .sgp-coords {
      font-size: 13px;
      font-weight: 700;
      color: #0f172a;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      max-width: 220px;
    }

    .sgp-meta {
      font-size: 11px;
      color: #475569;
      margin-top: 4px;
    }

    .sgp-copy {
      padding: 10px 12px;
      border: none;
      border-radius: 14px;
      background: linear-gradient(135deg, #0f172a, #1e293b);
      color: white;
      font-size: 12px;
      font-weight: 700;
      cursor: pointer;
      transition: transform 0.15s ease, opacity 0.15s ease;
      white-space: nowrap;
    }

    .sgp-copy:hover {
      transform: translateY(-1px);
      opacity: 0.95;
    }

    .sgp-map-card {
      position: relative;
      min-height: 320px;
      overflow: hidden;
      display: flex;
      flex-direction: column;
      flex-shrink: 0;
    }

    .sgp-map-topbar {
      height: 42px;
      min-height: 42px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 0 12px;
      border-bottom: 1px solid rgba(15,23,42,0.06);
      background: #ffffff;
      font-size: 12px;
      font-weight: 700;
      color: #0f172a;
    }

    .sgp-map-status {
      color: #334155;
      font-size: 11px;
      font-weight: 600;
    }

    .sgp-iframe-wrap {
      position: relative;
      flex: 1;
      min-height: 260px;
      background: white;
    }

    .sgp-iframe {
      width: 100%;
      height: 100%;
      border: none;
      background: white;
      display: block;
    }

    .sgp-floating-status {
      position: absolute;
      left: 12px;
      bottom: 12px;
      z-index: 2;
      padding: 8px 10px;
      border-radius: 14px;
      background: rgba(15,23,42,0.78);
      color: white;
      font-size: 11px;
      font-weight: 700;
      box-shadow: 0 10px 20px rgba(0,0,0,0.2);
      max-width: calc(100% - 24px);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      pointer-events: none;
    }

    .sgp-game-pin {
      position: absolute;
      width: 26px;
      height: 26px;
      transform: translate(-50%, -100%);
      z-index: 1000;
      pointer-events: none;
      filter: drop-shadow(0 4px 6px rgba(0,0,0,0.35));
      display: grid;
      place-items: center;
      font-size: 26px;
      line-height: 1;
    }

    .sgp-resize {
      position: absolute;
      right: 0;
      bottom: 0;
      width: 24px;
      height: 24px;
      cursor: nwse-resize;
      background:
        linear-gradient(135deg, transparent 0%, transparent 46%, rgba(15,23,42,0.28) 47%, rgba(15,23,42,0.28) 54%, transparent 55%),
        linear-gradient(135deg, transparent 0%, transparent 63%, rgba(15,23,42,0.42) 64%, rgba(15,23,42,0.42) 71%, transparent 72%),
        linear-gradient(135deg, transparent 0%, transparent 80%, rgba(15,23,42,0.6) 81%, rgba(15,23,42,0.6) 88%, transparent 89%);
    }

    .sgp-dock {
      position: fixed;
      left: 22px;
      bottom: 88px;
      z-index: 100002;
      display: none;
      align-items: center;
      gap: 10px;
      padding: 10px 14px;
      border-radius: 16px;
      background: rgba(15,23,42,0.95);
      color: white;
      box-shadow: 0 14px 36px rgba(0,0,0,0.28);
      cursor: pointer;
      font-size: 13px;
      font-weight: 700;
    }

    .sgp-dock.show {
      display: flex;
    }
  `;
  document.head.appendChild(style);

  const fab = document.createElement("button");
  fab.className = "sgp-fab";
  fab.innerHTML = `
    <span class="sgp-fab-icon">🗺</span>
    <span>Open Secret Project</span>
  `;
  root.appendChild(fab);

  const dock = document.createElement("div");
  dock.className = "sgp-dock";
  dock.innerHTML = `<span>🗺</span><span>Secret Project minimized</span>`;
  root.appendChild(dock);

  const overlay = document.createElement("div");
  overlay.className = "sgp-overlay";
  root.appendChild(overlay);

  const panel = document.createElement("div");
  panel.className = "sgp-panel";
  panel.style.width = `${savedWidth}px`;
  panel.style.height = `${savedHeight}px`;
  overlay.appendChild(panel);

  const header = document.createElement("div");
  header.className = "sgp-header";
  panel.appendChild(header);

  const headerLeft = document.createElement("div");
  headerLeft.className = "sgp-header-left";
  header.appendChild(headerLeft);

  const logo = document.createElement("div");
  logo.className = "sgp-logo";
  logo.textContent = "⌖";
  headerLeft.appendChild(logo);

  const titleGroup = document.createElement("div");
  titleGroup.className = "sgp-title-group";
  headerLeft.appendChild(titleGroup);

  const title = document.createElement("div");
  title.className = "sgp-title";
  title.textContent = "Secret Project";
  titleGroup.appendChild(title);

  const subtitle = document.createElement("div");
  subtitle.className = "sgp-subtitle";
  subtitle.textContent = "Location tools • live map • draggable panel";
  titleGroup.appendChild(subtitle);

  const actions = document.createElement("div");
  actions.className = "sgp-actions";
  header.appendChild(actions);

  const minimizeBtn = document.createElement("button");
  minimizeBtn.className = "sgp-btn";
  minimizeBtn.textContent = "–";
  actions.appendChild(minimizeBtn);

  const closeBtn = document.createElement("button");
  closeBtn.className = "sgp-btn";
  closeBtn.textContent = "✕";
  actions.appendChild(closeBtn);

  const content = document.createElement("div");
  content.className = "sgp-content";
  panel.appendChild(content);

  const tabs = document.createElement("div");
  tabs.className = "sgp-tabs";
  tabs.innerHTML = `
    <button class="sgp-tab-btn active" data-tab="menu" type="button">Menu</button>
    <button class="sgp-tab-btn" data-tab="credits" type="button">Credits</button>
  `;
  content.appendChild(tabs);

  const pages = document.createElement("div");
  pages.className = "sgp-pages";
  content.appendChild(pages);

  const menuPage = document.createElement("div");
  menuPage.className = "sgp-page active";
  menuPage.style.overflowY = "auto";
  menuPage.style.overflowX = "hidden";
  pages.appendChild(menuPage);

  const creditsPage = document.createElement("div");
  creditsPage.className = "sgp-page";
  creditsPage.style.overflowY = "auto";
  creditsPage.style.overflowX = "hidden";
  pages.appendChild(creditsPage);

  const menuCard = document.createElement("div");
  menuCard.className = "sgp-menu-card";
  menuCard.innerHTML = `
    <div class="sgp-menu-section">
      <div class="sgp-menu-section-title">Overview</div>
      <div class="sgp-menu-labels">
        <div class="sgp-menu-label-static">
          <div class="sgp-menu-icon">📍</div>
          <div class="sgp-menu-label">Live Coordinates</div>
          <div class="sgp-menu-hint">Auto-detected</div>
        </div>
        <div class="sgp-menu-label-static">
          <div class="sgp-menu-icon">🛰</div>
          <div class="sgp-menu-label">Map Viewer</div>
          <div class="sgp-menu-hint">Preview panel</div>
        </div>
        <div class="sgp-menu-label-static">
          <div class="sgp-menu-icon">🧭</div>
          <div class="sgp-menu-label">Quick Position</div>
          <div class="sgp-menu-hint">Current location</div>
        </div>
      </div>
    </div>

    <div class="sgp-menu-section">
      <div class="sgp-menu-section-title">Actions</div>
      <div class="sgp-menu-buttons">
        <button class="sgp-menu-item sgp-pin-btn" type="button">
          <div class="sgp-menu-icon">📌</div>
          <div class="sgp-menu-label">Add Pin</div>
          <div class="sgp-menu-hint">Place marker</div>
        </button>
        <button class="sgp-menu-item sgp-remove-pin-btn" type="button">
          <div class="sgp-menu-icon">✖</div>
          <div class="sgp-menu-label">Remove Pin</div>
          <div class="sgp-menu-hint">Clear marker</div>
        </button>
      </div>
    </div>
  `;
  menuPage.appendChild(menuCard);

  const infoCard = document.createElement("div");
  infoCard.className = "sgp-info-card";
  infoCard.innerHTML = `
    <div class="sgp-info-left">
      <div class="sgp-badge">● Tracking page data</div>
      <div class="sgp-coords">Waiting for coordinates...</div>
      <div class="sgp-meta">Auto-refresh every 2 seconds</div>
    </div>
  `;
  menuPage.appendChild(infoCard);

  const copyBtn = document.createElement("button");
  copyBtn.className = "sgp-copy";
  copyBtn.textContent = "Copy";
  infoCard.appendChild(copyBtn);

  const mapCard = document.createElement("div");
  mapCard.className = "sgp-map-card";
  menuPage.appendChild(mapCard);

  const mapTopbar = document.createElement("div");
  mapTopbar.className = "sgp-map-topbar";
  mapTopbar.innerHTML = `
    <span>Google Maps preview</span>
    <span class="sgp-map-status">No location detected yet</span>
  `;
  mapCard.appendChild(mapTopbar);

  const iframeWrap = document.createElement("div");
  iframeWrap.className = "sgp-iframe-wrap";
  mapCard.appendChild(iframeWrap);

  const iframe = document.createElement("iframe");
  iframe.className = "sgp-iframe";
  iframe.loading = "lazy";
  iframe.referrerPolicy = "no-referrer-when-downgrade";
  iframe.allowFullscreen = true;
  iframe.src = "about:blank";
  iframeWrap.appendChild(iframe);

  const floatingStatus = document.createElement("div");
  floatingStatus.className = "sgp-floating-status";
  floatingStatus.textContent = "Waiting for coordinates...";
  iframeWrap.appendChild(floatingStatus);

  const creditPageCard = document.createElement("div");
  creditPageCard.className = "sgp-credit-page-card";
  creditPageCard.innerHTML = `
    <div class="sgp-credit-page-inner">
      <div class="sgp-credit-hero">
        <div class="sgp-credit-kicker">✨ Secret Project Credits</div>
        <div class="sgp-credit-hero-title">Built with vision</div>
        <div class="sgp-credit-hero-subtitle">
          A dedicated page honoring the minds behind the experience.
        </div>
      </div>

      <div class="sgp-credit-showcase">
        <div class="sgp-credit-profile">
          <div class="sgp-credit-profile-avatar">👑</div>
          <div class="sgp-credit-profile-content">
            <div class="sgp-credit-profile-role">Founder</div>
            <div class="sgp-credit-profile-name">RandomAccount</div>
            <div class="sgp-credit-profile-desc">
              Visionary behind the concept, direction, and identity of Secret Project.
            </div>
          </div>
        </div>

        <div class="sgp-credit-profile">
          <div class="sgp-credit-profile-avatar">🤖</div>
          <div class="sgp-credit-profile-content">
            <div class="sgp-credit-profile-role">Developer</div>
            <div class="sgp-credit-profile-name">ChatGPT</div>
            <div class="sgp-credit-profile-desc">
              Designed and engineered the interface, logic, layout, and interactive experience.
            </div>
          </div>
        </div>
      </div>
    </div>
  `;
  creditsPage.appendChild(creditPageCard);

  const coordsEl = infoCard.querySelector(".sgp-coords");
  const pinBtn = menuCard.querySelector(".sgp-pin-btn");
  const removePinBtn = menuCard.querySelector(".sgp-remove-pin-btn");
  const mapStatus = mapTopbar.querySelector(".sgp-map-status");
  const tabButtons = tabs.querySelectorAll(".sgp-tab-btn");

  function setActiveTab(tabName) {
    activeTab = tabName;

    tabButtons.forEach((btn) => {
      btn.classList.toggle("active", btn.dataset.tab === tabName);
    });

    menuPage.classList.toggle("active", tabName === "menu");
    creditsPage.classList.toggle("active", tabName === "credits");
  }

  tabButtons.forEach((btn) => {
    btn.addEventListener("click", (event) => {
      event.stopPropagation();
      setActiveTab(btn.dataset.tab);
    });
  });

  const resizeHandle = document.createElement("div");
  resizeHandle.className = "sgp-resize";
  panel.appendChild(resizeHandle);

  function openWindow() {
    overlay.classList.add("open");
    fab.innerHTML = `<span class="sgp-fab-icon">✕</span><span>Close Secret Project</span>`;
    dock.classList.remove("show");
    isOpen = true;
  }

  function closeWindow() {
    overlay.classList.remove("open");
    fab.innerHTML = `<span class="sgp-fab-icon">🗺</span><span>Open Secret Project</span>`;
    dock.classList.remove("show");
    isOpen = false;
    isMinimized = false;
    content.style.display = "flex";
    panel.style.height = `${savedHeight}px`;
    panel.style.width = `${savedWidth}px`;
    minimizeBtn.textContent = "–";
    resizeHandle.style.display = "block";
  }

  function minimizeWindow() {
    if (!isMinimized) {
      savedHeight = panel.offsetHeight;
      savedWidth = panel.offsetWidth;
      content.style.display = "none";
      resizeHandle.style.display = "none";
      panel.style.height = "68px";
      panel.style.width = "320px";
      minimizeBtn.textContent = "▢";
      dock.classList.add("show");
    } else {
      content.style.display = "flex";
      resizeHandle.style.display = "block";
      panel.style.height = `${savedHeight}px`;
      panel.style.width = `${savedWidth}px`;
      minimizeBtn.textContent = "–";
      dock.classList.remove("show");
    }
    isMinimized = !isMinimized;
  }

  fab.addEventListener("click", () => {
    if (isOpen) {
      closeWindow();
    } else {
      openWindow();
    }
  });

  closeBtn.addEventListener("click", (event) => {
    event.stopPropagation();
    closeWindow();
  });

  minimizeBtn.addEventListener("click", (event) => {
    event.stopPropagation();
    minimizeWindow();
  });

  dock.addEventListener("click", () => {
    if (isOpen && isMinimized) {
      minimizeWindow();
    }
  });

  overlay.addEventListener("mousedown", (event) => {
    if (event.target === overlay) {
      closeWindow();
    }
  });

  header.addEventListener("mousedown", (event) => {
    if (event.target === minimizeBtn || event.target === closeBtn) {
      return;
    }

    isDragging = true;
    const rect = panel.getBoundingClientRect();
    offsetX = event.clientX - rect.left;
    offsetY = event.clientY - rect.top;
  });

  resizeHandle.addEventListener("mousedown", (event) => {
    event.stopPropagation();
    isResizing = true;
  });

  document.addEventListener("mousemove", (event) => {
    if (isDragging) {
      const maxLeft = window.innerWidth - panel.offsetWidth - 10;
      const maxTop = window.innerHeight - panel.offsetHeight - 10;
      const newLeft = Math.min(Math.max(10, event.clientX - offsetX), Math.max(10, maxLeft));
      const newTop = Math.min(Math.max(10, event.clientY - offsetY), Math.max(10, maxTop));
      panel.style.left = `${newLeft}px`;
      panel.style.top = `${newTop}px`;
    }

    if (isResizing && !isMinimized) {
      const rect = panel.getBoundingClientRect();
      const newWidth = Math.max(event.clientX - rect.left, 340);
      const newHeight = Math.max(event.clientY - rect.top, 360);
      panel.style.width = `${newWidth}px`;
      panel.style.height = `${newHeight}px`;
      savedWidth = newWidth;
      savedHeight = newHeight;
    }
  });

  document.addEventListener("mouseup", () => {
    isDragging = false;
    isResizing = false;
  });

  copyBtn.addEventListener("click", async () => {
    if (!lastCoords) {
      return;
    }

    try {
      await navigator.clipboard.writeText(lastCoords);
      copyBtn.textContent = "Copied";
      setTimeout(() => {
        copyBtn.textContent = "Copy";
      }, 1200);
    } catch (error) {
      copyBtn.textContent = "Failed";
      setTimeout(() => {
        copyBtn.textContent = "Copy";
      }, 1200);
    }
  });

  pinBtn.addEventListener("click", (event) => {
    event.stopPropagation();
    const latLng = getCurrentLatLng();

    if (!latLng) {
      floatingStatus.textContent = "No coordinates available yet";
      mapStatus.textContent = "Pin failed";
      return;
    }

    pinEnabled = true;
    pinnedLatLng = latLng;
    refreshGamePin();
  });

  removePinBtn.addEventListener("click", (event) => {
    event.stopPropagation();
    pinEnabled = false;
    pinnedLatLng = null;

    document.querySelectorAll(".sgp-game-pin").forEach((pin) => pin.remove());

    mapStatus.textContent = "Pin removed";
    floatingStatus.textContent = lastCoords
      ? `Lat ${lastCoords.split(",")[0]} • Lng ${lastCoords.split(",")[1]}`
      : "Waiting for coordinates...";
  });

  function extractCoords() {
    const html = document.documentElement.innerHTML;
    const patterns = [
      /(-?\d{1,3}\.\d+)\s*,\s*(-?\d{1,3}\.\d+)/,
      /"lat"\s*:\s*(-?\d{1,3}\.\d+).*?"lng"\s*:\s*(-?\d{1,3}\.\d+)/i,
      /"latitude"\s*:\s*(-?\d{1,3}\.\d+).*?"longitude"\s*:\s*(-?\d{1,3}\.\d+)/i
    ];

    for (const pattern of patterns) {
      const match = html.match(pattern);

      if (match) {
        const lat = parseFloat(match[1]);
        const lng = parseFloat(match[2]);

        if (
          !Number.isNaN(lat) &&
          lat >= -90 &&
          lat <= 90 &&
          !Number.isNaN(lng) &&
          lng >= -180 &&
          lng <= 180
        ) {
          return `${lat},${lng}`;
        }
      }
    }

    return null;
  }

  function getCurrentLatLng() {
    if (!lastCoords) {
      return null;
    }

    const [latStr, lngStr] = lastCoords.split(",");
    const lat = parseFloat(latStr);
    const lng = parseFloat(lngStr);

    if (Number.isNaN(lat) || Number.isNaN(lng)) {
      return null;
    }

    return { lat, lng };
  }

  function getOrCreateGamePin(container) {
    let pin = container.querySelector(".sgp-game-pin");

    if (!pin) {
      pin = document.createElement("div");
      pin.className = "sgp-game-pin";
      pin.textContent = "📍";
      container.appendChild(pin);
    }

    return pin;
  }

  function parseTranslateAndScale(transformValue) {
    if (!transformValue || transformValue === "none") {
      return { x: 0, y: 0, scale: 1 };
    }

    const match3d = transformValue.match(
      /translate3d\(([-\d.]+)px,\s*([-\d.]+)px,\s*[-\d.]+px\)(?:\s*scale\(([-\d.]+)\))?/
    );

    if (match3d) {
      return {
        x: parseFloat(match3d[1]) || 0,
        y: parseFloat(match3d[2]) || 0,
        scale: parseFloat(match3d[3]) || 1
      };
    }

    const match2d = transformValue.match(
      /translate\(([-\d.]+)px,\s*([-\d.]+)px\)(?:\s*scale\(([-\d.]+)\))?/
    );

    if (match2d) {
      return {
        x: parseFloat(match2d[1]) || 0,
        y: parseFloat(match2d[2]) || 0,
        scale: parseFloat(match2d[3]) || 1
      };
    }

    return { x: 0, y: 0, scale: 1 };
  }

  function latLngToWorldPixel(lat, lng, zoom) {
    const tileSize = 256;
    const scale = tileSize * Math.pow(2, zoom);
    const x = ((lng + 180) / 360) * scale;
    const sinLat = Math.sin((lat * Math.PI) / 180);
    const clamped = Math.min(Math.max(sinLat, -0.9999), 0.9999);
    const y = (0.5 - Math.log((1 + clamped) / (1 - clamped)) / (4 * Math.PI)) * scale;
    return { x, y };
  }

  function isLeafletMapCandidate(obj, container) {
    return Boolean(
      obj &&
        typeof obj === "object" &&
        typeof obj.latLngToContainerPoint === "function" &&
        typeof obj.containerPointToLatLng === "function" &&
        typeof obj.getZoom === "function" &&
        obj._container === container
    );
  }

  function findLeafletMapNearContainer(container) {
    if (!container) {
      return null;
    }

    const seen = new WeakSet();
    const roots = [container, container.parentElement, container.closest("#miniMapArea"), window];

    function scan(obj, depth) {
      if (!obj || typeof obj !== "object" || seen.has(obj) || depth < 0) {
        return null;
      }

      seen.add(obj);

      if (isLeafletMapCandidate(obj, container)) {
        return obj;
      }

      let keys = [];

      try {
        keys = Object.getOwnPropertyNames(obj);
      } catch (error) {
        return null;
      }

      for (const key of keys) {
        if (key === "parentNode" || key === "children" || key === "childNodes") {
          continue;
        }

        let value;

        try {
          value = obj[key];
        } catch (error) {
          continue;
        }

        if (!value || typeof value !== "object") {
          continue;
        }

        if (isLeafletMapCandidate(value, container)) {
          return value;
        }

        const found = scan(value, depth - 1);
        if (found) {
          return found;
        }
      }

      return null;
    }

    for (const rootNode of roots) {
      const found = scan(rootNode, rootNode === window ? 2 : 4);
      if (found) {
        return found;
      }
    }

    return null;
  }

  function getDomProjectionContext() {
    const mapArea = document.querySelector("#miniMapArea");
    const container = mapArea?.querySelector(".leaflet-container");
    const mapPane = mapArea?.querySelector(".leaflet-map-pane");
    const tileContainer = mapArea?.querySelector(".leaflet-tile-container");

    if (!mapArea || !container || !mapPane || !tileContainer) {
      return null;
    }

    const tiles = Array.from(mapArea.querySelectorAll(".leaflet-tile-pane .leaflet-tile-loaded"));

    if (!tiles.length) {
      return null;
    }

    let bestTile = null;
    let bestScore = Infinity;

    for (const tile of tiles) {
      const src = tile.getAttribute("src") || "";
      const xMatch = src.match(/[?&]x=(-?\d+)/);
      const yMatch = src.match(/[?&]y=(-?\d+)/);
      const zMatch = src.match(/[?&]z=(\d+)/);

      if (!xMatch || !yMatch || !zMatch) {
        continue;
      }

      const tileTransform = parseTranslateAndScale(tile.style.transform);
      const containerTransform = parseTranslateAndScale(tileContainer.style.transform);
      const score = Math.abs((containerTransform.scale || 1) - 1);

      if (score < bestScore) {
        bestScore = score;
        bestTile = {
          tileX: parseInt(xMatch[1], 10),
          tileY: parseInt(yMatch[1], 10),
          zoom: parseInt(zMatch[1], 10),
          tileTransform,
          containerTransform
        };
      }
    }

    if (!bestTile) {
      return null;
    }

    const mapPaneTransform = parseTranslateAndScale(mapPane.style.transform);

    return {
      container,
      zoom: bestTile.zoom,
      tileX: bestTile.tileX,
      tileY: bestTile.tileY,
      tileXOffset: bestTile.tileTransform.x,
      tileYOffset: bestTile.tileTransform.y,
      tileContainerX: bestTile.containerTransform.x,
      tileContainerY: bestTile.containerTransform.y,
      tileScale: bestTile.containerTransform.scale || 1,
      mapPaneX: mapPaneTransform.x,
      mapPaneY: mapPaneTransform.y
    };
  }

  function projectWithDomFallback(latLng) {
    const ctx = getDomProjectionContext();

    if (!ctx) {
      return null;
    }

    const world = latLngToWorldPixel(latLng.lat, latLng.lng, ctx.zoom);
    const tileWorldX = ctx.tileX * 256;
    const tileWorldY = ctx.tileY * 256;

    const pixelX =
      ctx.mapPaneX +
      ctx.tileContainerX +
      ctx.tileXOffset +
      (world.x - tileWorldX) * ctx.tileScale;

    const pixelY =
      ctx.mapPaneY +
      ctx.tileContainerY +
      ctx.tileYOffset +
      (world.y - tileWorldY) * ctx.tileScale;

    return {
      container: ctx.container,
      x: pixelX,
      y: pixelY
    };
  }

  function refreshGamePin() {
    if (!pinEnabled || !pinnedLatLng) {
      return;
    }

    const container = document.querySelector("#miniMapArea .leaflet-container");

    if (!container) {
      mapStatus.textContent = "Pin failed";
      floatingStatus.textContent = "Game map not found";
      return;
    }

    const leafletMap = findLeafletMapNearContainer(container);

    if (leafletMap) {
      try {
        const point = leafletMap.latLngToContainerPoint([pinnedLatLng.lat, pinnedLatLng.lng]);
        const pin = getOrCreateGamePin(container);
        pin.style.left = `${point.x}px`;
        pin.style.top = `${point.y}px`;

        const inView =
          point.x >= 0 &&
          point.y >= 0 &&
          point.x <= container.clientWidth &&
          point.y <= container.clientHeight;

        mapStatus.textContent = inView ? "Pin fixed" : "Pin off-screen";
        floatingStatus.textContent = inView
          ? `Pin fixed on map • ${pinnedLatLng.lat}, ${pinnedLatLng.lng}`
          : `Pin is off-screen • ${pinnedLatLng.lat}, ${pinnedLatLng.lng}`;
        return;
      } catch (error) {
        // Fall back to DOM projection below.
      }
    }

    const projected = projectWithDomFallback(pinnedLatLng);

    if (!projected) {
      mapStatus.textContent = "Pin failed";
      floatingStatus.textContent = "Could not project pin";
      return;
    }

    const pin = getOrCreateGamePin(projected.container);
    pin.style.left = `${projected.x}px`;
    pin.style.top = `${projected.y}px`;

    const inView =
      projected.x >= 0 &&
      projected.y >= 0 &&
      projected.x <= projected.container.clientWidth &&
      projected.y <= projected.container.clientHeight;

    mapStatus.textContent = inView ? "Pin tracking" : "Pin off-screen";
    floatingStatus.textContent = inView
      ? `Pin tracking map • ${pinnedLatLng.lat}, ${pinnedLatLng.lng}`
      : `Pin is off-screen • ${pinnedLatLng.lat}, ${pinnedLatLng.lng}`;
  }

  function updatePreviewIframe(lat, lng) {
    const url = `https://www.google.com/maps?q=${encodeURIComponent(`${lat},${lng}`)}&z=6&output=embed`;

    if (iframe.src !== url) {
      iframe.src = url;
    }
  }

  function updateMap() {
    const coords = extractCoords();

    if (!coords) {
      refreshGamePin();
      return;
    }

    if (coords !== lastCoords) {
      const [lat, lng] = coords.split(",");
      lastCoords = coords;

      coordsEl.textContent = `${lat}, ${lng}`;
      floatingStatus.textContent = `Lat ${lat} • Lng ${lng}`;
      mapStatus.textContent = "Location detected";
      updatePreviewIframe(lat, lng);

      if (pinEnabled) {
        pinnedLatLng = {
          lat: parseFloat(lat),
          lng: parseFloat(lng)
        };
      }
    }

    refreshGamePin();
  }

  setInterval(updateMap, 50);
})();