(function () {
  'use strict';

  const { useState, useRef, useEffect, useCallback, useMemo } = React;
  // ReactDOM is available as a global (CDN-loaded alongside React)

/*
 * ═══════════════════════════════════════════════════════════════════════════════
 * PZO INTERACTIVE WORLD MAP
 * ═══════════════════════════════════════════════════════════════════════════════
 *
 * PURPOSE:
 *   Interactive regional map component for the Phantom Zenith Origin website.
 *   Displays the area surrounding Haven Core with clickable landmarks, cursor-
 *   driven parallax panning, and a parabolic perspective warp to simulate a
 *   holographic terminal display.
 *
 * VISUAL DESIGN:
 *   - Dark blue-black base (--map-land landmass, --map-sea at 40% opacity)
 *   - Muted mint-teal grid (--map-grid at 40% opacity, 0.75px stroke)
 *   - Solid coastline stroke matching grid color at 37.5% opacity
 *   - Scanline overlay for CRT/holographic texture
 *   - 10° CSS perspective warp (rotateX) for curved-surface illusion
 *   - Corner clipping from perspective warp is intentional — reads as
 *     holographic display edge falloff
 *   - Dashed outlines for landmarks, color-coded by type
 *   - Share Tech Mono for all text (PZO's terminal/data font)
 *
 * INTERACTION MODEL:
 *   Desktop: Cursor position drives a soft parallax pan of the map. The
 *     viewport is slightly smaller than the full map extent (~15% overflow),
 *     so moving the cursor toward edges reveals more of the map. Cursor
 *     tracking uses cubic easing (pow 1.5) so movement is gentle near center
 *     and accelerating toward edges. Hovering a landmark highlights its label.
 *     Clicking opens a popover card with description + future CTA slot.
 *   Mobile: Tap to select a landmark (pans to center it). Tap elsewhere to
 *     deselect. No hover-to-pan since there's no persistent cursor.
 *   Both: When a landmark is selected, the map pans to center on it.
 *     Dismissing the popover returns to default behavior (cursor-following
 *     on desktop, centered on mobile).
 *
 * POPOVER ARCHITECTURE:
 *   The popover card is rendered via React portal (ReactDOM.createPortal) to
 *   document.body. This is necessary because the map container uses
 *   overflow:hidden for the parallax panning, which would clip popovers near
 *   edges. The portal keeps the popover in the top-level DOM stacking context
 *   while React still fully owns its lifecycle within this component.
 *   Positioning uses position:fixed with viewport-relative coordinates from
 *   SVG's getScreenCTM(), updated every animation frame while selected.
 *   A document-level click listener handles click-outside dismissal since
 *   the popover isn't a DOM child of the map container.
 *
 * DATA EXTERNALIZATION NOTES:
 *   All map data (landmarks, terrain paths, config) is defined in the
 *   LANDMARK_DATA, TERRAIN_DATA, and MAP_CONFIG objects at the top of this
 *   file. These are intentionally structured for easy extraction into separate
 *   JSON or JS data files when the website's data pipeline
 *   (assets/data/*.js with IIFE patterns writing to window.PZO.data) is
 *   ready to absorb them.
 *
 *   When externalizing:
 *   1. Move LANDMARK_DATA → assets/data/worldmap-landmarks.js
 *   2. Move TERRAIN_DATA → assets/data/worldmap-terrain.js
 *   3. Move MAP_CONFIG → assets/data/worldmap-config.js  (or merge into one)
 *   4. Have each write to window.PZO.data.worldmap.landmarks, .terrain, .config
 *   5. This component then reads from props or a context provider instead of
 *      importing the constants directly.
 *
 *   The terrain SVG paths (coastlines, sea shapes) are defined as path data
 *   strings so they remain resolution-independent and can be authored in any
 *   vector tool then pasted in as `d` attribute values.
 *
 * FUTURE FEATURES (not yet implemented):
 *   - "View in Field Record" CTA button inside popover cards
 *     (wire via onNavigateToRecord(landmarkId) prop callback)
 *   - Stage-specific color overlays or pulsing indicators for active missions
 *   - Fog-of-war / progressive reveal based on player progression
 *   - Connection lines between related landmarks
 */


/* ─────────────────────────────────────────────────────────────────────────────
 * MAP CONFIGURATION
 * ─────────────────────────────────────────────────────────────────────────────
 * Controls the viewport, parallax, and perspective behavior.
 * When externalized, this becomes its own config file or merges into a
 * unified worldmap data file.
 */
const MAP_CONFIG = {
  // The "virtual canvas" size in arbitrary units. All landmark positions and
  // terrain paths are authored relative to this coordinate space.
  // 1600×1200 gives a 4:3 working area with plenty of room.
  canvasWidth: 1600,
  canvasHeight: 1200,

  // How much larger the map canvas is than the visible viewport, as a ratio.
  // 1.15 means the canvas is 15% larger than what's shown — the extra 15%
  // is the parallax travel range. Kept small so all landmarks remain visible
  // from the default centered position.
  parallaxOverflow: 1.15,

  // How quickly the viewport tracks the cursor. Lower = smoother/slower.
  // This is the lerp factor applied per animation frame.
  panEasing: 0.04,

  // CSS perspective degree for the parabolic warp effect.
  // 10° gives a pronounced holographic curve. The resulting corner clipping
  // from overflow:hidden is intentional and reads as display edge falloff.
  // Tested range: 4° (subtle) → 16° (extreme). 10° is the sweet spot.
  perspectiveDeg: 10,

  // Grid line spacing in canvas units
  gridSpacing: 80,

  // How long the pan-to-landmark animation takes (ms) before easing settles
  panToLandmarkDuration: 600,
};


/* ─────────────────────────────────────────────────────────────────────────────
 * LANDMARK DATA
 * ─────────────────────────────────────────────────────────────────────────────
 * Each landmark has:
 *   id              – unique key (will map to Field Record entry IDs)
 *   name            – display label (rendered uppercase via CSS)
 *   type            – "city" | "region" | "location" | "hotzone"
 *                     Determines icon shape, color, and border style
 *   x, y            – center position in canvas units (0,0 = top-left)
 *   description     – short blurb for the popover card
 *   size            – relative size multiplier for the icon (default 1)
 *   fieldRecordSlug – (future) URL slug for Field Record navigation, or null
 *
 * PLACEHOLDER NOTE: All names, positions, descriptions, and sizes below are
 * placeholders. Replace with authored PZO world data when ready. The visual
 * representation (icon shape, outline style) is driven by `type`, so adding
 * new landmarks is purely a data authoring task — no code changes needed.
 *
 * POSITIONING GUIDE: Keep landmarks within the inner ~90% of the canvas
 * (roughly x: 80-1520, y: 60-1140) to avoid labels being clipped by the
 * perspective warp's corner falloff effect.
 */
const LANDMARK_DATA = [
  {
    id: "haven-core",
    name: "Haven Core",
    type: "city",
    x: 564,
    y: 235,
    size: 2,
    description:
      "The central city-state and last bastion of organized civilization on Orryx. All Runner operations originate from and return to Haven Core.",
    fieldRecordSlug: "haven-core",
  },
  {
    id: "veilwood-fractals",
    name: "Veilwood Fractals",
    type: "region",
    x: 200,
    y: 310,
    size: 1.5,
    description:
      "Tessellated forest region where trees reproduce via geometric splitting triggered by Refractant saturation. Navigational disorientation, audio distortion, and reactive flora make sustained operations difficult.",
    fieldRecordSlug: null,
  },
  {
    id: "glass-reaches",
    name: "Glass Reaches",
    type: "region",
    x: 1030,
    y: 670,
    size: 1.4,
    description:
      "Vast fused silica plains produced by a historical Refractant detonation. Mirror-smooth for kilometers with extreme environmental exposure. Ancient salvage lies sealed under the glass surface.",
    fieldRecordSlug: null,
  },
  {
    id: "lumen-marshes",
    name: "Lumen Marshes",
    type: "region",
    x: 310,
    y: 720,
    size: 1.4,
    description:
      "Bioluminescent wetlands fed by underground Refractant seepage. Native fauna exhibit psionic mimicry — the capacity to project false sensory information as a biological defense adaptation.",
    fieldRecordSlug: null,
  },
  {
    id: "hollow-trenches",
    name: "Hollow Trenches",
    type: "region",
    x: 729,
    y: 180,
    size: 1.3,
    description:
      "Deep ravines carved by collapsed orbital elevators from the colonial era. Structurally complex metallic terrain. Heritage site for early Karn autonomous communities.",
    fieldRecordSlug: null,
  },
  {
    id: "thales-refuge",
    name: "Thale's Refuge",
    type: "location",
    x: 1350,
    y: 850,
    size: 1.0,
    description:
      "Fortified mining town exporting metals to Haven Core. One to four days' travel depending on route and conditions. The closest thing to a second city the region has.",
    fieldRecordSlug: null,
  },
  {
    id: "ovir-station",
    name: "Ovir Station",
    type: "location",
    x: 732,
    y: 900,
    size: 0.9,
    description:
      "Black-market biotech hub built on a derelict monorail junction. The Governmental Consensus knows about it. The relationship is complicated.",
    fieldRecordSlug: null,
  },
  {
    id: "bralin",
    name: "Bralin",
    type: "location",
    x: 160,
    y: 580,
    size: 1.0,
    description:
      "Sire-majority enclave specializing in psionic horticulture. Predates Haven Core. Living continuity with pre-contact Sire tradition and knowledge the city has never thought to ask about.",
    fieldRecordSlug: null,
  },
  {
    id: "refractant-breach",
    name: "The Saturation",
    type: "hotzone",
    x: 390,
    y: 1050,
    size: 0.8,
    description:
      "A volatile region where subsurface Refractant deposits have breached the surface in sustained, unpredictable eruptions. Extremely hazardous. High-value mineral salvage reported by surviving survey teams.",
    fieldRecordSlug: null,
  },
  {
    id: "dust-flats",
    name: "Periarch Flats",
    type: "location",
    x: 748,
    y: 385,
    size: 0.9,
    description:
      "Arid dust plains and canyon approaches marking the transition from the Threshold Expanse into true wilderness. Derelict extraction infrastructure and abandoned processing facilities line the route outward.",
    fieldRecordSlug: null,
  },
];


/* ─────────────────────────────────────────────────────────────────────────────
 * TERRAIN DATA
 * ─────────────────────────────────────────────────────────────────────────────
 * SVG path data for terrain features rendered behind landmarks.
 * Each entry has:
 *   id       – unique key
 *   type     – "sea" | "coastline" | (future: "river", "road", etc.)
 *   d        – SVG path `d` attribute string, authored in canvas coordinates
 *   opacity  – fill/stroke opacity (used as fallback; render logic may override)
 *
 * RENDERING NOTES:
 *   - Sea: Filled with --map-sea at 40% opacity. The low opacity lets the
 *     grid lines bleed through, creating a unified scanner aesthetic across
 *     land and sea while still reading as distinct zones.
 *   - Coastline: Solid stroke in --map-grid color at 37.5% opacity.
 *     Originally dashed, changed to solid during visual iteration for a
 *     cleaner land/sea boundary that matches the grid's visual weight.
 *
 * AUTHOR GUIDE: Paths must extend well beyond the canvas bounds to avoid
 * showing edges during parallax panning. Current sea path extends from
 * y:-400 to y:1600 and x out to 2200 (canvas is 1600×1200 with ~120px
 * parallax overflow on each side). When authoring new terrain, pad
 * generously — at least 400 units beyond canvas edges in any direction
 * the terrain touches.
 *
 * PLACEHOLDER NOTE: The paths below are rough placeholders. Author final
 * coastline/terrain shapes in a vector editor, export path data, and paste
 * here (or into the externalized data file).
 */
const TERRAIN_DATA = [
  {
    id: "sea-main",
    type: "sea",
    // Bounding rectangle with authored landmass cut out via evenodd fill-rule.
    // The rectangle fills everything with sea color; evenodd subtracts the
    // landmass interior (including island cutouts from the original SVG).
    // Coordinates are pre-scaled from the 1896×1897 source SVG to the
    // 1600×1200 canvas space (scale 0.8439, Y offset -200.4 to center).
    // Bounding box extends 500 units beyond canvas edges for parallax safety.
    fillRule: "evenodd",
    d: `M -500 -500 L 2100 -500 L 2100 1700 L -500 1700 Z M 1007.6 -199.6 L 992.0 -159.5 C 989.2 -157.2 982.6 -151.6 978.9 -146.8 C 975.2 -142.1 969.5 -123.8 967.1 -115.2 L 957.4 -98.7 L 949.4 -90.7 V -67.5 L 943.0 -51.5 L 929.9 -41.4 H 908.4 L 894.1 -56.1 L 888.2 -73.8 L 883.5 -77.6 L 867.1 -56.1 L 843.4 -51.5 L 838.0 -56.1 L 830.8 -47.7 L 809.7 7.2 V 39.2 L 804.2 65.4 V 74.7 L 822.8 89.0 L 834.6 74.7 L 830.8 59.1 L 825.3 55.3 L 834.6 43.0 H 858.2 L 863.7 39.2 H 870.0 L 872.6 46.8 H 888.2 L 892.8 43.0 L 899.6 46.8 L 909.7 43.0 L 923.2 46.8 L 929.9 43.0 L 935.8 44.3 L 939.2 51.5 L 948.1 48.5 L 949.4 51.5 L 938.8 60.8 L 933.7 63.3 L 932.5 67.1 L 947.2 65.8 L 961.6 54.0 L 969.6 54.9 V 59.5 H 965.8 V 63.3 L 971.3 62.4 L 974.7 65.8 L 968.3 71.7 L 959.9 73.4 L 950.6 72.6 L 946.4 73.8 L 952.3 78.9 L 974.2 80.6 L 978.0 73.8 L 1036.3 85.7 L 1038.4 92.8 L 1038.0 97.9 H 1053.6 L 1059.1 92.8 L 1074.2 97.9 L 1081.0 102.5 L 1082.7 105.1 L 1087.7 97.5 H 1093.7 L 1099.6 92.8 L 1112.6 89.0 L 1121.1 101.7 L 1119.0 107.6 H 1105.5 L 1096.6 111.0 L 1093.7 114.8 L 1104.2 122.8 L 1111.0 124.1 L 1123.6 128.7 V 132.5 L 1119.0 134.2 L 1122.8 138.8 L 1119.4 141.8 L 1087.7 147.7 L 1084.4 160.3 L 1061.2 162.0 L 1057.4 169.6 L 1051.9 168.8 L 1035.0 152.3 H 1023.6 L 1012.2 156.5 L 988.6 151.5 L 946.4 178.9 L 956.1 230.4 L 949.8 234.6 L 891.5 219.0 L 874.7 230.4 L 870.4 238.4 L 859.5 239.7 L 849.8 231.6 L 848.5 237.6 L 834.6 227.0 L 828.7 235.9 V 241.4 L 813.1 240.5 L 802.9 246.4 L 792.8 248.5 L 784.8 255.7 V 273.0 L 800.4 293.2 H 813.1 L 835.8 305.9 L 853.6 300.8 L 872.6 308.4 L 891.5 303.8 L 897.9 304.6 L 923.6 301.7 L 935.4 297.9 V 292.8 L 948.1 290.7 L 949.8 294.5 L 960.3 289.9 L 966.6 289.5 L 971.3 281.0 L 973.8 288.2 L 991.1 285.2 L 1021.1 289.5 L 1032.1 296.6 L 1026.1 299.2 L 1027.8 305.9 V 310.5 H 1033.3 L 1038.4 317.3 L 1046.0 318.6 L 1056.9 330.8 L 1060.7 328.7 L 1064.1 336.3 L 1071.3 338.0 L 1108.4 347.7 L 1132.9 345.1 L 1144.3 353.6 H 1149.8 L 1159.9 358.6 L 1180.2 351.9 L 1192.4 355.3 L 1197.9 359.9 L 1193.7 366.7 L 1194.5 375.5 L 1198.7 383.1 L 1199.6 386.9 L 1204.6 389.9 H 1210.5 L 1216.4 395.4 L 1220.2 394.5 L 1224.5 403.0 L 1218.1 400.8 L 1207.6 401.3 L 1204.6 393.2 L 1185.2 388.6 L 1180.2 386.9 L 1183.5 392.4 L 1184.4 397.9 L 1189.9 404.6 L 1193.7 410.1 H 1190.7 L 1185.2 406.8 V 408.9 L 1192.4 418.1 L 1195.3 425.3 L 1190.7 430.4 L 1183.5 435.4 L 1183.1 438.0 L 1175.9 439.2 L 1167.1 430.4 L 1151.5 425.3 L 1140.9 423.6 L 1133.7 421.1 L 1125.3 419.8 L 1132.1 427.0 L 1130.4 428.7 L 1118.1 432.1 L 1111.8 433.3 L 1105.5 428.7 L 1104.2 433.3 L 1106.7 441.8 V 451.5 L 1102.1 460.8 L 1094.1 460.3 L 1089.9 457.4 L 1091.1 452.7 L 1076.8 443.9 V 447.7 L 1067.9 440.5 L 1065.8 441.8 V 445.6 L 1051.5 438.0 L 1045.6 435.4 L 1033.7 425.7 L 1030.4 415.6 L 1023.2 422.8 L 1016.4 417.7 L 995.3 412.2 L 983.1 405.9 L 977.6 405.1 V 414.8 L 974.2 419.4 L 965.0 408.9 L 956.1 405.1 L 954.4 414.3 H 947.2 L 940.1 409.3 H 937.1 L 934.2 425.7 H 923.6 L 918.5 439.2 L 919.4 451.1 L 912.2 457.4 L 917.7 465.8 L 921.5 466.7 L 923.6 473.8 V 478.1 L 934.2 486.1 L 943.9 488.2 L 960.3 496.6 L 968.8 509.7 L 1002.9 524.9 L 1019.4 525.3 L 1027.8 529.5 H 1035.4 L 1031.6 533.8 L 1040.5 541.8 L 1043.4 546.0 H 1059.9 L 1067.1 544.7 L 1070.9 549.4 L 1078.0 552.3 L 1081.8 555.3 L 1094.5 557.8 L 1105.9 551.1 L 1121.1 554.9 L 1129.1 562.4 L 1132.1 569.6 L 1141.8 573.4 L 1165.0 577.2 H 1171.3 L 1173.4 568.8 L 1165.0 563.3 L 1159.9 557.0 V 551.9 L 1146.8 548.1 L 1151.5 546.0 L 1163.7 548.1 L 1170.0 549.4 L 1174.7 552.3 L 1185.6 553.6 L 1192.8 559.1 L 1201.7 559.9 L 1209.7 569.6 L 1219.0 573.4 L 1225.7 578.5 L 1221.9 579.3 L 1212.6 577.2 L 1216.4 583.1 L 1229.1 592.4 L 1227.4 594.5 L 1221.9 597.9 H 1216.4 V 603.0 L 1203.8 606.3 L 1201.7 600.4 L 1195.3 599.6 V 594.5 L 1189.4 591.6 L 1187.3 593.2 L 1176.4 591.6 L 1168.3 584.8 L 1161.2 582.7 L 1159.9 587.3 L 1154.8 595.8 L 1154.0 599.6 L 1155.7 604.6 L 1152.7 605.5 L 1147.7 604.6 L 1145.6 597.9 L 1138.8 595.8 L 1134.6 589.0 H 1128.3 L 1122.3 593.2 L 1124.9 601.7 L 1123.2 606.3 L 1121.1 610.1 V 619.8 L 1118.5 624.5 L 1116.0 632.5 L 1128.3 639.2 L 1134.6 644.3 L 1143.4 646.4 L 1144.3 651.1 L 1140.5 654.4 L 1143.4 661.2 L 1140.5 663.7 L 1138.0 666.2 L 1147.7 673.8 L 1154.0 674.7 L 1173.4 684.4 H 1182.7 L 1192.8 685.2 L 1204.2 692.4 L 1210.5 702.1 L 1204.2 703.4 L 1202.9 711.0 L 1201.2 714.3 L 1211.4 718.1 L 1213.9 722.4 L 1212.6 725.7 L 1210.5 727.4 L 1212.6 730.0 L 1229.9 732.1 L 1236.7 732.9 L 1242.2 736.7 L 1243.4 732.9 L 1256.5 733.8 L 1257.8 737.6 L 1267.9 738.8 V 742.2 L 1274.7 741.4 L 1279.7 742.2 L 1283.1 746.8 L 1285.6 740.5 L 1290.3 739.2 L 1309.7 748.1 L 1309.3 752.3 L 1315.6 757.8 L 1316.9 760.3 L 1323.2 757.8 L 1328.7 759.9 L 1335.0 765.8 L 1345.1 778.5 L 1346.4 785.2 L 1351.0 782.7 L 1355.7 794.9 L 1361.6 792.8 L 1368.8 799.2 V 801.7 L 1373.0 805.9 V 811.0 H 1386.5 L 1394.5 813.5 L 1410.1 827.4 L 1418.1 838.8 L 1422.8 840.9 L 1429.1 843.0 L 1441.8 854.9 L 1445.6 860.8 L 1451.5 862.0 L 1454.8 873.4 H 1449.4 L 1451.5 879.7 L 1448.9 881.0 L 1450.2 884.4 L 1442.6 882.3 L 1448.1 890.7 V 892.4 L 1441.8 888.2 L 1440.1 892.0 L 1444.3 901.3 L 1437.1 899.2 L 1429.1 894.1 L 1424.9 895.8 L 1428.7 900.4 L 1435.0 903.8 L 1439.2 910.1 L 1442.6 912.7 L 1446.8 916.0 L 1445.6 917.7 L 1446.8 921.5 L 1452.7 928.7 L 1453.6 933.3 L 1462.9 939.7 L 1473.0 943.0 L 1478.5 948.5 L 1486.1 962.0 L 1487.3 965.8 L 1475.5 966.2 L 1473.0 970.0 L 1464.1 971.7 L 1459.1 972.2 L 1443.0 963.7 H 1433.3 L 1422.3 956.5 L 1415.6 951.9 L 1411.8 948.5 L 1408.8 942.2 L 1411.0 938.4 V 935.4 L 1402.9 928.7 L 1395.8 927.8 V 932.5 L 1392.8 933.3 L 1395.3 937.1 L 1394.9 940.9 L 1394.1 943.5 L 1399.1 947.3 L 1400.0 951.9 L 1399.1 954.4 L 1400.4 959.5 L 1398.7 961.6 L 1387.7 952.7 L 1384.4 951.1 L 1382.7 948.5 L 1380.6 952.7 H 1373.4 L 1364.1 947.3 L 1359.9 943.0 L 1354.0 935.9 L 1349.4 931.2 L 1345.1 927.4 L 1336.7 925.7 H 1334.2 L 1342.2 935.9 L 1343.4 942.2 L 1348.5 948.1 V 951.9 L 1344.7 954.9 L 1340.1 955.7 L 1334.2 951.5 L 1329.5 953.6 L 1322.3 944.3 L 1318.1 944.7 L 1313.1 948.5 L 1305.0 948.9 L 1297.0 949.8 L 1294.9 952.3 L 1278.5 949.8 L 1276.8 944.7 L 1278.5 940.1 L 1279.7 937.6 L 1284.8 933.8 V 930.4 L 1270.9 912.7 L 1254.4 911.0 L 1248.9 910.1 L 1243.9 901.3 L 1243.0 887.8 L 1239.2 869.2 L 1241.3 861.6 L 1241.8 852.3 L 1246.0 849.4 L 1247.2 844.3 L 1252.3 838.8 L 1250.2 828.7 L 1248.1 823.2 L 1243.0 818.1 V 812.2 L 1246.0 808.4 L 1243.4 802.5 V 789.0 V 785.2 L 1247.2 779.7 L 1243.0 775.5 L 1242.2 771.3 V 766.7 L 1244.3 763.3 L 1240.5 760.3 L 1237.5 757.0 H 1232.1 V 761.6 L 1235.0 765.0 L 1234.2 769.6 L 1237.5 773.8 V 776.4 L 1231.6 778.5 L 1232.5 786.1 L 1229.9 790.7 L 1224.9 789.0 L 1220.2 786.1 L 1222.3 792.0 L 1227.0 799.2 L 1228.7 802.5 L 1227.8 804.6 L 1221.5 806.8 L 1216.0 803.8 L 1213.9 808.4 L 1209.7 808.9 V 813.1 H 1205.0 L 1194.9 804.6 L 1189.0 797.0 L 1181.4 792.4 L 1172.6 794.1 H 1169.2 L 1167.5 792.0 V 795.8 V 800.4 L 1165.4 802.5 L 1164.5 805.9 L 1159.1 813.9 H 1155.7 L 1154.0 816.0 H 1152.3 L 1150.2 808.0 L 1143.9 801.7 L 1135.4 798.7 L 1141.3 809.7 V 819.4 L 1137.5 827.0 L 1140.5 830.8 L 1145.1 831.6 L 1146.8 838.4 L 1149.4 843.0 L 1148.9 846.8 L 1143.9 852.3 L 1141.3 861.2 L 1138.8 862.0 L 1132.1 857.8 L 1130.4 865.8 L 1120.7 867.1 L 1116.4 881.0 L 1117.7 890.3 L 1119.0 900.4 L 1114.3 905.9 L 1117.7 909.7 L 1129.5 912.2 L 1134.6 916.5 L 1132.1 920.3 L 1121.9 919.0 L 1127.0 927.8 L 1132.9 932.5 V 941.8 L 1123.2 937.1 L 1123.6 944.7 L 1116.4 946.4 L 1108.4 940.9 L 1088.6 941.8 L 1092.0 948.1 L 1090.3 950.6 L 1097.9 960.3 V 964.1 L 1101.7 967.5 V 970.9 H 1098.7 L 1100.8 973.8 L 1100.4 978.1 H 1098.7 V 981.9 L 1097.0 987.3 L 1093.2 991.6 L 1086.1 985.7 L 1081.4 997.5 H 1076.4 L 1072.6 1008.9 H 1068.3 L 1066.2 1016.0 L 1071.3 1021.5 L 1077.6 1023.2 L 1078.5 1028.7 L 1077.6 1032.1 L 1072.6 1030.0 L 1071.7 1034.2 L 1072.6 1038.8 L 1066.2 1043.0 L 1063.3 1037.1 H 1060.3 L 1053.1 1030.8 L 1051.9 1024.1 L 1048.9 1018.6 L 1038.8 1011.4 L 1035.4 1002.5 L 1027.4 996.2 L 1021.5 981.0 L 1020.7 971.3 L 1019.4 964.1 L 1011.4 958.6 L 1001.2 959.1 V 962.9 L 993.7 966.2 L 992.4 949.8 L 1000.4 940.1 L 997.9 932.1 L 1003.4 923.6 L 1001.2 918.1 L 996.2 914.8 L 1009.3 908.9 V 894.1 L 1006.7 893.2 L 1003.4 898.7 L 1002.5 904.2 L 998.3 900.0 L 997.0 881.9 L 994.5 873.0 L 992.4 863.7 L 991.1 868.8 L 988.6 871.7 V 882.7 L 986.5 886.1 L 979.7 901.7 L 975.1 900.4 V 887.8 L 973.4 876.8 L 971.3 871.7 L 972.6 868.8 L 960.7 866.7 L 953.1 855.7 L 955.3 844.3 L 953.1 841.8 V 832.1 L 965.0 818.6 L 966.2 805.9 L 969.6 800.8 L 968.8 792.8 L 973.0 770.9 V 758.6 L 968.8 746.4 V 742.2 L 965.0 735.0 L 959.5 717.7 L 945.6 709.7 L 943.9 693.2 L 944.7 681.4 L 942.6 678.9 L 940.9 675.1 L 931.2 670.9 L 912.6 659.5 L 911.8 655.3 L 893.7 653.6 L 884.4 658.6 L 868.3 657.4 L 865.4 648.9 L 864.1 640.9 L 856.9 627.4 L 855.7 618.1 L 849.4 615.6 L 848.9 611.4 L 844.7 608.9 L 843.4 603.4 L 828.3 593.7 L 817.3 588.2 L 812.2 580.6 L 813.1 571.3 L 808.0 572.2 L 805.9 569.2 V 565.0 L 795.8 563.3 L 794.1 559.9 L 791.1 561.2 L 793.2 567.5 L 791.1 570.0 L 793.2 573.4 L 792.0 586.1 H 780.6 L 779.7 594.1 L 783.5 599.6 L 786.5 601.3 L 788.6 609.7 L 790.3 613.1 L 798.7 614.8 L 802.5 619.8 L 808.0 622.4 L 808.8 627.4 L 799.6 626.2 L 797.5 624.9 H 794.1 L 789.4 619.8 L 786.5 621.5 H 783.5 L 779.7 612.2 L 774.2 613.1 L 772.6 608.0 L 774.2 604.6 L 770.0 603.4 L 765.4 606.8 L 759.5 599.6 L 760.7 589.9 L 754.8 584.4 L 756.1 578.5 L 744.7 565.0 L 744.3 558.6 L 740.1 556.1 L 738.4 549.8 L 741.3 546.4 L 738.4 540.9 L 732.5 542.2 L 731.2 538.8 L 735.8 535.0 L 734.6 533.3 L 727.4 530.0 L 723.6 524.5 L 713.9 522.8 L 708.8 519.4 L 705.5 521.9 H 695.3 L 694.1 525.7 H 691.1 L 689.0 522.8 L 675.5 520.3 L 674.7 524.5 L 669.6 529.1 L 671.7 530.8 V 534.2 L 668.3 535.9 L 664.1 540.9 L 654.0 542.2 L 646.4 537.6 L 645.6 529.1 L 647.2 525.7 L 642.6 515.6 L 635.4 508.0 L 630.8 496.6 L 623.2 489.5 L 608.8 483.1 L 602.5 478.9 L 598.7 468.4 L 600.8 464.1 L 596.2 454.0 L 591.5 455.3 L 583.1 441.8 L 584.0 436.7 L 581.8 435.0 L 582.3 431.2 L 577.2 428.3 L 578.5 422.8 L 577.2 419.8 L 584.0 410.1 L 585.2 403.4 L 587.3 401.7 L 588.6 392.0 L 596.2 384.4 L 599.6 383.5 L 605.9 376.8 L 626.1 363.3 L 630.8 362.4 L 632.5 358.6 L 635.4 356.5 L 639.6 351.1 L 647.7 346.8 L 654.4 341.8 L 659.9 339.7 L 658.2 329.1 L 660.7 321.5 L 665.4 318.1 L 666.2 309.7 L 659.1 303.4 L 652.7 299.6 L 641.3 286.5 L 638.4 277.6 L 636.7 271.7 L 632.5 265.8 L 627.4 264.6 L 616.0 265.4 L 608.0 268.4 L 604.2 271.7 L 602.1 278.5 L 594.5 277.6 L 588.6 274.7 L 587.3 276.8 L 580.6 274.7 L 577.2 275.5 L 572.1 273.4 L 571.3 269.6 L 576.4 268.4 L 572.1 263.7 L 564.5 260.3 L 559.5 251.9 L 558.2 244.7 L 553.2 250.2 L 548.3 255.7 L 547.8 267.7 L 548.2 273.7 L 548.6 279.7 L 545.2 290.8 L 537.2 301.4 L 534.3 306.6 L 543.0 309.4 L 550.4 309.1 L 560.8 319.3 L 564.5 326.1 L 574.4 328.5 L 576.2 335.0 L 581.4 342.3 L 587.8 348.0 L 583.3 353.6 L 578.7 355.8 L 576.5 360.4 L 572.6 360.6 L 570.1 368.8 L 565.5 372.8 L 561.0 372.3 L 555.5 376.1 L 553.1 384.7 L 547.5 386.3 L 543.2 385.3 L 539.7 397.7 L 533.6 397.7 L 532.3 400.7 L 525.7 400.8 L 524.9 405.5 L 520.7 408.0 L 523.2 416.5 L 518.8 424.3 L 520.7 433.9 L 516.5 432.9 L 516.2 439.6 L 514.7 442.2 L 514.1 446.3 L 510.3 446.5 L 510.3 455.7 L 507.8 457.8 L 509.7 466.0 L 508.0 469.1 L 512.2 474.9 L 515.8 475.2 L 518.4 479.7 L 520.2 481.4 L 520.9 488.2 L 519.2 490.0 L 515.6 486.7 L 516.5 497.4 L 511.6 497.0 L 512.8 504.6 L 510.9 511.7 L 502.7 504.4 L 497.4 498.0 L 491.7 486.0 L 491.3 495.4 L 491.3 504.6 L 501.0 519.8 L 498.3 522.8 L 502.5 531.2 L 506.0 537.3 L 508.0 535.4 L 515.1 541.7 L 516.5 546.5 L 516.8 555.2 L 507.4 560.6 L 504.3 553.1 L 503.5 545.4 L 501.1 544.8 L 496.2 543.1 L 498.0 549.2 L 501.8 552.1 L 502.0 557.3 L 495.1 565.4 L 497.9 569.0 L 497.2 572.7 L 501.0 584.3 L 498.4 586.0 L 493.1 581.3 L 481.0 577.3 L 475.4 564.0 L 460.9 565.5 L 451.2 557.8 L 445.5 557.6 L 443.0 553.5 L 428.5 548.9 L 424.5 553.1 L 429.6 557.4 L 439.1 561.2 L 443.7 566.5 L 446.7 575.7 L 456.9 582.0 L 466.9 584.9 L 469.2 591.2 L 475.4 594.7 L 479.8 594.8 L 487.7 600.9 L 494.6 600.2 L 500.6 607.7 L 507.6 607.5 L 512.6 612.6 L 520.4 610.8 L 530.4 619.8 L 530.2 626.5 L 535.1 633.0 L 532.9 636.2 L 533.7 640.4 L 532.6 644.2 L 529.8 648.1 L 538.4 649.1 L 541.8 653.4 L 543.8 655.9 L 549.6 656.0 L 551.0 657.8 L 551.8 669.9 L 545.5 675.6 L 541.5 673.7 C 541.0 674.7 540.1 676.7 539.7 676.8 C 539.4 676.9 537.2 675.8 536.2 675.2 L 532.1 668.5 L 531.0 677.1 L 526.5 681.1 L 526.3 683.7 L 532.7 685.9 L 535.6 688.5 L 535.0 694.0 L 543.3 696.9 L 550.9 702.1 L 548.7 705.0 L 542.9 703.1 L 535.7 705.6 L 523.9 699.8 L 517.8 692.3 L 514.9 692.7 L 510.9 683.3 L 513.0 678.3 L 507.9 678.9 L 497.9 668.6 L 494.9 662.9 L 481.5 658.8 L 470.8 659.7 L 460.6 663.9 L 457.7 667.8 L 454.4 673.1 L 459.9 676.9 L 467.9 674.1 L 479.5 674.8 L 485.0 672.7 L 487.3 674.7 L 488.7 680.9 L 492.9 681.9 L 496.0 689.8 L 500.9 691.4 L 503.0 698.7 L 511.1 707.0 L 514.0 706.6 L 527.3 717.7 L 530.6 718.5 L 538.4 718.0 L 542.9 720.2 L 545.8 724.2 L 555.4 728.5 L 561.3 733.8 L 566.1 741.3 L 569.7 744.6 L 567.2 746.6 L 570.1 750.6 L 577.5 753.8 L 584.5 753.5 L 587.3 751.0 L 591.0 751.7 L 597.4 761.7 L 599.5 769.0 L 597.2 771.9 L 598.4 774.6 L 605.7 780.0 L 609.3 778.9 L 616.4 782.2 L 622.7 794.9 L 622.2 799.4 L 619.4 803.3 L 620.3 806.5 L 624.9 808.7 L 632.2 808.4 L 630.3 813.7 L 634.4 817.4 L 636.1 824.8 L 639.3 823.9 L 642.1 826.1 L 644.2 822.5 L 654.7 831.8 L 655.4 835.5 L 659.3 843.2 L 666.7 845.9 L 675.1 846.1 L 679.0 844.6 L 687.1 848.4 L 692.5 844.2 L 694.1 845.1 L 693.9 849.1 L 699.8 849.6 L 705.8 854.0 L 714.9 856.7 L 717.3 858.6 L 714.5 861.2 L 719.4 862.9 L 722.4 869.0 L 728.6 870.7 L 732.8 870.0 L 740.8 873.4 L 748.7 873.3 L 752.4 877.1 L 751.9 879.9 L 754.6 884.8 L 758.3 885.5 L 763.0 885.0 L 767.6 882.8 L 771.8 885.2 L 775.4 885.4 L 774.7 889.2 L 770.1 890.0 L 766.6 888.4 C 766.0 889.3 764.7 891.2 764.3 891.2 L 760.3 892.4 L 759.8 896.9 L 767.8 895.5 L 777.6 896.2 L 783.2 902.1 L 789.8 902.0 L 794.7 902.3 L 800.2 909.1 L 799.3 910.6 L 792.9 906.8 L 788.2 907.2 L 786.6 910.8 L 782.9 911.8 L 784.1 914.1 L 789.4 916.1 L 794.9 916.7 L 798.1 915.8 L 801.0 919.8 L 802.9 915.7 L 806.5 916.0 L 808.7 920.7 L 816.3 921.1 L 823.3 927.0 L 828.1 933.1 L 834.5 933.9 L 834.6 937.4 L 822.4 942.2 L 817.2 947.2 L 811.1 947.2 L 809.4 949.0 L 800.1 945.5 L 794.7 939.2 L 789.7 943.2 L 786.7 945.0 L 784.5 955.7 L 776.0 956.4 L 770.0 952.4 L 766.7 953.3 L 762.7 956.2 L 763.6 963.9 L 761.5 965.8 L 757.4 974.4 L 751.9 982.6 L 747.1 984.4 L 745.3 988.9 L 736.6 987.4 L 731.6 987.1 L 728.3 990.7 L 721.7 990.8 L 717.3 992.1 L 711.3 997.3 L 702.0 1001.7 L 700.0 1005.3 L 700.2 1009.2 L 700.5 1014.8 L 695.7 1018.0 L 692.1 1028.2 L 687.2 1028.3 L 680.9 1029.2 L 676.8 1031.7 L 668.1 1030.3 L 658.3 1026.9 L 654.1 1029.0 L 655.5 1033.9 L 654.0 1040.9 L 651.5 1042.9 L 652.6 1047.0 L 650.1 1047.2 L 647.8 1048.4 L 645.6 1049.9 L 654.2 1054.0 L 658.9 1057.9 L 659.7 1065.6 L 655.7 1068.5 L 655.3 1074.7 L 656.4 1081.4 L 654.5 1085.5 L 648.3 1083.8 L 644.1 1086.3 L 641.0 1081.5 L 636.3 1080.2 L 630.3 1081.0 L 630.2 1075.8 L 627.5 1081.8 L 619.5 1088.9 L 601.6 1097.1 L 594.9 1096.8 L 587.5 1096.8 L 578.4 1095.8 L 563.4 1089.2 L 563.7 1093.5 L 562.1 1101.8 L 558.8 1107.2 L 555.6 1108.1 L 552.8 1105.8 L 551.9 1109.1 L 549.2 1110.3 L 544.3 1106.9 L 541.4 1112.1 L 537.5 1118.5 L 530.0 1119.8 L 524.1 1117.5 L 523.7 1123.8 L 515.6 1124.8 L 516.4 1133.8 L 513.0 1135.6 L 505.4 1132.1 L 503.8 1147.9 L 499.5 1151.3 L 495.1 1148.2 L 494.5 1165.9 L 486.1 1179.7 L 485.3 1184.4 L 482.4 1185.2 L 483.2 1188.0 L 478.4 1195.6 L 473.1 1197.1 L 468.6 1207.6 L 464.9 1213.0 L 463.8 1227.4 L 467.2 1244.0 L 469.2 1250.9 L 483.1 1258.3 L 490.4 1257.5 L 496.5 1255.8 L 500.9 1258.9 L 499.0 1261.6 L 495.2 1260.5 L 493.1 1262.4 L 482.2 1264.2 L 472.4 1268.4 L 470.9 1279.8 L 466.2 1282.0 L 465.9 1290.0 L 459.7 1296.1 L 456.1 1311.2 L 441.2 1332.6 L 441.3 1340.5 L 440.5 1346.9 L 445.6 1363.7 L 450.6 1369.2 L 448.9 1374.3 L 449.8 1384.8 L 445.6 1399.6 H 2400 V -199.6 H 1007.6 Z M 981.3 996.4 L 989.6 980.6 L 1003.1 978.1 L 1018.1 998.9 L 1029.0 1019.8 L 1036.5 1052.3 L 1058.2 1071.5 L 1061.6 1094.9 L 1053.2 1098.2 V 1112.4 L 1045.7 1108.3 L 1042.4 1130.0 L 1032.3 1125.8 L 1016.4 1112.4 L 994.7 1081.6 L 990.5 1087.4 L 978.8 1073.2 V 1056.5 L 969.6 1047.3 L 971.2 1030.6 L 969.6 1010.6 L 981.3 996.4 Z M 959.2 904.2 L 978.0 942.8 L 981.3 965.9 L 964.7 994.5 L 949.2 990.1 L 931.5 972.5 L 934.9 958.2 L 931.5 940.6 L 934.9 921.8 L 949.2 916.3 L 954.8 904.2 H 959.2 Z M 1267.8 965.9 L 1250.2 975.3 L 1256.1 991.8 L 1250.2 1015.3 L 1273.7 1038.8 L 1264.3 1067.0 L 1273.7 1095.3 L 1305.3 1116.5 L 1314.7 1105.9 L 1355.7 1121.2 L 1359.2 1111.7 L 1381.5 1121.2 L 1388.5 1111.7 L 1381.5 1092.9 L 1375.6 1044.7 L 1355.7 995.3 L 1326.4 969.4 L 1314.7 988.2 L 1293.6 982.4 L 1267.8 965.9 Z M 1083.2 233.6 L 1101.0 223.9 L 1110.9 202.4 L 1169.9 196.9 L 1209.0 214.9 L 1230.6 207.2 L 1316.9 215.7 L 1340.6 198.2 L 1369.9 198.4 L 1405.1 226.1 L 1426.6 236.1 L 1422.5 249.8 L 1404.9 259.5 L 1396.9 277.1 L 1363.5 284.7 L 1340.0 280.6 L 1306.5 290.2 L 1275.1 299.8 L 1218.1 305.3 L 1169.2 279.4 L 1134.0 275.2 L 1089.0 251.3 L 1083.2 233.6 Z M 1405.0 1085.9 L 1392.1 1088.2 L 1401.4 1111.7 H 1409.6 L 1424.9 1114.1 L 1422.5 1092.9 L 1409.6 1076.5 L 1405.0 1085.9 Z`,
    opacity: 1, // Overridden in render to 0.4 for grid bleed-through
  },
  {
    id: "coastline-main",
    type: "coastline",
    // Authored coastline, rivers, and island outlines from the source SVG.
    // Contains multiple subpaths (M commands) for disconnected features:
    // the main continental coastline, interior rivers/waterways, offshore
    // islands, and smaller coastal features.
    d: `M 454.4 673.1 L 457.7 667.8 L 460.6 663.9 L 470.8 659.7 L 481.5 658.8 L 494.9 662.9 L 497.9 668.6 L 507.9 678.9 L 513.0 678.3 L 510.9 683.3 L 514.9 692.7 L 517.8 692.3 L 523.9 699.8 L 535.7 705.6 L 542.9 703.1 L 548.7 705.0 L 550.9 702.1 L 543.3 696.9 L 535.0 694.0 L 535.6 688.5 L 532.7 685.9 L 526.3 683.7 L 526.5 681.1 L 531.0 677.1 L 532.1 668.5 L 536.2 675.2 C 537.2 675.8 539.4 676.9 539.7 676.8 C 540.1 676.7 541.0 674.7 541.5 673.7 L 545.5 675.6 L 551.8 669.9 L 551.0 657.8 L 549.6 656.0 L 543.8 655.9 L 541.8 653.4 L 538.4 649.1 L 529.8 648.1 L 532.6 644.2 L 533.7 640.4 L 532.9 636.2 L 535.1 633.0 L 530.2 626.5 L 530.4 619.8 L 520.4 610.8 L 512.6 612.6 L 507.6 607.5 L 500.6 607.7 L 494.6 600.2 L 487.7 600.9 L 479.8 594.8 L 475.4 594.7 L 469.2 591.2 L 466.9 584.9 L 456.9 582.0 L 446.7 575.7 L 443.7 566.5 L 439.1 561.2 L 429.6 557.4 L 424.5 553.1 L 428.5 548.9 L 443.0 553.5 L 445.5 557.6 L 451.2 557.8 L 460.9 565.5 L 475.4 564.0 L 481.0 577.3 L 493.1 581.3 L 498.4 586.0 L 501.0 584.3 L 497.2 572.7 L 497.9 569.0 L 495.1 565.4 L 502.0 557.3 L 501.8 552.1 L 498.0 549.2 L 496.2 543.1 L 501.1 544.8 L 503.5 545.4 L 504.3 553.1 L 507.4 560.6 L 516.8 555.2 L 516.5 546.5 L 515.1 541.7 L 508.0 535.4 L 506.0 537.3 L 502.5 531.2 L 498.3 522.8 L 501.0 519.8 L 491.3 504.6 L 491.3 495.4 L 491.7 486.0 L 497.4 498.0 L 502.7 504.4 L 510.9 511.7 L 512.8 504.6 L 511.6 497.0 L 516.5 497.4 L 515.6 486.7 L 519.2 490.0 L 520.9 488.2 L 520.2 481.4 L 518.4 479.7 L 515.8 475.2 L 512.2 474.9 L 508.0 469.1 L 509.7 466.0 L 507.8 457.8 L 510.3 455.7 L 510.3 446.5 L 514.1 446.3 L 514.7 442.2 L 516.2 439.6 L 516.5 432.9 L 520.7 433.9 L 518.8 424.3 L 523.2 416.5 L 520.7 408.0 L 524.9 405.5 L 525.7 400.8 L 532.3 400.7 L 533.6 397.7 L 539.7 397.7 L 543.2 385.3 L 547.5 386.3 L 553.1 384.7 L 555.5 376.1 L 561.0 372.3 L 565.5 372.8 L 570.1 368.8 L 572.6 360.6 L 576.5 360.4 L 578.7 355.8 L 583.3 353.6 L 587.8 348.0 L 581.4 342.3 L 576.2 335.0 L 574.4 328.5 L 564.5 326.1 L 560.8 319.3 L 550.4 309.1 L 543.0 309.4 L 534.3 306.6 L 537.2 301.4 L 545.2 290.8 L 548.6 279.7 L 548.2 273.7 M 454.4 673.1 L 459.9 676.9 L 467.9 674.1 L 479.5 674.8 L 485.0 672.7 L 487.3 674.7 L 488.7 680.9 L 492.9 681.9 L 496.0 689.8 L 500.9 691.4 L 503.0 698.7 L 511.1 707.0 L 514.0 706.6 L 527.3 717.7 L 530.6 718.5 L 538.4 718.0 L 542.9 720.2 L 545.8 724.2 L 555.4 728.5 L 561.3 733.8 L 566.1 741.3 L 569.7 744.6 L 567.2 746.6 L 570.1 750.6 L 577.5 753.8 L 584.5 753.5 L 587.3 751.0 L 591.0 751.7 L 597.4 761.7 L 599.5 769.0 L 597.2 771.9 L 598.4 774.6 L 605.7 780.0 L 609.3 778.9 L 616.4 782.2 L 622.7 794.9 L 622.2 799.4 L 619.4 803.3 L 620.3 806.5 L 624.9 808.7 L 632.2 808.4 L 630.3 813.7 L 634.4 817.4 L 636.1 824.8 L 639.3 823.9 L 642.1 826.1 L 644.2 822.5 L 654.7 831.8 L 655.4 835.5 L 659.3 843.2 L 666.7 845.9 L 675.1 846.1 L 679.0 844.6 L 687.1 848.4 L 692.5 844.2 L 694.1 845.1 L 693.9 849.1 L 699.8 849.6 L 705.8 854.0 L 714.9 856.7 L 717.3 858.6 L 714.5 861.2 L 719.4 862.9 L 722.4 869.0 L 728.6 870.7 L 732.8 870.0 L 740.8 873.4 L 748.7 873.3 L 752.4 877.1 L 751.9 879.9 L 754.6 884.8 L 758.3 885.5 L 763.0 885.0 L 767.6 882.8 L 771.8 885.2 L 775.4 885.4 L 774.7 889.2 L 770.1 890.0 L 766.6 888.4 C 766.0 889.3 764.7 891.2 764.3 891.2 M 454.4 673.1 L 446.7 675.2 L 436.7 678.3 L 426.6 678.9 L 416.9 676.9 L 401.3 666.2 L 394.1 658.8 L 390.3 645.6 L 384.4 632.9 L 381.4 624.5 L 370.0 616.5 L 363.7 614.8 L 352.7 616.5 H 343.5 L 335.0 611.4 L 333.3 604.2 L 334.2 599.2 L 338.0 585.7 L 336.7 573.0 L 333.3 564.1 L 325.7 559.1 L 319.8 561.2 L 308.0 557.8 L 300.4 553.5 L 297.9 546.8 L 297.0 540.5 L 292.0 536.7 L 285.2 535.9 L 277.2 536.7 L 268.4 534.2 L 263.3 529.1 V 522.4 L 265.4 514.3 L 262.0 507.6 L 255.7 502.1 L 248.9 504.6 L 236.7 507.6 L 227.4 504.4 L 221.1 497.0 L 217.7 486.0 L 210.1 475.2 L 199.6 469.1 L 187.3 467.5 M 764.3 891.2 C 764.0 891.3 761.5 892.1 760.3 892.4 M 764.3 891.2 L 760.3 892.4 M 760.3 892.4 L 759.8 896.9 L 767.8 895.5 L 777.6 896.2 L 783.2 902.1 L 789.8 902.0 L 794.7 902.3 L 800.2 909.1 L 799.3 910.6 L 792.9 906.8 L 788.2 907.2 L 786.6 910.8 L 782.9 911.8 L 784.1 914.1 L 789.4 916.1 L 794.9 916.7 L 798.1 915.8 L 801.0 919.8 L 802.9 915.7 L 806.5 916.0 L 808.7 920.7 L 816.3 921.1 L 823.3 927.0 L 828.1 933.1 L 834.5 933.9 L 834.6 937.4 L 822.4 942.2 L 817.2 947.2 L 811.1 947.2 L 809.4 949.0 L 800.1 945.5 L 794.7 939.2 L 789.7 943.2 L 786.7 945.0 L 784.5 955.7 L 776.0 956.4 L 770.0 952.4 L 766.7 953.3 L 762.7 956.2 L 763.6 963.9 L 761.5 965.8 L 757.4 974.4 L 751.9 982.6 L 747.1 984.4 L 745.3 988.9 L 736.6 987.4 L 731.6 987.1 L 728.3 990.7 L 721.7 990.8 L 717.3 992.1 L 711.3 997.3 L 702.0 1001.7 L 700.0 1005.3 L 700.2 1009.2 L 700.5 1014.8 L 695.7 1018.0 L 692.1 1028.2 L 687.2 1028.3 L 680.9 1029.2 L 676.8 1031.7 L 668.1 1030.3 L 658.3 1026.9 L 654.1 1029.0 L 655.5 1033.9 L 654.0 1040.9 L 651.5 1042.9 L 652.6 1047.0 L 650.1 1047.2 L 647.8 1048.4 L 645.6 1049.9 L 654.2 1054.0 L 658.9 1057.9 L 659.7 1065.6 L 655.7 1068.5 L 655.3 1074.7 L 656.4 1081.4 L 654.5 1085.5 L 648.3 1083.8 L 644.1 1086.3 L 641.0 1081.5 L 636.3 1080.2 L 630.3 1081.0 L 630.2 1075.8 L 627.5 1081.8 L 619.5 1088.9 L 601.6 1097.1 L 594.9 1096.8 L 587.5 1096.8 L 578.4 1095.8 L 563.4 1089.2 L 563.7 1093.5 L 562.1 1101.8 L 558.8 1107.2 L 555.6 1108.1 L 552.8 1105.8 L 551.9 1109.1 L 549.2 1110.3 L 544.3 1106.9 L 541.4 1112.1 L 537.5 1118.5 L 530.0 1119.8 L 524.1 1117.5 L 523.7 1123.8 L 515.6 1124.8 L 516.4 1133.8 L 513.0 1135.6 L 505.4 1132.1 L 503.8 1147.9 L 499.5 1151.3 L 495.1 1148.2 L 494.5 1165.9 L 486.1 1179.7 L 485.3 1184.4 L 482.4 1185.2 L 483.2 1188.0 L 478.4 1195.6 L 473.1 1197.1 L 468.6 1207.6 L 464.9 1213.0 L 463.8 1227.4 L 467.2 1244.0 L 469.2 1250.9 L 483.1 1258.3 L 490.4 1257.5 L 496.5 1255.8 L 500.9 1258.9 L 499.0 1261.6 L 495.2 1260.5 L 493.1 1262.4 L 482.2 1264.2 L 472.4 1268.4 L 470.9 1279.8 L 466.2 1282.0 L 465.9 1290.0 L 459.7 1296.1 L 456.1 1311.2 L 441.2 1332.6 L 441.3 1340.5 L 440.5 1346.9 L 445.6 1363.7 L 450.6 1369.2 L 448.9 1374.3 L 449.8 1384.8 L 445.6 1399.6 H 2400 V -199.6 H 1007.6 L 992.0 -159.5 C 989.2 -157.2 982.6 -151.6 978.9 -146.8 C 975.2 -142.1 969.5 -123.8 967.1 -115.2 L 957.4 -98.7 L 949.4 -90.7 V -67.5 L 943.0 -51.5 L 929.9 -41.4 H 908.4 L 894.1 -56.1 L 888.2 -73.8 L 883.5 -77.6 L 867.1 -56.1 L 843.4 -51.5 L 838.0 -56.1 L 830.8 -47.7 L 809.7 7.2 V 39.2 L 804.2 65.4 V 74.7 L 822.8 89.0 L 834.6 74.7 L 830.8 59.1 L 825.3 55.3 L 834.6 43.0 H 858.2 L 863.7 39.2 H 870.0 L 872.6 46.8 H 888.2 L 892.8 43.0 L 899.6 46.8 L 909.7 43.0 L 923.2 46.8 L 929.9 43.0 L 935.8 44.3 L 939.2 51.5 L 948.1 48.5 L 949.4 51.5 L 938.8 60.8 L 933.7 63.3 L 932.5 67.1 L 947.2 65.8 L 961.6 54.0 L 969.6 54.9 V 59.5 H 965.8 V 63.3 L 971.3 62.4 L 974.7 65.8 L 968.3 71.7 L 959.9 73.4 L 950.6 72.6 L 946.4 73.8 L 952.3 78.9 L 974.2 80.6 L 978.0 73.8 L 1036.3 85.7 L 1038.4 92.8 L 1038.0 97.9 H 1053.6 L 1059.1 92.8 L 1074.2 97.9 L 1081.0 102.5 L 1082.7 105.1 L 1087.7 97.5 H 1093.7 L 1099.6 92.8 L 1112.6 89.0 L 1121.1 101.7 L 1119.0 107.6 H 1105.5 L 1096.6 111.0 L 1093.7 114.8 L 1104.2 122.8 L 1111.0 124.1 L 1123.6 128.7 V 132.5 L 1119.0 134.2 L 1122.8 138.8 L 1119.4 141.8 L 1087.7 147.7 L 1084.4 160.3 L 1061.2 162.0 L 1057.4 169.6 L 1051.9 168.8 L 1035.0 152.3 H 1023.6 L 1012.2 156.5 L 988.6 151.5 L 946.4 178.9 L 956.1 230.4 L 949.8 234.6 L 891.5 219.0 L 874.7 230.4 L 870.4 238.4 L 859.5 239.7 L 849.8 231.6 L 848.5 237.6 L 834.6 227.0 L 828.7 235.9 V 241.4 L 813.1 240.5 L 802.9 246.4 L 792.8 248.5 L 784.8 255.7 V 273.0 L 800.4 293.2 H 813.1 L 835.8 305.9 L 853.6 300.8 L 872.6 308.4 L 891.5 303.8 L 897.9 304.6 L 923.6 301.7 L 935.4 297.9 V 292.8 L 948.1 290.7 L 949.8 294.5 L 960.3 289.9 L 966.6 289.5 L 971.3 281.0 L 973.8 288.2 L 991.1 285.2 L 1021.1 289.5 L 1032.1 296.6 L 1026.1 299.2 L 1027.8 305.9 V 310.5 H 1033.3 L 1038.4 317.3 L 1046.0 318.6 L 1056.9 330.8 L 1060.7 328.7 L 1064.1 336.3 L 1071.3 338.0 L 1108.4 347.7 L 1132.9 345.1 L 1144.3 353.6 H 1149.8 L 1159.9 358.6 L 1180.2 351.9 L 1192.4 355.3 L 1197.9 359.9 L 1193.7 366.7 L 1194.5 375.5 L 1198.7 383.1 L 1199.6 386.9 L 1204.6 389.9 H 1210.5 L 1216.4 395.4 L 1220.2 394.5 L 1224.5 403.0 L 1218.1 400.8 L 1207.6 401.3 L 1204.6 393.2 L 1185.2 388.6 L 1180.2 386.9 L 1183.5 392.4 L 1184.4 397.9 L 1189.9 404.6 L 1193.7 410.1 H 1190.7 L 1185.2 406.8 V 408.9 L 1192.4 418.1 L 1195.3 425.3 L 1190.7 430.4 L 1183.5 435.4 L 1183.1 438.0 L 1175.9 439.2 L 1167.1 430.4 L 1151.5 425.3 L 1140.9 423.6 L 1133.7 421.1 L 1125.3 419.8 L 1132.1 427.0 L 1130.4 428.7 L 1118.1 432.1 L 1111.8 433.3 L 1105.5 428.7 L 1104.2 433.3 L 1106.7 441.8 V 451.5 L 1102.1 460.8 L 1094.1 460.3 L 1089.9 457.4 L 1091.1 452.7 L 1076.8 443.9 V 447.7 L 1067.9 440.5 L 1065.8 441.8 V 445.6 L 1051.5 438.0 L 1045.6 435.4 L 1033.7 425.7 L 1030.4 415.6 L 1023.2 422.8 L 1016.4 417.7 L 995.3 412.2 L 983.1 405.9 L 977.6 405.1 V 414.8 L 974.2 419.4 L 965.0 408.9 L 956.1 405.1 L 954.4 414.3 H 947.2 L 940.1 409.3 H 937.1 L 934.2 425.7 H 923.6 L 918.5 439.2 L 919.4 451.1 L 912.2 457.4 L 917.7 465.8 L 921.5 466.7 L 923.6 473.8 V 478.1 L 934.2 486.1 L 943.9 488.2 L 960.3 496.6 L 968.8 509.7 L 1002.9 524.9 L 1019.4 525.3 L 1027.8 529.5 H 1035.4 L 1031.6 533.8 L 1040.5 541.8 L 1043.4 546.0 H 1059.9 L 1067.1 544.7 L 1070.9 549.4 L 1078.0 552.3 L 1081.8 555.3 L 1094.5 557.8 L 1105.9 551.1 L 1121.1 554.9 L 1129.1 562.4 L 1132.1 569.6 L 1141.8 573.4 L 1165.0 577.2 H 1171.3 L 1173.4 568.8 L 1165.0 563.3 L 1159.9 557.0 V 551.9 L 1146.8 548.1 L 1151.5 546.0 L 1163.7 548.1 L 1170.0 549.4 L 1174.7 552.3 L 1185.6 553.6 L 1192.8 559.1 L 1201.7 559.9 L 1209.7 569.6 L 1219.0 573.4 L 1225.7 578.5 L 1221.9 579.3 L 1212.6 577.2 L 1216.4 583.1 L 1229.1 592.4 L 1227.4 594.5 L 1221.9 597.9 H 1216.4 V 603.0 L 1203.8 606.3 L 1201.7 600.4 L 1195.3 599.6 V 594.5 L 1189.4 591.6 L 1187.3 593.2 L 1176.4 591.6 L 1168.3 584.8 L 1161.2 582.7 L 1159.9 587.3 L 1154.8 595.8 L 1154.0 599.6 L 1155.7 604.6 L 1152.7 605.5 L 1147.7 604.6 L 1145.6 597.9 L 1138.8 595.8 L 1134.6 589.0 H 1128.3 L 1122.3 593.2 L 1124.9 601.7 L 1123.2 606.3 L 1121.1 610.1 V 619.8 L 1118.5 624.5 L 1116.0 632.5 L 1128.3 639.2 L 1134.6 644.3 L 1143.4 646.4 L 1144.3 651.1 L 1140.5 654.4 L 1143.4 661.2 L 1140.5 663.7 L 1138.0 666.2 L 1147.7 673.8 L 1154.0 674.7 L 1173.4 684.4 H 1182.7 L 1192.8 685.2 L 1204.2 692.4 L 1210.5 702.1 L 1204.2 703.4 L 1202.9 711.0 L 1201.2 714.3 L 1211.4 718.1 L 1213.9 722.4 L 1212.6 725.7 L 1210.5 727.4 L 1212.6 730.0 L 1229.9 732.1 L 1236.7 732.9 L 1242.2 736.7 L 1243.4 732.9 L 1256.5 733.8 L 1257.8 737.6 L 1267.9 738.8 V 742.2 L 1274.7 741.4 L 1279.7 742.2 L 1283.1 746.8 L 1285.6 740.5 L 1290.3 739.2 L 1309.7 748.1 L 1309.3 752.3 L 1315.6 757.8 L 1316.9 760.3 L 1323.2 757.8 L 1328.7 759.9 L 1335.0 765.8 L 1345.1 778.5 L 1346.4 785.2 L 1351.0 782.7 L 1355.7 794.9 L 1361.6 792.8 L 1368.8 799.2 V 801.7 L 1373.0 805.9 V 811.0 H 1386.5 L 1394.5 813.5 L 1410.1 827.4 L 1418.1 838.8 L 1422.8 840.9 L 1429.1 843.0 L 1441.8 854.9 L 1445.6 860.8 L 1451.5 862.0 L 1454.8 873.4 H 1449.4 L 1451.5 879.7 L 1448.9 881.0 L 1450.2 884.4 L 1442.6 882.3 L 1448.1 890.7 V 892.4 L 1441.8 888.2 L 1440.1 892.0 L 1444.3 901.3 L 1437.1 899.2 L 1429.1 894.1 L 1424.9 895.8 L 1428.7 900.4 L 1435.0 903.8 L 1439.2 910.1 L 1442.6 912.7 L 1446.8 916.0 L 1445.6 917.7 L 1446.8 921.5 L 1452.7 928.7 L 1453.6 933.3 L 1462.9 939.7 L 1473.0 943.0 L 1478.5 948.5 L 1486.1 962.0 L 1487.3 965.8 L 1475.5 966.2 L 1473.0 970.0 L 1464.1 971.7 L 1459.1 972.2 L 1443.0 963.7 H 1433.3 L 1422.3 956.5 L 1415.6 951.9 L 1411.8 948.5 L 1408.8 942.2 L 1411.0 938.4 V 935.4 L 1402.9 928.7 L 1395.8 927.8 V 932.5 L 1392.8 933.3 L 1395.3 937.1 L 1394.9 940.9 L 1394.1 943.5 L 1399.1 947.3 L 1400.0 951.9 L 1399.1 954.4 L 1400.4 959.5 L 1398.7 961.6 L 1387.7 952.7 L 1384.4 951.1 L 1382.7 948.5 L 1380.6 952.7 H 1373.4 L 1364.1 947.3 L 1359.9 943.0 L 1354.0 935.9 L 1349.4 931.2 L 1345.1 927.4 L 1336.7 925.7 H 1334.2 L 1342.2 935.9 L 1343.4 942.2 L 1348.5 948.1 V 951.9 L 1344.7 954.9 L 1340.1 955.7 L 1334.2 951.5 L 1329.5 953.6 L 1322.3 944.3 L 1318.1 944.7 L 1313.1 948.5 L 1305.0 948.9 L 1297.0 949.8 L 1294.9 952.3 L 1278.5 949.8 L 1276.8 944.7 L 1278.5 940.1 L 1279.7 937.6 L 1284.8 933.8 V 930.4 L 1270.9 912.7 L 1254.4 911.0 L 1248.9 910.1 L 1243.9 901.3 L 1243.0 887.8 L 1239.2 869.2 L 1241.3 861.6 L 1241.8 852.3 L 1246.0 849.4 L 1247.2 844.3 L 1252.3 838.8 L 1250.2 828.7 L 1248.1 823.2 L 1243.0 818.1 V 812.2 L 1246.0 808.4 L 1243.4 802.5 V 789.0 V 785.2 L 1247.2 779.7 L 1243.0 775.5 L 1242.2 771.3 V 766.7 L 1244.3 763.3 L 1240.5 760.3 L 1237.5 757.0 H 1232.1 V 761.6 L 1235.0 765.0 L 1234.2 769.6 L 1237.5 773.8 V 776.4 L 1231.6 778.5 L 1232.5 786.1 L 1229.9 790.7 L 1224.9 789.0 L 1220.2 786.1 L 1222.3 792.0 L 1227.0 799.2 L 1228.7 802.5 L 1227.8 804.6 L 1221.5 806.8 L 1216.0 803.8 L 1213.9 808.4 L 1209.7 808.9 V 813.1 H 1205.0 L 1194.9 804.6 L 1189.0 797.0 L 1181.4 792.4 L 1172.6 794.1 H 1169.2 L 1167.5 792.0 V 795.8 V 800.4 L 1165.4 802.5 L 1164.5 805.9 L 1159.1 813.9 H 1155.7 L 1154.0 816.0 H 1152.3 L 1150.2 808.0 L 1143.9 801.7 L 1135.4 798.7 L 1141.3 809.7 V 819.4 L 1137.5 827.0 L 1140.5 830.8 L 1145.1 831.6 L 1146.8 838.4 L 1149.4 843.0 L 1148.9 846.8 L 1143.9 852.3 L 1141.3 861.2 L 1138.8 862.0 L 1132.1 857.8 L 1130.4 865.8 L 1120.7 867.1 L 1116.4 881.0 L 1117.7 890.3 L 1119.0 900.4 L 1114.3 905.9 L 1117.7 909.7 L 1129.5 912.2 L 1134.6 916.5 L 1132.1 920.3 L 1121.9 919.0 L 1127.0 927.8 L 1132.9 932.5 V 941.8 L 1123.2 937.1 L 1123.6 944.7 L 1116.4 946.4 L 1108.4 940.9 L 1088.6 941.8 L 1092.0 948.1 L 1090.3 950.6 L 1097.9 960.3 V 964.1 L 1101.7 967.5 V 970.9 H 1098.7 L 1100.8 973.8 L 1100.4 978.1 H 1098.7 V 981.9 L 1097.0 987.3 L 1093.2 991.6 L 1086.1 985.7 L 1081.4 997.5 H 1076.4 L 1072.6 1008.9 H 1068.3 L 1066.2 1016.0 L 1071.3 1021.5 L 1077.6 1023.2 L 1078.5 1028.7 L 1077.6 1032.1 L 1072.6 1030.0 L 1071.7 1034.2 L 1072.6 1038.8 L 1066.2 1043.0 L 1063.3 1037.1 H 1060.3 L 1053.1 1030.8 L 1051.9 1024.1 L 1048.9 1018.6 L 1038.8 1011.4 L 1035.4 1002.5 L 1027.4 996.2 L 1021.5 981.0 L 1020.7 971.3 L 1019.4 964.1 L 1011.4 958.6 L 1001.2 959.1 V 962.9 L 993.7 966.2 L 992.4 949.8 L 1000.4 940.1 L 997.9 932.1 L 1003.4 923.6 L 1001.2 918.1 L 996.2 914.8 L 1009.3 908.9 V 894.1 L 1006.7 893.2 L 1003.4 898.7 L 1002.5 904.2 L 998.3 900.0 L 997.0 881.9 L 994.5 873.0 L 992.4 863.7 L 991.1 868.8 L 988.6 871.7 V 882.7 L 986.5 886.1 L 979.7 901.7 L 975.1 900.4 V 887.8 L 973.4 876.8 L 971.3 871.7 L 972.6 868.8 L 960.7 866.7 L 953.1 855.7 L 955.3 844.3 L 953.1 841.8 V 832.1 L 965.0 818.6 L 966.2 805.9 L 969.6 800.8 L 968.8 792.8 L 973.0 770.9 V 758.6 L 968.8 746.4 V 742.2 L 965.0 735.0 L 959.5 717.7 L 945.6 709.7 L 943.9 693.2 L 944.7 681.4 L 942.6 678.9 L 940.9 675.1 L 931.2 670.9 L 912.6 659.5 L 911.8 655.3 L 893.7 653.6 L 884.4 658.6 L 868.3 657.4 L 865.4 648.9 L 864.1 640.9 L 856.9 627.4 L 855.7 618.1 L 849.4 615.6 L 848.9 611.4 L 844.7 608.9 L 843.4 603.4 L 828.3 593.7 L 817.3 588.2 L 812.2 580.6 L 813.1 571.3 L 808.0 572.2 L 805.9 569.2 V 565.0 L 795.8 563.3 L 794.1 559.9 L 791.1 561.2 L 793.2 567.5 L 791.1 570.0 L 793.2 573.4 L 792.0 586.1 H 780.6 L 779.7 594.1 L 783.5 599.6 L 786.5 601.3 L 788.6 609.7 L 790.3 613.1 L 798.7 614.8 L 802.5 619.8 L 808.0 622.4 L 808.8 627.4 L 799.6 626.2 L 797.5 624.9 H 794.1 L 789.4 619.8 L 786.5 621.5 H 783.5 L 779.7 612.2 L 774.2 613.1 L 772.6 608.0 L 774.2 604.6 L 770.0 603.4 L 765.4 606.8 L 759.5 599.6 L 760.7 589.9 L 754.8 584.4 L 756.1 578.5 L 744.7 565.0 L 744.3 558.6 L 740.1 556.1 L 738.4 549.8 L 741.3 546.4 L 738.4 540.9 L 732.5 542.2 L 731.2 538.8 L 735.8 535.0 L 734.6 533.3 L 727.4 530.0 L 723.6 524.5 L 713.9 522.8 L 708.8 519.4 L 705.5 521.9 H 695.3 L 694.1 525.7 H 691.1 L 689.0 522.8 L 675.5 520.3 L 674.7 524.5 L 669.6 529.1 L 671.7 530.8 V 534.2 L 668.3 535.9 L 664.1 540.9 L 654.0 542.2 L 646.4 537.6 L 645.6 529.1 L 647.2 525.7 L 642.6 515.6 L 635.4 508.0 L 630.8 496.6 L 623.2 489.5 L 608.8 483.1 L 602.5 478.9 L 598.7 468.4 L 600.8 464.1 L 596.2 454.0 L 591.5 455.3 L 583.1 441.8 L 584.0 436.7 L 581.8 435.0 L 582.3 431.2 L 577.2 428.3 L 578.5 422.8 L 577.2 419.8 L 584.0 410.1 L 585.2 403.4 L 587.3 401.7 L 588.6 392.0 L 596.2 384.4 L 599.6 383.5 L 605.9 376.8 L 626.1 363.3 L 630.8 362.4 L 632.5 358.6 L 635.4 356.5 L 639.6 351.1 L 647.7 346.8 L 654.4 341.8 L 659.9 339.7 L 658.2 329.1 L 660.7 321.5 L 665.4 318.1 L 666.2 309.7 L 659.1 303.4 L 652.7 299.6 L 641.3 286.5 L 638.4 277.6 L 636.7 271.7 L 632.5 265.8 L 627.4 264.6 L 616.0 265.4 L 608.0 268.4 L 604.2 271.7 L 602.1 278.5 L 594.5 277.6 L 588.6 274.7 L 587.3 276.8 L 580.6 274.7 L 577.2 275.5 L 572.1 273.4 L 571.3 269.6 L 576.4 268.4 L 572.1 263.7 L 564.5 260.3 L 559.5 251.9 L 558.2 244.7 L 553.2 250.2 M 274.3 -199.6 L 280.2 -178.9 L 274.3 -167.1 V -155.7 L 284.4 -140.9 L 289.5 -115.2 L 296.6 -104.6 L 309.7 -93.7 L 317.7 -84.0 L 327.0 -78.5 L 335.9 -71.3 L 341.8 -67.1 L 350.6 -71.3 L 362.9 -63.7 L 372.2 -59.1 L 376.8 -52.7 L 373.8 -40.5 L 376.8 -36.3 L 383.1 -34.2 L 388.2 -27.0 L 397.5 -21.1 L 399.2 -15.6 V -7.6 L 397.5 0.4 L 403.8 8.4 L 415.2 13.1 L 425.7 14.8 L 435.9 21.9 L 449.8 30.0 L 456.1 37.6 L 465.0 57.0 V 75.1 L 467.1 91.1 L 463.3 104.2 L 457.4 116.9 L 447.3 128.7 L 444.3 139.2 L 447.3 154.9 L 454.0 166.7 L 471.3 179.3 L 483.1 186.1 L 493.7 190.3 L 507.2 192.0 L 519.4 196.6 L 533.6 199.6 L 545.2 213.1 L 550.4 228.3 L 553.1 244.7 L 553.2 250.2 M 553.2 250.2 L 548.3 255.7 L 547.8 267.7 L 548.2 273.7 M 343.0 152.3 L 348.9 163.3 L 357.8 173.0 L 361.6 181.0 L 366.2 188.6 H 379.7 L 389.9 186.1 L 401.7 190.3 L 407.6 194.1 L 412.7 202.1 V 210.1 L 417.7 217.7 L 424.1 223.6 H 434.6 L 444.3 219.8 L 454.9 221.1 L 465.0 226.6 L 473.4 236.3 L 475.5 244.7 V 251.9 L 483.1 260.3 L 491.1 269.6 L 500.0 277.6 L 503.6 280.0 M 548.2 273.7 L 539.7 276.8 L 523.2 283.5 L 507.2 282.3 L 503.6 280.0 M 0.0 60.3 H 7.6 L 13.5 65.8 L 17.7 70.9 H 30.4 L 45.1 79.3 L 53.6 84.0 L 65.0 78.1 L 73.8 76.8 L 79.3 80.6 L 81.0 87.3 L 84.4 92.0 L 94.5 94.1 L 102.5 97.9 V 105.1 L 105.5 111.4 H 115.6 L 124.5 107.6 L 128.7 111.4 V 120.3 L 131.2 125.7 L 136.7 127.4 L 146.4 123.2 H 151.9 L 154.4 129.1 L 165.8 132.9 L 169.2 138.0 L 167.1 145.6 V 152.3 L 170.9 161.6 L 171.7 166.7 L 167.1 171.3 L 165.8 178.9 L 171.7 186.9 H 181.4 L 192.4 183.5 L 203.8 183.1 L 213.1 188.2 L 217.3 195.4 L 228.3 200.4 H 238.8 L 249.4 197.5 L 256.5 199.6 L 263.3 205.9 L 265.8 216.5 L 264.1 228.3 L 265.8 234.2 C 269.2 235.3 276.1 237.6 276.8 237.6 C 277.5 237.6 283.3 237.0 286.1 236.7 L 293.2 239.7 L 296.6 248.9 L 307.6 252.7 H 317.7 L 324.1 249.8 L 329.5 244.7 L 335.9 238.8 L 343.5 240.9 C 345.6 242.1 349.8 244.4 349.8 244.7 C 349.8 245.1 348.7 249.9 348.1 252.3 L 341.8 257.0 L 341.4 261.6 L 345.1 266.7 L 361.6 270.5 L 382.7 277.6 L 389.9 286.5 L 400.0 292.0 L 418.6 296.6 H 429.5 L 446.4 305.1 L 459.9 305.9 L 472.2 300.0 L 478.5 290.8 L 483.1 283.5 L 492.0 280.2 L 503.6 280.0 M 1229.1 605.5 L 1236.3 608.4 H 1243.0 L 1246.4 612.2 L 1253.6 615.6 L 1266.7 610.1 L 1262.0 604.6 L 1253.6 600.4 H 1243.9 L 1239.2 603.0 H 1232.5 L 1229.1 605.5 Z M 1256.5 587.3 L 1262.0 595.8 V 601.7 L 1267.9 604.6 L 1275.9 600.4 L 1277.2 594.5 L 1268.8 589.0 L 1259.9 586.5 L 1256.5 587.3 Z M 1141.8 445.6 L 1146.0 439.7 L 1151.5 435.4 L 1156.1 439.2 L 1158.2 443.9 L 1152.3 448.9 L 1141.8 445.6 Z M 1083.2 233.6 L 1101.0 223.9 L 1110.9 202.4 L 1169.9 196.9 L 1209.0 214.9 L 1230.6 207.2 L 1316.9 215.7 L 1340.6 198.2 L 1369.9 198.4 L 1405.1 226.1 L 1426.6 236.1 L 1422.5 249.8 L 1404.9 259.5 L 1396.9 277.1 L 1363.5 284.7 L 1340.0 280.6 L 1306.5 290.2 L 1275.1 299.8 L 1218.1 305.3 L 1169.2 279.4 L 1134.0 275.2 L 1089.0 251.3 L 1083.2 233.6 Z M 959.2 904.2 L 978.0 942.8 L 981.3 965.9 L 964.7 994.5 L 949.2 990.1 L 931.5 972.5 L 934.9 958.2 L 931.5 940.6 L 934.9 921.8 L 949.2 916.3 L 954.8 904.2 H 959.2 Z M 989.6 980.6 L 981.3 996.4 L 969.6 1010.6 L 971.2 1030.6 L 969.6 1047.3 L 978.8 1056.5 V 1073.2 L 990.5 1087.4 L 994.7 1081.6 L 1016.4 1112.4 L 1032.3 1125.8 L 1042.4 1130.0 L 1045.7 1108.3 L 1053.2 1112.4 V 1098.2 L 1061.6 1094.9 L 1058.2 1071.5 L 1036.5 1052.3 L 1029.0 1019.8 L 1018.1 998.9 L 1003.1 978.1 L 989.6 980.6 Z M 1250.2 975.3 L 1267.8 965.9 L 1293.6 982.4 L 1314.7 988.2 L 1326.4 969.4 L 1355.7 995.3 L 1375.6 1044.7 L 1381.5 1092.9 L 1388.5 1111.7 L 1381.5 1121.2 L 1359.2 1111.7 L 1355.7 1121.2 L 1314.7 1105.9 L 1305.3 1116.5 L 1273.7 1095.3 L 1264.3 1067.0 L 1273.7 1038.8 L 1250.2 1015.3 L 1256.1 991.8 L 1250.2 975.3 Z M 1392.1 1088.2 L 1405.0 1085.9 L 1409.6 1076.5 L 1422.5 1092.9 L 1424.9 1114.1 L 1409.6 1111.7 H 1401.4 L 1392.1 1088.2 Z`,
    opacity: 0.5, // Overridden in render to 0.375
  },
];


/* ─────────────────────────────────────────────────────────────────────────────
 * TYPE STYLE DEFINITIONS
 * ─────────────────────────────────────────────────────────────────────────────
 * Visual properties for each landmark type. This drives icon rendering
 * without hardcoding colors/shapes into the render logic. Adding a new
 * landmark type means adding one entry here and one `case` in LandmarkIcon.
 *
 * Color values are kept as hex literals (not CSS var() strings) because many
 * usages concatenate an alpha suffix: e.g. style.color + "66". These values
 * match the CSS tokens defined in tokens.css:
 *   city / location  → --landmark-city          (#c8b832)
 *   city label       → --landmark-city-label     (#e8d84a)
 *   region           → --landmark-region         (#00d4ff)
 *   location label   → --landmark-location-label (#c8b862)
 *   hotzone          → --landmark-hotzone        (#ff3344)
 *   hotzone label    → --landmark-hotzone-label  (#ff5566)
 */
const TYPE_STYLES = {
  city: {
    color: "#c8b832",
    glowColor: "#c8b83266",
    dashArray: "6 4",
    labelColor: "#e8d84a",
  },
  region: {
    color: "#00d4ff",
    glowColor: "#00d4ff44",
    dashArray: "8 5",
    labelColor: "#00d4ff",
  },
  location: {
    color: "#c8b832",
    glowColor: "#c8b83244",
    dashArray: "5 3",
    labelColor: "#c8b862",
  },
  hotzone: {
    color: "#ff3344",
    glowColor: "#ff334444",
    dashArray: "4 4",
    labelColor: "#ff5566",
  },
};


/* ─────────────────────────────────────────────────────────────────────────────
 * COMPONENT: LandmarkIcon
 * ─────────────────────────────────────────────────────────────────────────────
 * Renders the appropriate SVG icon for a landmark based on its type.
 * Each type has a distinct geometric shape to maintain visual taxonomy:
 *   city    → irregular polygon (organic settlement footprint)
 *   region  → large dashed circle (geographic area)
 *   location → rotated square / diamond (structural point)
 *   hotzone → concentric circles with warning triangle
 *
 * FUTURE: When landmark graphics are authored as custom SVG, this component
 * can be extended to accept a `customPath` field from the landmark data,
 * falling back to these procedural shapes for any landmark without one.
 */
const LandmarkIcon = ({ landmark, isHovered, isSelected, onClick, onHover }) => {
  const style = TYPE_STYLES[landmark.type];
  const s = 24 * (landmark.size || 1); // Base icon size scaled by landmark's size multiplier
  const { x, y } = landmark;

  // Glow filter and stroke width respond to hover/select state
  const glowIntensity = isSelected ? 12 : isHovered ? 8 : 0;
  const strokeWidth = isSelected ? 2.5 : isHovered ? 2 : 1.5;

  // Wrap onClick to stop event propagation — without this, clicks on
  // landmarks bubble up to the container's handleBackgroundClick which
  // deselects the current landmark, causing a hitch when trying to
  // navigate directly between landmarks.
  const handleClick = (e) => {
    e.stopPropagation();
    onClick(landmark.id);
  };

  let shapeElement = null;

  switch (landmark.type) {
    case "city":
      // Irregular polygon — approximates an organic settlement footprint.
      // Vertices are authored as multipliers of `s` offset from center.
      shapeElement = (
        <path
          d={`M ${x - s * 0.8} ${y - s * 0.3}
              L ${x - s * 0.5} ${y - s * 0.9}
              L ${x + s * 0.3} ${y - s * 0.85}
              L ${x + s * 0.9} ${y - s * 0.2}
              L ${x + s * 0.7} ${y + s * 0.6}
              L ${x + s * 0.1} ${y + s * 0.8}
              L ${x - s * 0.6} ${y + s * 0.5}
              Z`}
          fill={isHovered || isSelected ? style.glowColor : style.color + "18"}
          stroke={style.color}
          strokeWidth={strokeWidth}
          strokeDasharray={style.dashArray}
          filter={glowIntensity > 0 ? `url(#glow-${landmark.type})` : undefined}
          style={{ cursor: "pointer", transition: "all 0.3s ease" }}
          onClick={handleClick}
          onMouseEnter={() => onHover(landmark.id)}
          onMouseLeave={() => onHover(null)}
        />
      );
      break;

    case "region":
      // Large dashed circle — represents a broad geographic area
      shapeElement = (
        <circle
          cx={x}
          cy={y}
          r={s * 1.8}
          fill={isHovered || isSelected ? style.glowColor : style.color + "10"}
          stroke={style.color}
          strokeWidth={strokeWidth}
          strokeDasharray={style.dashArray}
          filter={glowIntensity > 0 ? `url(#glow-${landmark.type})` : undefined}
          style={{ cursor: "pointer", transition: "all 0.3s ease" }}
          onClick={handleClick}
          onMouseEnter={() => onHover(landmark.id)}
          onMouseLeave={() => onHover(null)}
        />
      );
      break;

    case "location":
      // Rotated square (diamond) — structural point of interest
      shapeElement = (
        <rect
          x={x - s * 0.6}
          y={y - s * 0.6}
          width={s * 1.2}
          height={s * 1.2}
          transform={`rotate(45 ${x} ${y})`}
          fill={isHovered || isSelected ? style.glowColor : style.color + "18"}
          stroke={style.color}
          strokeWidth={strokeWidth}
          strokeDasharray={style.dashArray}
          filter={glowIntensity > 0 ? `url(#glow-${landmark.type})` : undefined}
          style={{ cursor: "pointer", transition: "all 0.3s ease" }}
          onClick={handleClick}
          onMouseEnter={() => onHover(landmark.id)}
          onMouseLeave={() => onHover(null)}
        />
      );
      break;

    case "hotzone":
      // Concentric dashed circles with warning triangle and exclamation dot
      shapeElement = (
        <g
          style={{ cursor: "pointer" }}
          onClick={handleClick}
          onMouseEnter={() => onHover(landmark.id)}
          onMouseLeave={() => onHover(null)}
        >
          {/* Outer ring — wider, lower opacity */}
          <circle
            cx={x} cy={y} r={s * 1.1}
            fill="none" stroke={style.color} strokeWidth={1}
            strokeDasharray="3 3" opacity={0.5}
          />
          {/* Inner ring — primary interactive area */}
          <circle
            cx={x} cy={y} r={s * 0.7}
            fill={isHovered || isSelected ? style.glowColor : style.color + "15"}
            stroke={style.color}
            strokeWidth={strokeWidth}
            strokeDasharray={style.dashArray}
            filter={glowIntensity > 0 ? `url(#glow-${landmark.type})` : undefined}
            style={{ transition: "all 0.3s ease" }}
          />
          {/* Warning triangle */}
          <path
            d={`M ${x} ${y - s * 0.3} L ${x + s * 0.25} ${y + s * 0.15} L ${x - s * 0.25} ${y + s * 0.15} Z`}
            fill="none" stroke={style.color} strokeWidth={1.5}
            opacity={isHovered || isSelected ? 1 : 0.7}
            style={{ transition: "opacity 0.3s ease" }}
          />
          {/* Exclamation dot */}
          <circle
            cx={x} cy={y + s * 0.08} r={1.5}
            fill={style.color}
            opacity={isHovered || isSelected ? 1 : 0.7}
          />
        </g>
      );
      break;

    default:
      break;
  }

  return shapeElement;
};


/* ─────────────────────────────────────────────────────────────────────────────
 * COMPONENT: LandmarkLabel
 * ─────────────────────────────────────────────────────────────────────────────
 * Renders the text label above a landmark. Positioned relative to the
 * landmark's center, offset upward by its size so labels don't overlap icons.
 * Region labels get extra offset since their circle radius is larger.
 * Labels are non-interactive (pointerEvents: none) so they don't interfere
 * with icon click/hover targets.
 */
const LandmarkLabel = ({ landmark, isHovered, isSelected }) => {
  const style = TYPE_STYLES[landmark.type];
  const s = 24 * (landmark.size || 1);
  const labelY = landmark.type === "region"
    ? landmark.y - s * 1.8 - 12  // Above the circle radius
    : landmark.y - s - 14;        // Above the icon bounds

  return (
    <text
      x={landmark.x}
      y={labelY}
      textAnchor="middle"
      fill={isHovered || isSelected ? "#ffffff" : style.labelColor}
      fontSize={isSelected ? 26 : isHovered ? 24 : 22}
      letterSpacing="1.5px"
      opacity={isHovered || isSelected ? 1 : 0.75}
      style={{
        fontFamily: "var(--mono)",
        transition: "all 0.25s ease",
        textShadow: isHovered || isSelected
          ? `0 0 8px ${style.color}88, 0 0 20px ${style.color}44`
          : "none",
        pointerEvents: "none",
        textTransform: "uppercase",
      }}
    >
      {landmark.name}
    </text>
  );
};


/* ─────────────────────────────────────────────────────────────────────────────
 * COMPONENT: PopoverCard
 * ─────────────────────────────────────────────────────────────────────────────
 * The expanded information panel that appears when a landmark is selected.
 * Rendered via React portal to document.body (see POPOVER ARCHITECTURE note
 * at the top of this file) so it is free of the map container's
 * overflow:hidden clipping.
 *
 * Uses position:fixed with viewport-relative coordinates from getScreenCTM().
 * The transform translate(-50%, -110%) centers the card horizontally above
 * the landmark with a small gap, and the gradient connector line bridges
 * the visual gap down to the landmark position.
 *
 * Contains:
 *   - Type badge (e.g. "◆ CITY", "◆ HOT ZONE")
 *   - Landmark name heading
 *   - Gradient divider
 *   - Description text
 *   - [FUTURE] "View in Field Record" CTA button
 *
 * FUTURE: The CTA button calls onNavigateToRecord(landmark.fieldRecordSlug)
 * which the parent page uses to route to the Field Record entry. The button
 * markup is included below as a comment block — uncomment and wire when the
 * Field Record navigation system is ready to accept external entry points.
 *
 * CSS CLASSES:
 *   Static structural styles live in operations.css (.worldmap-popover-*).
 *   Dynamic values driven by landmark type color remain as inline styles.
 */
const PopoverCard = ({ landmark, position, visible, onClose, onNavigateToRecord }) => {
  const style = TYPE_STYLES[landmark.type];
  const cardRef = useRef(null);

  if (!landmark || !position) return null;

  const typeLabels = {
    city: "CITY",
    region: "REGION",
    location: "LOCATION",
    hotzone: "HOT ZONE",
  };

  return (
    <div
      ref={cardRef}
      className="worldmap-popover-wrapper"
      style={{
        /*
         * PORTAL POSITIONING
         * Since this component is portaled to document.body, we use "fixed"
         * positioning with viewport-relative coordinates (from getScreenCTM).
         * Dynamic values (left, top, opacity, pointerEvents) stay inline;
         * static positioning properties live in .worldmap-popover-wrapper.
         */
        left: `${position.x}px`,
        top: `${position.y}px`,
        opacity: visible ? 1 : 0,
        pointerEvents: visible ? "auto" : "none",
      }}
      onClick={(e) => e.stopPropagation()}
    >
      {/* Card body — dynamic border and boxShadow keyed to landmark type color */}
      <div
        className="worldmap-popover-card"
        style={{
          border: `1px solid ${style.color}66`,
          boxShadow: `0 0 20px ${style.color}22, 0 4px 30px #00000088, inset 0 0 30px #00000044`,
        }}
      >
        {/* Type badge */}
        <div
          className="worldmap-popover-type-badge"
          style={{ color: style.color }}
        >
          ◆ {typeLabels[landmark.type]}
        </div>

        {/* Name */}
        <div
          className="worldmap-popover-name"
          style={{ textShadow: `0 0 10px ${style.color}44` }}
        >
          {landmark.name}
        </div>

        {/* Divider */}
        <div
          className="worldmap-popover-divider"
          style={{
            background: `linear-gradient(90deg, transparent, ${style.color}44, transparent)`,
          }}
        />

        {/* Description */}
        <div className="worldmap-popover-description">
          {landmark.description}
        </div>

        {/*
         * FUTURE: "View in Field Record" CTA button
         * Uncomment and wire when Field Record navigation is ready.
         * The onNavigateToRecord prop should be passed down from the
         * parent page component that controls routing.
         *
         * {landmark.fieldRecordSlug && (
         *   <button
         *     onClick={() => onNavigateToRecord(landmark.fieldRecordSlug)}
         *     style={{
         *       marginTop: "12px",
         *       padding: "6px 12px",
         *       background: "transparent",
         *       border: `1px solid ${style.color}66`,
         *       color: style.color,
         *       fontFamily: "var(--mono)",
         *       fontSize: "10px",
         *       letterSpacing: "1.5px",
         *       cursor: "pointer",
         *       textTransform: "uppercase",
         *       transition: "all 0.2s ease",
         *     }}
         *   >
         *     VIEW IN FIELD RECORD →
         *   </button>
         * )}
         */}
      </div>

      {/* Connector line pointing down to the landmark */}
      <div
        className="worldmap-popover-connector"
        style={{
          background: `linear-gradient(to bottom, ${style.color}66, transparent)`,
        }}
      />
    </div>
  );
};


/* ─────────────────────────────────────────────────────────────────────────────
 * COMPONENT: PZOWorldMap
 * ─────────────────────────────────────────────────────────────────────────────
 * The main map component. Orchestrates all subsystems:
 *
 *   RENDERING:
 *     SVG scene with layered content (back to front):
 *       1. Background rect (landmass fill — var(--map-land))
 *       2. Grid lines (var(--map-grid), 0.75px, 40% opacity)
 *       3. Terrain (sea fill var(--map-sea) at 40%, coastline var(--map-grid) at 37.5%)
 *       4. Landmark icons (type-driven shapes)
 *       5. Landmark labels (Share Tech Mono, uppercase)
 *       6. Vignette overlay (radial gradient edge darkening)
 *     Plus DOM overlays (not in SVG, not affected by perspective):
 *       - Scanline texture (.worldmap-scanline)
 *       - Title badge (.worldmap-title-badge)
 *       - Compass rose (.worldmap-compass)
 *       - Coordinate readout (.worldmap-coord-readout)
 *
 *   PARALLAX:
 *     Animation loop runs via requestAnimationFrame, writing directly to
 *     the SVG viewBox attribute (no React re-renders). panCurrent lerps
 *     toward panTarget at the configured easing rate. Mouse position maps
 *     to pan offset via cubic easing (pow 1.5).
 *
 *   SELECTION:
 *     Clicking a landmark locks parallax, pans toward the landmark, and
 *     opens a portaled popover. Clicking again or clicking background
 *     dismisses and unlocks parallax.
 */
function PZOWorldMap() {
  // ── State ──────────────────────────────────────────────────────────────
  const [hoveredId, setHoveredId] = useState(null);
  const [selectedId, setSelectedId] = useState(null);
  const [popoverPos, setPopoverPos] = useState(null);
  // Controls the popover's visible fade-in. The popover always renders
  // immediately when selected (so position tracking works from frame one),
  // but starts at opacity 0. After a 500ms delay, popoverVisible flips
  // to true, triggering a 500ms CSS opacity transition to full visibility.
  // This hides the ghost-position flash during the pan animation without
  // blocking the position tracker from running.
  const [popoverVisible, setPopoverVisible] = useState(false);

  // ── Refs ───────────────────────────────────────────────────────────────
  const containerRef = useRef(null);
  const svgRef = useRef(null);
  const animFrameRef = useRef(null);

  // Parallax state stored in refs to avoid re-renders on every mouse move.
  // panTarget is where we WANT to be; panCurrent is where we ARE (lerped).
  const panTarget = useRef({ x: 0, y: 0 });
  const panCurrent = useRef({ x: 0, y: 0 });
  const isLockedToLandmark = useRef(false);
  const mouseInside = useRef(false);

  const { canvasWidth: CW, canvasHeight: CH, parallaxOverflow, panEasing, gridSpacing } = MAP_CONFIG;

  // ── Derived values ─────────────────────────────────────────────────────
  // Maximum pan offset in each direction (canvas units).
  // This is half the overflow, since pan is centered.
  const maxPanX = (CW * (parallaxOverflow - 1)) / 2;
  const maxPanY = (CH * (parallaxOverflow - 1)) / 2;

  // ── Memoized landmark lookup ──────────────────────────────────────────
  const landmarkMap = useMemo(() => {
    const map = {};
    LANDMARK_DATA.forEach((lm) => (map[lm.id] = lm));
    return map;
  }, []);

  // ── Parallax animation loop ───────────────────────────────────────────
  // Runs continuously via requestAnimationFrame. Smoothly interpolates
  // panCurrent toward panTarget using the configured easing factor.
  // Updates the SVG viewBox directly (no React state = no re-renders).
  const animatePan = useCallback(() => {
    const cur = panCurrent.current;
    const tgt = panTarget.current;

    // Lerp toward target
    cur.x += (tgt.x - cur.x) * panEasing;
    cur.y += (tgt.y - cur.y) * panEasing;

    // Snap if close enough to avoid infinite micro-adjustments
    if (Math.abs(tgt.x - cur.x) < 0.01) cur.x = tgt.x;
    if (Math.abs(tgt.y - cur.y) < 0.01) cur.y = tgt.y;

    // Apply to SVG viewBox
    if (svgRef.current) {
      const vbX = -maxPanX - cur.x;
      const vbY = -maxPanY - cur.y;
      const vbW = CW + maxPanX * 2;
      const vbH = CH + maxPanY * 2;
      svgRef.current.setAttribute("viewBox", `${vbX} ${vbY} ${vbW} ${vbH}`);
    }

    animFrameRef.current = requestAnimationFrame(animatePan);
  }, [CW, CH, maxPanX, maxPanY, panEasing]);

  // Start/stop the animation loop
  useEffect(() => {
    animFrameRef.current = requestAnimationFrame(animatePan);
    return () => {
      if (animFrameRef.current) cancelAnimationFrame(animFrameRef.current);
    };
  }, [animatePan]);

  // ── Mouse move handler (parallax tracking) ────────────────────────────
  // Converts cursor position within the container to a pan offset.
  // When cursor is at center: pan = 0. At edges: pan = ±maxPan.
  // Cubic easing (pow 1.5) makes movement gentle near center and
  // accelerating toward edges.
  const handleMouseMove = useCallback(
    (e) => {
      if (isLockedToLandmark.current) return;

      const rect = containerRef.current?.getBoundingClientRect();
      if (!rect) return;

      // Normalize cursor position to -1..+1 range
      const nx = ((e.clientX - rect.left) / rect.width) * 2 - 1;
      const ny = ((e.clientY - rect.top) / rect.height) * 2 - 1;

      // Cubic easing for natural feel
      const easedX = Math.sign(nx) * Math.pow(Math.abs(nx), 1.5);
      const easedY = Math.sign(ny) * Math.pow(Math.abs(ny), 1.5);

      panTarget.current = {
        x: -easedX * maxPanX,
        y: -easedY * maxPanY,
      };
    },
    [maxPanX, maxPanY]
  );

  const handleMouseEnter = useCallback(() => {
    mouseInside.current = true;
  }, []);

  const handleMouseLeave = useCallback(() => {
    mouseInside.current = false;
    if (!isLockedToLandmark.current) {
      // Ease back to center when cursor leaves
      panTarget.current = { x: 0, y: 0 };
    }
  }, []);

  // ── Popover position tracking ─────────────────────────────────────────
  // Projects a landmark's SVG-space position into viewport-relative screen
  // coordinates using getScreenCTM(). Since the popover uses position:fixed,
  // viewport coords are exactly what we need.
  const updatePopoverPosition = useCallback((lm) => {
    if (!svgRef.current) return;
    const svg = svgRef.current;
    const pt = svg.createSVGPoint();
    pt.x = lm.x;
    pt.y = lm.y;
    const ctm = svg.getScreenCTM();
    if (!ctm) return;
    const screenPt = pt.matrixTransform(ctm);
    setPopoverPos({ x: screenPt.x, y: screenPt.y });
  }, []);

  // ── Landmark selection ────────────────────────────────────────────────
  // When a landmark is clicked:
  // 1. Lock parallax panning (stop following cursor)
  // 2. Set pan target to shift toward the landmark (damped by 0.5)
  // 3. Begin updating popover position every frame
  const handleDeselect = useCallback(() => {
    if (window.PZO.sound) window.PZO.sound.collapse();
    setSelectedId(null);
    setPopoverPos(null);
    setPopoverVisible(false);
    isLockedToLandmark.current = false;
    if (!mouseInside.current) {
      panTarget.current = { x: 0, y: 0 };
    }
  }, []);

  // Ref to track the fade-in delay timer so we can cancel it on
  // rapid re-selection or deselection
  const popoverTimerRef = useRef(null);

  // Clear popover timer on unmount to prevent state updates after teardown
  useEffect(() => {
    return () => {
      if (popoverTimerRef.current) clearTimeout(popoverTimerRef.current);
    };
  }, []);

  const handleLandmarkClick = useCallback(
    (id) => {
      if (selectedId === id) {
        // Clicking same landmark again deselects
        handleDeselect();
        return;
      }

      const lm = landmarkMap[id];
      if (!lm) return;

      // Clear any pending timers from a previous selection
      if (popoverTimerRef.current) clearTimeout(popoverTimerRef.current);

      // Clamp pan so the viewBox never overshoots the parallax travel range.
      // Without this, landmarks near top/bottom edges pull the viewport past
      // the terrain boundaries, exposing raw background.
      const clampedPan = {
        x: Math.max(-maxPanX, Math.min(maxPanX, -(lm.x - CW / 2) * 0.5)),
        y: Math.max(-maxPanY, Math.min(maxPanY, -(lm.y - CH / 2) * 0.5)),
      };

      const isSwap = selectedId !== null;

      if (!isSwap) {
        // FRESH OPEN: No popover showing. Select immediately, start
        // invisible, then fade in after 500ms delay.
        setPopoverVisible(false);
        setSelectedId(id);
        isLockedToLandmark.current = true;
        panTarget.current = clampedPan;
        requestAnimationFrame(() => updatePopoverPosition(lm));
        popoverTimerRef.current = setTimeout(() => { setPopoverVisible(true); if (window.PZO.sound) window.PZO.sound.expand(); }, 500);
      } else {
        // SWAP: Popover is currently visible. Fade it out first (500ms
        // CSS transition), then after the fade-out completes, switch
        // to the new landmark and fade the new popover in.
        setPopoverVisible(false);
        isLockedToLandmark.current = true;
        panTarget.current = clampedPan;
        popoverTimerRef.current = setTimeout(() => {
          // Fade-out complete — switch to new landmark
          setSelectedId(id);
          requestAnimationFrame(() => updatePopoverPosition(lm));
          // Schedule fade-in after another 500ms
          popoverTimerRef.current = setTimeout(() => { setPopoverVisible(true); if (window.PZO.sound) window.PZO.sound.expand(); }, 500);
        }, 500);
      }
    },
    [selectedId, landmarkMap, CW, CH, handleDeselect, updatePopoverPosition]
  );

  // Continuously update popover position as the map pans to keep it anchored
  useEffect(() => {
    if (!selectedId) return;
    const lm = landmarkMap[selectedId];
    if (!lm) return;

    let running = true;
    const update = () => {
      if (!running) return;
      updatePopoverPosition(lm);
      requestAnimationFrame(update);
    };
    update();
    return () => { running = false; };
  }, [selectedId, landmarkMap, updatePopoverPosition]);

  const handleBackgroundClick = useCallback((e) => {
    if (selectedId) handleDeselect();
  }, [selectedId, handleDeselect]);

  /*
   * PORTAL CLICK-OUTSIDE HANDLING
   * Since the popover is portaled to document.body, we need a document-level
   * click listener to dismiss it when clicking outside. The popover itself
   * calls stopPropagation on clicks so they don't reach this handler.
   * The map container's own onClick also calls handleDeselect for clicks
   * on the map background. This listener catches clicks on surrounding page
   * content that would otherwise be ignored.
   *
   * Uses setTimeout(0) to avoid the same click that selected the landmark
   * from immediately triggering dismissal via event bubbling.
   */
  useEffect(() => {
    if (!selectedId) return;

    const handleGlobalClick = (e) => {
      if (containerRef.current && !containerRef.current.contains(e.target)) {
        handleDeselect();
      }
    };

    const timer = setTimeout(() => {
      document.addEventListener("click", handleGlobalClick);
    }, 0);

    return () => {
      clearTimeout(timer);
      document.removeEventListener("click", handleGlobalClick);
    };
  }, [selectedId, handleDeselect]);

  // ── Grid lines (rendered as SVG) ──────────────────────────────────────
  // Grid covers the full canvas plus overflow so it's always visible during
  // panning. Color: --map-grid at 40% opacity, 0.75px stroke.
  // Grid is rendered behind terrain so sea fill can partially occlude it
  // (sea at 40% opacity lets grid bleed through for unified scanner feel).
  const gridLines = useMemo(() => {
    const lines = [];
    const pad = maxPanX + gridSpacing;
    for (let x = -pad; x <= CW + pad; x += gridSpacing) {
      lines.push(
        <line
          key={`gv-${x}`}
          x1={x} y1={-pad - maxPanY}
          x2={x} y2={CH + pad + maxPanY}
          stroke="var(--map-grid)"
          strokeWidth="0.75"
          opacity="0.4"
        />
      );
    }
    for (let y = -pad; y <= CH + pad; y += gridSpacing) {
      lines.push(
        <line
          key={`gh-${y}`}
          x1={-pad - maxPanX} y1={y}
          x2={CW + pad + maxPanX} y2={y}
          stroke="var(--map-grid)"
          strokeWidth="0.75"
          opacity="0.4"
        />
      );
    }
    return lines;
  }, [CW, CH, maxPanX, maxPanY, gridSpacing]);

  // ── Render ─────────────────────────────────────────────────────────────
  const selectedLandmark = selectedId ? landmarkMap[selectedId] : null;

  return (
    <div className="worldmap-frame">
      {/* ── Topbar (matches Stage Map chrome) ──────────────────────────── */}
      <div className="worldmap-topbar">
        <span className="worldmap-topbar-dot" />
        <span className="worldmap-topbar-title">World Map</span>
        <span className="worldmap-topbar-eyebrow">Orryx // Regional Survey</span>
      </div>

      {/* ── Map viewport ──────────────────────────────────────────────── */}
      <div
        ref={containerRef}
        className="worldmap-container"
        onMouseMove={handleMouseMove}
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
        onClick={handleBackgroundClick}
        style={{
          // aspectRatio is dynamic (derived from MAP_CONFIG canvas dimensions)
          aspectRatio: `${CW} / ${CH}`,
          // cursor changes based on selection state
          cursor: selectedId ? "default" : "crosshair",
        }}
      >
      {/* Perspective-warped map layer */}
      <div
        style={{
          width: "100%",
          height: "100%",
          transform: `rotateX(${MAP_CONFIG.perspectiveDeg}deg)`,
          transformOrigin: "center center",
        }}
      >
        <svg
          ref={svgRef}
          viewBox={`${-maxPanX} ${-maxPanY} ${CW + maxPanX * 2} ${CH + maxPanY * 2}`}
          style={{
            width: "100%",
            height: "100%",
            display: "block",
          }}
          preserveAspectRatio="xMidYMid meet"
        >
          {/* ── SVG Definitions (filters, gradients) ────────────────── */}
          <defs>
            {/* Glow filters for each landmark type */}
            {Object.entries(TYPE_STYLES).map(([type, s]) => (
              <filter key={`glow-${type}`} id={`glow-${type}`} x="-50%" y="-50%" width="200%" height="200%">
                <feGaussianBlur stdDeviation="4" result="blur" />
                <feFlood floodColor={s.color} floodOpacity="0.4" result="color" />
                <feComposite in="color" in2="blur" operator="in" result="shadow" />
                <feMerge>
                  <feMergeNode in="shadow" />
                  <feMergeNode in="SourceGraphic" />
                </feMerge>
              </filter>
            ))}

            {/* Vignette gradient for the map edges */}
            <radialGradient id="vignette" cx="50%" cy="50%" r="60%">
              <stop offset="0%" stopColor="transparent" />
              <stop offset="100%" stopColor="var(--map-bg)" stopOpacity="0.6" />
            </radialGradient>
          </defs>

          {/* ── Background fill (landmass) ──────────────────────────── */}
          <rect
            x={-maxPanX - 200}
            y={-maxPanY - 200}
            width={CW + maxPanX * 2 + 400}
            height={CH + maxPanY * 2 + 400}
            fill="var(--map-land)"
          />

          {/* ── Grid ────────────────────────────────────────────────── */}
          {gridLines}

          {/* ── Terrain layers ──────────────────────────────────────── */}
          {/*
           * Terrain is rendered on top of the grid. The sea fill at 40%
           * opacity lets grid lines show through for a unified scanner
           * aesthetic. The coastline is a solid stroke in grid color.
           */}
          {TERRAIN_DATA.map((terrain) => {
            switch (terrain.type) {
              case "sea":
                return (
                  <path
                    key={terrain.id}
                    d={terrain.d}
                    fill="var(--map-sea)"
                    opacity="0.4"
                  />
                );
              case "coastline":
                return (
                  <path
                    key={terrain.id}
                    d={terrain.d}
                    fill="none"
                    stroke="var(--map-grid)"
                    strokeWidth="1.5"
                    opacity="0.375"
                  />
                );
              default:
                return null;
            }
          })}

          {/* ── Landmark icons ──────────────────────────────────────── */}
          {LANDMARK_DATA.map((lm) => (
            <LandmarkIcon
              key={lm.id}
              landmark={lm}
              isHovered={hoveredId === lm.id}
              isSelected={selectedId === lm.id}
              onClick={handleLandmarkClick}
              onHover={setHoveredId}
            />
          ))}

          {/* ── Landmark labels ─────────────────────────────────────── */}
          {LANDMARK_DATA.map((lm) => (
            <LandmarkLabel
              key={`label-${lm.id}`}
              landmark={lm}
              isHovered={hoveredId === lm.id}
              isSelected={selectedId === lm.id}
            />
          ))}

          {/* ── Vignette overlay ────────────────────────────────────── */}
          <rect
            x={-maxPanX - 200}
            y={-maxPanY - 200}
            width={CW + maxPanX * 2 + 400}
            height={CH + maxPanY * 2 + 400}
            fill="url(#vignette)"
            pointerEvents="none"
          />

        </svg>
      </div>

      {/* ── Popover Card (portaled to document.body) ────────────────── */}
      {/*
       * Rendered via React portal so it is free of the map container's
       * overflow:hidden clipping. Position tracking uses fixed positioning
       * with viewport-relative coordinates from getScreenCTM(), updated
       * every animation frame while a landmark is selected.
       */}
      {selectedLandmark && popoverPos && ReactDOM.createPortal(
        <PopoverCard
          landmark={selectedLandmark}
          position={popoverPos}
          visible={popoverVisible}
          onClose={handleDeselect}
          onNavigateToRecord={(slug) => {
            // TODO: wire to SPA router — e.g. PZO.navigate(`/field-reference#${slug}`);
          }}
        />,
        document.body
      )}

      {/* ── Scanline overlay (cosmetic) ──────────────────────────────── */}
      {/*
       * Faint horizontal scanlines to reinforce the terminal/holographic
       * display aesthetic. Pure CSS class, no performance cost.
       */}
      <div className="worldmap-scanline" />

      {/* ── Compass Rose (fixed overlay, does not pan with map) ───────── */}
      {/*
       * Rendered as a DOM overlay rather than inside the SVG so it stays
       * fixed while the map pans beneath it. Reinforces the HUD/instrument
       * overlay aesthetic.
       */}
      <div className="worldmap-compass">
        <svg width="44" height="60" viewBox="0 0 44 60">
          <text
            x="22" y="16" textAnchor="middle"
            fill="var(--cyan)" fontSize="20"
            style={{ fontFamily: "var(--mono)" }}
            fontWeight="bold" letterSpacing="2px" opacity="0.7"
          >
            N
          </text>
          <line x1="22" y1="24" x2="22" y2="50" stroke="var(--cyan)" strokeWidth="2" opacity="0.7" />
          <line x1="12" y1="50" x2="32" y2="50" stroke="var(--cyan)" strokeWidth="2" opacity="0.7" />
          <line x1="16" y1="46" x2="16" y2="54" stroke="var(--cyan)" strokeWidth="1" opacity="0.35" />
          <line x1="28" y1="46" x2="28" y2="54" stroke="var(--cyan)" strokeWidth="1" opacity="0.35" />
        </svg>
      </div>

      </div>{/* end .worldmap-container */}

      {/* ── Bottom bar (coordinate readout, matches Stage Map chrome) ──── */}
      <div className="worldmap-bottombar">
        SECTOR 7G • ORRYX SURFACE • GRID REF ACTIVE
      </div>

    </div>/* end .worldmap-frame */
  );
}

  window.OpsTool_WorldMap = PZOWorldMap;

}());
